From 431600342f546eebb1ab778a83b302f3323132d1 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 25 Jul 2024 11:55:59 +0200 Subject: [PATCH 001/139] skeleton for comps --- .webpack/webpack.common.mjs | 3 +- package-lock.json | 101 ++++++++++++++++++++ package.json | 1 + src/MCT.js | 1 + src/plugins/comps/CompsTelemetryProvider.js | 49 ++++++++++ src/plugins/comps/plugin.js | 45 +++++++++ src/plugins/plugins.js | 2 + 7 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 src/plugins/comps/CompsTelemetryProvider.js create mode 100644 src/plugins/comps/plugin.js diff --git a/.webpack/webpack.common.mjs b/.webpack/webpack.common.mjs index fab1106dfa..e89f9c0658 100644 --- a/.webpack/webpack.common.mjs +++ b/.webpack/webpack.common.mjs @@ -90,7 +90,8 @@ const config = { __OPENMCT_REVISION__: `'${gitRevision}'`, __OPENMCT_BUILD_BRANCH__: `'${gitBranch}'`, __VUE_OPTIONS_API__: true, // enable/disable Options API support, default: true - __VUE_PROD_DEVTOOLS__: false // enable/disable devtools support in production, default: false + __VUE_PROD_DEVTOOLS__: false, // enable/disable devtools support in production, default: false + __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false', // enable/disable hydration mismatch details in production, default: false }), new VueLoaderPlugin(), new CopyWebpackPlugin({ diff --git a/package-lock.json b/package-lock.json index 002dd4c0a9..03283641cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,6 +63,7 @@ "location-bar": "3.0.1", "lodash": "4.17.21", "marked": "12.0.0", + "mathjs": "^13.0.3", "mini-css-extract-plugin": "2.7.6", "moment": "2.30.1", "moment-duration-format": "2.3.2", @@ -645,6 +646,18 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.24.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", @@ -3160,6 +3173,19 @@ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, + "node_modules/complex.js": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz", + "integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -4105,6 +4131,12 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4555,6 +4587,12 @@ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "dev": true }, + "node_modules/escape-latex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", + "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==", + "dev": true + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -5854,6 +5892,19 @@ "node": ">= 0.6" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -7136,6 +7187,12 @@ "integrity": "sha512-UrzO3fL7nnxlQXlvTynNAenL+21oUQRlzqQFsA2U11ryb4+NLOCOePZ70PTojEaUKhiFugh7dG0Q+I58xlPdWg==", "dev": true }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "dev": true + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -7793,6 +7850,29 @@ "node": ">= 18" } }, + "node_modules/mathjs": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-13.0.3.tgz", + "integrity": "sha512-GpP9OW6swA5POZXvgpc/1FYkAr8lKgV04QHS1tIU60klFfplVCYaNzn6qy0vSp0hAQQN7shcx9CeB507dlLujA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.24.8", + "complex.js": "^2.1.1", + "decimal.js": "^10.4.3", + "escape-latex": "^1.2.0", + "fraction.js": "^4.3.7", + "javascript-natural-sort": "^0.7.1", + "seedrandom": "^3.0.5", + "tiny-emitter": "^2.1.0", + "typed-function": "^4.2.1" + }, + "bin": { + "mathjs": "bin/cli.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -9545,6 +9625,12 @@ "node": ">= 0.10" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, "node_modules/regex-parser": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.0.tgz", @@ -9901,6 +9987,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "dev": true + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -10975,6 +11067,15 @@ "node": ">= 0.6" } }, + "node_modules/typed-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.1.tgz", + "integrity": "sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", diff --git a/package.json b/package.json index 14f0b37fa3..781399e283 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "location-bar": "3.0.1", "lodash": "4.17.21", "marked": "12.0.0", + "mathjs": "13.0.3", "mini-css-extract-plugin": "2.7.6", "moment": "2.30.1", "moment-duration-format": "2.3.2", diff --git a/src/MCT.js b/src/MCT.js index 75215abefd..6a61d41569 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -265,6 +265,7 @@ export class MCT extends EventEmitter { this.install(this.plugins.UserIndicator()); this.install(this.plugins.Gauge()); this.install(this.plugins.InspectorViews()); + this.install(this.plugins.Comps()); } /** * Set path to where assets are hosted. This should be the path to main.js. diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js new file mode 100644 index 0000000000..4063600de2 --- /dev/null +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -0,0 +1,49 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2024, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +export default class ConditionSetTelemetryProvider { + constructor(openmct) { + this.openmct = openmct; + } + + isTelemetryObject(domainObject) { + return domainObject.type === 'comps'; + } + + supportsRequest(domainObject) { + return domainObject.type === 'comps'; + } + + supportsSubscribe(domainObject) { + return domainObject.type === 'comps'; + } + + async request(domainObject, options) { + // TODO: do some math in a worker + return { value: 0}; + } + + subscribe(domainObject, callback) { + // TODO: add to listener list and return a function to remove it + return () => {}; + } +} diff --git a/src/plugins/comps/plugin.js b/src/plugins/comps/plugin.js new file mode 100644 index 0000000000..a79de9e700 --- /dev/null +++ b/src/plugins/comps/plugin.js @@ -0,0 +1,45 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2024, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ +import CompsTelemetryProvider from './CompsTelemetryProvider.js'; + +export default function CompsPlugin() { + return function install(openmct) { + openmct.types.addType('comps', { + name: 'Comps', + key: 'comps', + description: + 'Add one or more telemetry objects, apply a mathematical operation to them, and republish the result as a new telemetry object.', + creatable: true, + cssClass: 'icon-telemetry', + initialize: function (domainObject) { + domainObject.configuration = { + }; + domainObject.composition = []; + domainObject.telemetry = {}; + } + }); + openmct.composition.addPolicy((parent, child) => { + return openmct.telemetry.isTelemetryObject(child); + }); + openmct.telemetry.addProvider(new CompsTelemetryProvider(openmct)); + }; +} diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index 2c2b6809ca..f320e1b266 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -86,6 +86,7 @@ import UTCTimeSystem from './utcTimeSystem/plugin.js'; import ViewDatumAction from './viewDatumAction/plugin.js'; import ViewLargeAction from './viewLargeAction/plugin.js'; import WebPagePlugin from './webPage/plugin.js'; +import CompsPlugin from './comps/plugin.js'; const plugins = {}; @@ -173,5 +174,6 @@ plugins.Gauge = GaugePlugin; plugins.Timelist = TimeList; plugins.InspectorViews = InspectorViews; plugins.InspectorDataVisualization = InspectorDataVisualization; +plugins.Comps = CompsPlugin; export default plugins; From 6c74e84e1121d3bae87725b47b3e7e3e77e9582c Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 29 Jul 2024 18:37:21 +0200 Subject: [PATCH 002/139] more scaffolding --- .webpack/webpack.common.mjs | 3 +- src/plugins/comps/CompsMathWorker.js | 26 +++++++++++++++ src/plugins/comps/CompsTelemetryProvider.js | 36 ++++++++++++++++++++- src/plugins/comps/plugin.js | 5 ++- 4 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 src/plugins/comps/CompsMathWorker.js diff --git a/.webpack/webpack.common.mjs b/.webpack/webpack.common.mjs index e89f9c0658..96ec48b2a0 100644 --- a/.webpack/webpack.common.mjs +++ b/.webpack/webpack.common.mjs @@ -48,6 +48,7 @@ const config = { generatorWorker: './example/generator/generatorWorker.js', couchDBChangesFeed: './src/plugins/persistence/couch/CouchChangesFeed.js', inMemorySearchWorker: './src/api/objects/InMemorySearchWorker.js', + compsMathWorker: './src/plugins/comps/CompsMathWorker.js', espressoTheme: './src/plugins/themes/espresso-theme.scss', snowTheme: './src/plugins/themes/snow-theme.scss', darkmatterTheme: './src/plugins/themes/darkmatter-theme.scss' @@ -91,7 +92,7 @@ const config = { __OPENMCT_BUILD_BRANCH__: `'${gitBranch}'`, __VUE_OPTIONS_API__: true, // enable/disable Options API support, default: true __VUE_PROD_DEVTOOLS__: false, // enable/disable devtools support in production, default: false - __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false', // enable/disable hydration mismatch details in production, default: false + __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false, // enable/disable hydration mismatch details in production, default: false }), new VueLoaderPlugin(), new CopyWebpackPlugin({ diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js new file mode 100644 index 0000000000..1df64c0470 --- /dev/null +++ b/src/plugins/comps/CompsMathWorker.js @@ -0,0 +1,26 @@ +import { evaluate } from 'mathjs'; + +onconnect = function (e) { + const port = e.ports[0]; + console.debug('🧮 Comps Math Worker connected'); + + port.onmessage = function (event) { + console.debug('🧮 Comps Math Worker message:', event); + const { type, id, data, expression } = event.data; + if (type === 'calculate') { + try { + const result = data.map((point) => { + // Using Math.js to evaluate the expression against the data + return { ...point, value: evaluate(expression, point) }; + }); + port.postMessage({ type: 'response', id, result }); + } catch (error) { + port.postMessage({ type: 'error', id, error: error.message }); + } + } else if (type === 'init') { + port.postMessage({ type: 'ready' }); + } else { + port.postMessage({ type: 'error', id, error: 'Invalid message type' }); + } + }; +}; diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 4063600de2..e641e4e9c5 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -23,6 +23,7 @@ export default class ConditionSetTelemetryProvider { constructor(openmct) { this.openmct = openmct; + this.#startSharedWorker(); } isTelemetryObject(domainObject) { @@ -37,13 +38,46 @@ export default class ConditionSetTelemetryProvider { return domainObject.type === 'comps'; } + // eslint-disable-next-line require-await async request(domainObject, options) { // TODO: do some math in a worker - return { value: 0}; + return { value: 0 }; } subscribe(domainObject, callback) { // TODO: add to listener list and return a function to remove it return () => {}; } + + #startSharedWorker() { + // eslint-disable-next-line no-undef + const sharedWorkerURL = `${this.openmct.getAssetPath()}${__OPENMCT_ROOT_RELATIVE__}compsMathWorker.js`; + + const sharedWorker = new SharedWorker(sharedWorkerURL, `Comps Math Worker`); + sharedWorker.port.onmessage = this.onSharedWorkerMessage.bind(this); + sharedWorker.port.onmessageerror = this.onSharedWorkerMessageError.bind(this); + sharedWorker.port.start(); + + // send an initial message to the worker + sharedWorker.port.postMessage({ type: 'init' }); + + // for testing, try a message adding two numbers + sharedWorker.port.postMessage({ + type: 'calculate', + data: [{ a: 1, b: 2 }], + expression: 'a + b' + }); + + this.openmct.on('destroy', () => { + sharedWorker.port.close(); + }); + } + + onSharedWorkerMessage(event) { + console.log('📝 Shared worker message:', event.data); + } + + onSharedWorkerMessageError(event) { + console.error('❌ Shared worker message error:', event); + } } diff --git a/src/plugins/comps/plugin.js b/src/plugins/comps/plugin.js index a79de9e700..2f58b5a1f5 100644 --- a/src/plugins/comps/plugin.js +++ b/src/plugins/comps/plugin.js @@ -31,14 +31,13 @@ export default function CompsPlugin() { creatable: true, cssClass: 'icon-telemetry', initialize: function (domainObject) { - domainObject.configuration = { - }; + domainObject.configuration = {}; domainObject.composition = []; domainObject.telemetry = {}; } }); openmct.composition.addPolicy((parent, child) => { - return openmct.telemetry.isTelemetryObject(child); + return openmct.telemetry.isTelemetryObject(child); }); openmct.telemetry.addProvider(new CompsTelemetryProvider(openmct)); }; From f5d7a339151a936adb4abacaba781512b4405858 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 30 Jul 2024 16:44:14 +0200 Subject: [PATCH 003/139] more drafts --- .eslintrc.cjs | 3 +- src/plugins/comps/CompsManager.js | 0 src/plugins/comps/CompsTelemetryProvider.js | 92 +++++++++++++++++--- src/plugins/comps/CompsViewProvider.js | 96 +++++++++++++++++++++ src/plugins/comps/components/CompsView.vue | 39 +++++++++ src/plugins/comps/plugin.js | 2 + 6 files changed, 217 insertions(+), 15 deletions(-) create mode 100644 src/plugins/comps/CompsManager.js create mode 100644 src/plugins/comps/CompsViewProvider.js create mode 100644 src/plugins/comps/components/CompsView.vue diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 6715df7121..c6af7ba542 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -10,7 +10,8 @@ const config = { serviceworker: true }, globals: { - _: 'readonly' + _: 'readonly', + __OPENMCT_ROOT_RELATIVE__: 'readonly' }, plugins: ['prettier', 'unicorn', 'simple-import-sort'], extends: [ diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index e641e4e9c5..5c3bbfb164 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -20,12 +20,63 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -export default class ConditionSetTelemetryProvider { +export default class CompsTelemetryProvider { + #telemetryObjects = {}; + #telemetryCollections = {}; + #composition = []; + #openmct = null; + #sharedWorker = null; + constructor(openmct) { - this.openmct = openmct; + this.#openmct = openmct; + this.#loadComposition(); this.#startSharedWorker(); } + async #loadComposition() { + this.#composition = this.#openmct.composition.get(this.domainObject); + if (this.#composition) { + await this.#composition.load(); + // load all of our telemetry objects + this.#composition.forEach(this.#addTelemetryObject); + + this.#composition.on('add', this.#addTelemetryObject); + this.#composition.on('remove', this.#removeTelemetryObject); + } + } + + destroy() { + this.#composition.off('add', this.#addTelemetryObject); + this.#composition.off('remove', this.removeTelemetryObject); + } + + #addTelemetryObject(telemetryObject) { + const keyString = this.#openmct.objects.makeKeyString(telemetryObject.identifier); + this.#telemetryObjects[keyString] = telemetryObject; + this.#telemetryCollections[keyString] = + this.#openmct.telemetry.requestCollection(telemetryObject); + + this.#telemetryCollections[keyString].on('add', this.#telemetryProcessor); + this.#telemetryCollections[keyString].on('clear', this.#clearData); + this.#telemetryCollections[keyString].load(); + } + + #telemetryProcessor(telemetryObjects) { + console.debug('📡 Processing telemetry:', telemetryObjects); + } + + #clearData() { + // clear data + console.debug('🆑 Clearing data'); + } + + #removeTelemetryObject(telemetryObject) { + const keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier); + delete this.#telemetryObjects[keyString]; + this.#telemetryCollections[keyString]?.destroy(); + delete this.#telemetryCollections[keyString]; + } + isTelemetryObject(domainObject) { return domainObject.type === 'comps'; } @@ -40,8 +91,19 @@ export default class ConditionSetTelemetryProvider { // eslint-disable-next-line require-await async request(domainObject, options) { - // TODO: do some math in a worker - return { value: 0 }; + // get the telemetry from the collections + const telmetryToSend = {}; + Object.keys(this.#telemetryCollections).forEach((keyString) => { + telmetryToSend[keyString] = this.#telemetryCollections[keyString].getAll( + domainObject, + options + ); + }); + this.#sharedWorker.port.postMessage({ + type: 'calculate', + data: telmetryToSend, + expression: 'a + b' + }); } subscribe(domainObject, callback) { @@ -50,26 +112,28 @@ export default class ConditionSetTelemetryProvider { } #startSharedWorker() { - // eslint-disable-next-line no-undef - const sharedWorkerURL = `${this.openmct.getAssetPath()}${__OPENMCT_ROOT_RELATIVE__}compsMathWorker.js`; + if (this.#sharedWorker) { + throw new Error('Shared worker already started'); + } + const sharedWorkerURL = `${this.#openmct.getAssetPath()}${__OPENMCT_ROOT_RELATIVE__}compsMathWorker.js`; - const sharedWorker = new SharedWorker(sharedWorkerURL, `Comps Math Worker`); - sharedWorker.port.onmessage = this.onSharedWorkerMessage.bind(this); - sharedWorker.port.onmessageerror = this.onSharedWorkerMessageError.bind(this); - sharedWorker.port.start(); + this.#sharedWorker = new SharedWorker(sharedWorkerURL, `Comps Math Worker`); + this.#sharedWorker.port.onmessage = this.onSharedWorkerMessage.bind(this); + this.#sharedWorker.port.onmessageerror = this.onSharedWorkerMessageError.bind(this); + this.#sharedWorker.port.start(); // send an initial message to the worker - sharedWorker.port.postMessage({ type: 'init' }); + this.#sharedWorker.port.postMessage({ type: 'init' }); // for testing, try a message adding two numbers - sharedWorker.port.postMessage({ + this.#sharedWorker.port.postMessage({ type: 'calculate', data: [{ a: 1, b: 2 }], expression: 'a + b' }); - this.openmct.on('destroy', () => { - sharedWorker.port.close(); + this.#openmct.on('destroy', () => { + this.#sharedWorker.port.close(); }); } diff --git a/src/plugins/comps/CompsViewProvider.js b/src/plugins/comps/CompsViewProvider.js new file mode 100644 index 0000000000..fdd9801feb --- /dev/null +++ b/src/plugins/comps/CompsViewProvider.js @@ -0,0 +1,96 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2024, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import mount from 'utils/mount'; + +import CompsView from './components/CompsView.vue'; + +const DEFAULT_VIEW_PRIORITY = 100; + +export default class ConditionSetViewProvider { + constructor(openmct) { + this.openmct = openmct; + this.name = 'Comps View'; + this.key = 'comps.view'; + this.cssClass = 'icon-telemetry'; + } + + canView(domainObject, objectPath) { + return domainObject.type === 'comps' && this.openmct.router.isNavigatedObject(objectPath); + } + + canEdit(domainObject, objectPath) { + return domainObject.type === 'comps' && this.openmct.router.isNavigatedObject(objectPath); + } + + view(domainObject, objectPath) { + let _destroy = null; + let component = null; + + return { + show: (container, isEditing) => { + const { vNode, destroy } = mount( + { + el: container, + components: { + CompsView + }, + provide: { + openmct: this.openmct, + domainObject, + objectPath + }, + data() { + return { + isEditing + }; + }, + template: '' + }, + { + app: this.openmct.app, + element: container + } + ); + _destroy = destroy; + component = vNode.componentInstance; + }, + onEditModeChange: (isEditing) => { + component.isEditing = isEditing; + }, + destroy: () => { + if (_destroy) { + _destroy(); + } + component = null; + } + }; + } + + priority(domainObject) { + if (domainObject.type === 'comps') { + return Number.MAX_VALUE; + } else { + return DEFAULT_VIEW_PRIORITY; + } + } +} diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue new file mode 100644 index 0000000000..8cad6f4388 --- /dev/null +++ b/src/plugins/comps/components/CompsView.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/plugins/comps/plugin.js b/src/plugins/comps/plugin.js index 2f58b5a1f5..fc7a1cb05d 100644 --- a/src/plugins/comps/plugin.js +++ b/src/plugins/comps/plugin.js @@ -20,6 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ import CompsTelemetryProvider from './CompsTelemetryProvider.js'; +import CompsViewProvider from './CompsViewProvider.js'; export default function CompsPlugin() { return function install(openmct) { @@ -40,5 +41,6 @@ export default function CompsPlugin() { return openmct.telemetry.isTelemetryObject(child); }); openmct.telemetry.addProvider(new CompsTelemetryProvider(openmct)); + openmct.objectViews.addProvider(new CompsViewProvider(openmct)); }; } From ff814544c6c28c5a6ad0e07713b36eaeb0fabcab Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 2 Aug 2024 15:57:15 +0200 Subject: [PATCH 004/139] worker ready --- src/plugins/comps/CompsManager.js | 51 ++++++++++-- src/plugins/comps/CompsMathWorker.js | 17 ++-- src/plugins/comps/CompsTelemetryProvider.js | 92 ++++++++++++++------- src/plugins/comps/components/CompsView.vue | 25 +----- src/plugins/comps/plugin.js | 5 +- 5 files changed, 118 insertions(+), 72 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 1c011756d4..e4b7a480f3 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -3,46 +3,79 @@ import { EventEmitter } from 'eventemitter3'; export default class CompsManager extends EventEmitter { #openmct; #domainObject; + #composition; #telemetryObjects = {}; #telemetryCollections = {}; + #managerLoadedPromise; constructor(openmct, domainObject) { super(); this.#openmct = openmct; this.#domainObject = domainObject; + + // Load the composition + this.#managerLoadedPromise = this.#loadComposition(); } - #removeTelemetryObject(telemetryObject) { + load() { + return this.#managerLoadedPromise; + } + + async #loadComposition() { + this.#composition = this.#openmct.composition.get(this.#domainObject); + if (this.#composition) { + this.#composition.on('add', this.#addTelemetryObject); + this.#composition.on('remove', this.#removeTelemetryObject); + await this.#composition.load(); + } + } + + #removeTelemetryObject = (telemetryObject) => { + console.debug('❌ CompsManager: removeTelemetryObject', telemetryObject); const keyString = this.#openmct.objects.makeKeyString(telemetryObject.identifier); delete this.#telemetryObjects[keyString]; this.#telemetryCollections[keyString]?.destroy(); delete this.#telemetryCollections[keyString]; + }; + + requestUnderlyingTelemetry() { + const underlyingTelemetry = {}; + Object.keys(this.#telemetryCollections).forEach((collectionKey) => { + const collection = this.#telemetryCollections[collectionKey]; + underlyingTelemetry[collectionKey] = collection.getAll(); + }); + return underlyingTelemetry; } - telemetryProcessor(telemetryObjects) { - console.debug('Telemetry Processor', telemetryObjects); + #telemetryProcessor(telemetryObjects) { + this.emit('underlyingTelemetryUpdated', telemetryObjects); } - clearData() { + #clearData() { console.debug('Clear Data'); } - #addTelemetryObject(telemetryObject) { + getExpression() { + return 'a + b'; + } + + #addTelemetryObject = (telemetryObject) => { + console.debug('📢 CompsManager: #addTelemetryObject', telemetryObject); const keyString = this.#openmct.objects.makeKeyString(telemetryObject.identifier); this.#telemetryObjects[keyString] = telemetryObject; this.#telemetryCollections[keyString] = this.#openmct.telemetry.requestCollection(telemetryObject); - this.#telemetryCollections[keyString].on('add', this.telemetryProcessor); - this.#telemetryCollections[keyString].on('clear', this.clearData); + this.#telemetryCollections[keyString].on('add', this.#telemetryProcessor); + this.#telemetryCollections[keyString].on('clear', this.#clearData); this.#telemetryCollections[keyString].load(); - } + }; static getCompsManager(domainObject, openmct, compsManagerPool) { const id = openmct.objects.makeKeyString(domainObject.identifier); if (!compsManagerPool[id]) { - compsManagerPool[id] = new CompsManager(domainObject, this.openmct); + compsManagerPool[id] = new CompsManager(openmct, domainObject); } return compsManagerPool[id]; diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 1df64c0470..8f2f886773 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -6,21 +6,26 @@ onconnect = function (e) { port.onmessage = function (event) { console.debug('🧮 Comps Math Worker message:', event); - const { type, id, data, expression } = event.data; - if (type === 'calculate') { + const { type, callbackID, telemetryForComps, expression } = event.data; + if (type === 'calculateRequest' || type === 'calculateSubscription') { try { - const result = data.map((point) => { + // the reply type is different for request and subscription + const replyType = + type === 'calculateRequest' + ? 'calculationRequestResult' + : 'calculationSubscriptionResult'; + const result = telemetryForComps.map((point) => { // Using Math.js to evaluate the expression against the data return { ...point, value: evaluate(expression, point) }; }); - port.postMessage({ type: 'response', id, result }); + port.postMessage({ type: replyType, callbackID, result }); } catch (error) { - port.postMessage({ type: 'error', id, error: error.message }); + port.postMessage({ type: 'error', callbackID, error: error.message }); } } else if (type === 'init') { port.postMessage({ type: 'ready' }); } else { - port.postMessage({ type: 'error', id, error: 'Invalid message type' }); + port.postMessage({ type: 'error', callbackID, error: 'Invalid message type' }); } }; }; diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 3fb24ac536..10fbbacdd0 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -19,23 +19,20 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ +import CompsManager from './CompsManager.js'; export default class CompsTelemetryProvider { - #telemetryObjects = {}; - #telemetryCollections = {}; - #composition = []; #openmct = null; #sharedWorker = null; + #compsManagerPool = null; + #lastUniqueID = 1; + #requestPromises = {}; + #subscriptionCallbacks = {}; - constructor(openmct) { + constructor(openmct, compsManagerPool) { this.#openmct = openmct; - } - - #removeTelemetryObject(telemetryObject) { - const keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier); - delete this.#telemetryObjects[keyString]; - this.#telemetryCollections[keyString]?.destroy(); - delete this.#telemetryCollections[keyString]; + this.#compsManagerPool = compsManagerPool; + this.#startSharedWorker(); } isTelemetryObject(domainObject) { @@ -50,26 +47,55 @@ export default class CompsTelemetryProvider { return domainObject.type === 'comps'; } + #getCallbackID() { + return this.#lastUniqueID++; + } + // eslint-disable-next-line require-await async request(domainObject, options) { - // get the telemetry from the collections - const telmetryToSend = {}; - Object.keys(this.#telemetryCollections).forEach((keyString) => { - telmetryToSend[keyString] = this.#telemetryCollections[keyString].getAll( - domainObject, - options - ); - }); - this.#sharedWorker.port.postMessage({ - type: 'calculate', - data: telmetryToSend, - expression: 'a + b' + const specificCompsManager = CompsManager.getCompsManager( + domainObject, + this.#openmct, + this.#compsManagerPool + ); + await specificCompsManager.load(); + const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry(); + console.debug('🏟️ Telemetry for comps:', telemetryForComps); + const expression = specificCompsManager.getExpression(); + // need to create callbackID with a promise for future execution + return new Promise((resolve, reject) => { + const callbackID = this.#getCallbackID(); + this.#requestPromises[callbackID] = { resolve, reject }; + this.#sharedWorker.port.postMessage({ + type: 'calculateRequest', + telemetryForComps, + expression, + callbackID + }); }); } subscribe(domainObject, callback) { - // TODO: add to listener list and return a function to remove it - return () => {}; + const specificCompsManager = CompsManager.getCompsManager( + domainObject, + this.#openmct, + this.#compsManagerPool + ); + const callbackID = this.#getCallbackID(); + this.#subscriptionCallbacks[callbackID] = callback; + specificCompsManager.on('underlyingTelemetryUpdated', (newTelemetry) => { + const expression = specificCompsManager.getExpression(); + this.#sharedWorker.port.postMessage({ + type: 'calculateSubscription', + telemetryForComps: newTelemetry, + expression, + callbackID + }); + }); + return () => { + specificCompsManager.off('calculationUpdated', callback); + delete this.#subscriptionCallbacks[callbackID]; + }; } #startSharedWorker() { @@ -86,13 +112,6 @@ export default class CompsTelemetryProvider { // send an initial message to the worker this.#sharedWorker.port.postMessage({ type: 'init' }); - // for testing, try a message adding two numbers - this.#sharedWorker.port.postMessage({ - type: 'calculate', - data: [{ a: 1, b: 2 }], - expression: 'a + b' - }); - this.#openmct.on('destroy', () => { this.#sharedWorker.port.close(); }); @@ -100,6 +119,15 @@ export default class CompsTelemetryProvider { onSharedWorkerMessage(event) { console.log('📝 Shared worker message:', event.data); + const { type, result, callbackID } = event.data; + if (type === 'calculationSubscriptionResult') { + this.#subscriptionCallbacks[callbackID](result); + } else if (type === 'calculationRequestResult') { + this.#requestPromises[callbackID].resolve(result); + delete this.#requestPromises[callbackID]; + } else if (type === 'error') { + console.error('❌ Shared worker error:', event.data); + } } onSharedWorkerMessageError(event) { diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index a95bf7086b..3118fc1c27 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -33,33 +33,10 @@ const openmct = inject('openmct'); const domainObject = inject('domainObject'); const compsManagerPool = inject('compsManagerPool'); const compsManager = CompsManager.getCompsManager(domainObject, openmct, compsManagerPool); -const composition = openmct.composition.get(domainObject); onMounted(() => { - loadComposition(); console.debug('🚀 CompsView: onMounted with compsManager', compsManager); }); -async function loadComposition() { - if (composition) { - composition.on('add', addTelemetryObject); - composition.on('remove', removeTelemetryObject); - await composition.load(); - } -} - -function addTelemetryObject(object) { - console.debug('📢 CompsView: addTelemetryObject', object); -} - -function removeTelemetryObject(object) { - console.debug('❌ CompsView: removeTelemetryObject', object); -} - -onBeforeUnmount(() => { - if (composition) { - composition.off('add', addTelemetryObject); - composition.off('remove', removeTelemetryObject); - } -}); +onBeforeUnmount(() => {}); diff --git a/src/plugins/comps/plugin.js b/src/plugins/comps/plugin.js index a3bf5590a4..a1119132a0 100644 --- a/src/plugins/comps/plugin.js +++ b/src/plugins/comps/plugin.js @@ -40,7 +40,10 @@ export default function CompsPlugin() { } }); openmct.composition.addPolicy((parent, child) => { - return openmct.telemetry.isTelemetryObject(child); + if (parent.type === 'comps' && !openmct.telemetry.isTelemetryObject(child)) { + return false; + } + return true; }); openmct.telemetry.addProvider(new CompsTelemetryProvider(openmct, compsManagerPool)); openmct.objectViews.addProvider(new CompsViewProvider(openmct, compsManagerPool)); From 74c3a95ca376a9f65dc4d351db354aa6bac501d7 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 2 Aug 2024 16:26:15 +0200 Subject: [PATCH 005/139] telemetry is null for some reason --- src/plugins/comps/CompsMathWorker.js | 26 +++++++++++++++++---- src/plugins/comps/CompsTelemetryProvider.js | 8 +++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 8f2f886773..e4fac01c0f 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -14,10 +14,7 @@ onconnect = function (e) { type === 'calculateRequest' ? 'calculationRequestResult' : 'calculationSubscriptionResult'; - const result = telemetryForComps.map((point) => { - // Using Math.js to evaluate the expression against the data - return { ...point, value: evaluate(expression, point) }; - }); + const result = calculate(telemetryForComps, expression); port.postMessage({ type: replyType, callbackID, result }); } catch (error) { port.postMessage({ type: 'error', callbackID, error: error.message }); @@ -29,3 +26,24 @@ onconnect = function (e) { } }; }; + +function calculate(telemetryForComps, expression) { + const dataSet1 = Object.values(telemetryForComps)[0]; + const dataSet2 = Object.values(telemetryForComps)[1]; + + // Organize data by utc for quick access + const utcMap1 = new Map(dataSet1.map((item) => [item.utc, item.sin])); + const utcMap2 = new Map(dataSet2.map((item) => [item.utc, item.sin])); + + const sumResults = []; + + // Iterate over the first dataset and check for matching utc in the second dataset + for (const [utc, sin1] of utcMap1.entries()) { + if (utcMap2.has(utc)) { + const sin2 = utcMap2.get(utc); + const sumSin = evaluate(expression, { a: sin1, b: sin2 }); + sumResults.push({ utc, sumSin }); + } + } + return sumResults; +} diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 10fbbacdd0..5437ac770a 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -59,12 +59,12 @@ export default class CompsTelemetryProvider { this.#compsManagerPool ); await specificCompsManager.load(); - const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry(); - console.debug('🏟️ Telemetry for comps:', telemetryForComps); - const expression = specificCompsManager.getExpression(); - // need to create callbackID with a promise for future execution return new Promise((resolve, reject) => { const callbackID = this.#getCallbackID(); + const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry(); + const expression = specificCompsManager.getExpression(); + // need to create callbackID with a promise for future execution + console.debug('🏟️ Telemetry for comps:', telemetryForComps); this.#requestPromises[callbackID] = { resolve, reject }; this.#sharedWorker.port.postMessage({ type: 'calculateRequest', From ce5e435ae076104bd3137aa56da282e56b455d9f Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 2 Aug 2024 17:25:08 +0200 Subject: [PATCH 006/139] can add two sin waves --- src/plugins/comps/CompsManager.js | 4 ++-- src/plugins/comps/CompsMathWorker.js | 4 ++-- src/plugins/comps/CompsTelemetryProvider.js | 3 ++- src/plugins/comps/plugin.js | 2 ++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index e4b7a480f3..febf4f663f 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -59,7 +59,7 @@ export default class CompsManager extends EventEmitter { return 'a + b'; } - #addTelemetryObject = (telemetryObject) => { + #addTelemetryObject = async (telemetryObject) => { console.debug('📢 CompsManager: #addTelemetryObject', telemetryObject); const keyString = this.#openmct.objects.makeKeyString(telemetryObject.identifier); this.#telemetryObjects[keyString] = telemetryObject; @@ -68,7 +68,7 @@ export default class CompsManager extends EventEmitter { this.#telemetryCollections[keyString].on('add', this.#telemetryProcessor); this.#telemetryCollections[keyString].on('clear', this.#clearData); - this.#telemetryCollections[keyString].load(); + await this.#telemetryCollections[keyString].load(); }; static getCompsManager(domainObject, openmct, compsManagerPool) { diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index e4fac01c0f..3b8ced7690 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -41,8 +41,8 @@ function calculate(telemetryForComps, expression) { for (const [utc, sin1] of utcMap1.entries()) { if (utcMap2.has(utc)) { const sin2 = utcMap2.get(utc); - const sumSin = evaluate(expression, { a: sin1, b: sin2 }); - sumResults.push({ utc, sumSin }); + const output = evaluate(expression, { a: sin1, b: sin2 }); + sumResults.push({ utc, output }); } } return sumResults; diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 5437ac770a..3edb532591 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -64,7 +64,8 @@ export default class CompsTelemetryProvider { const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry(); const expression = specificCompsManager.getExpression(); // need to create callbackID with a promise for future execution - console.debug('🏟️ Telemetry for comps:', telemetryForComps); + console.debug('🏟️ 1 Telemetry for comps:', telemetryForComps); + console.debug('🏟️ 2 Telemetry for comps:', specificCompsManager.requestUnderlyingTelemetry()); this.#requestPromises[callbackID] = { resolve, reject }; this.#sharedWorker.port.postMessage({ type: 'calculateRequest', diff --git a/src/plugins/comps/plugin.js b/src/plugins/comps/plugin.js index a1119132a0..4311e394bd 100644 --- a/src/plugins/comps/plugin.js +++ b/src/plugins/comps/plugin.js @@ -19,6 +19,7 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ +import CompsMetadataProvider from './CompsMetadataProvider.js'; import CompsTelemetryProvider from './CompsTelemetryProvider.js'; import CompsViewProvider from './CompsViewProvider.js'; @@ -45,6 +46,7 @@ export default function CompsPlugin() { } return true; }); + openmct.telemetry.addProvider(new CompsMetadataProvider(openmct)); openmct.telemetry.addProvider(new CompsTelemetryProvider(openmct, compsManagerPool)); openmct.objectViews.addProvider(new CompsViewProvider(openmct, compsManagerPool)); }; From 69db5340421011d1317fb66b1a81fb45274877c5 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 2 Aug 2024 17:58:14 +0200 Subject: [PATCH 007/139] adding works --- src/plugins/comps/CompsManager.js | 6 ++++-- src/plugins/comps/CompsMathWorker.js | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index febf4f663f..045b6159fc 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -47,9 +47,11 @@ export default class CompsManager extends EventEmitter { return underlyingTelemetry; } - #telemetryProcessor(telemetryObjects) { + #telemetryProcessor = (telemetryObjects) => { + // new data! + console.debug(`🎉 new data!`, telemetryObjects); this.emit('underlyingTelemetryUpdated', telemetryObjects); - } + }; #clearData() { console.debug('Clear Data'); diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 3b8ced7690..66aaf1cdae 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -32,16 +32,16 @@ function calculate(telemetryForComps, expression) { const dataSet2 = Object.values(telemetryForComps)[1]; // Organize data by utc for quick access - const utcMap1 = new Map(dataSet1.map((item) => [item.utc, item.sin])); - const utcMap2 = new Map(dataSet2.map((item) => [item.utc, item.sin])); + const utcMap1 = new Map(dataSet1.map((item) => [item.utc, item])); + const utcMap2 = new Map(dataSet2.map((item) => [item.utc, item])); const sumResults = []; // Iterate over the first dataset and check for matching utc in the second dataset - for (const [utc, sin1] of utcMap1.entries()) { + for (const [utc, item1] of utcMap1.entries()) { if (utcMap2.has(utc)) { - const sin2 = utcMap2.get(utc); - const output = evaluate(expression, { a: sin1, b: sin2 }); + const item2 = utcMap2.get(utc); + const output = evaluate(expression, { a: item1.sin, b: item2.sin }); sumResults.push({ utc, output }); } } From 90a24b380fb836253911258206df0763a3a1f0fb Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 5 Aug 2024 16:26:54 +0200 Subject: [PATCH 008/139] exact values enabled --- src/plugins/comps/CompsManager.js | 12 ++- src/plugins/comps/CompsMathWorker.js | 100 +++++++++++++++----- src/plugins/comps/CompsTelemetryProvider.js | 20 ++-- 3 files changed, 94 insertions(+), 38 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 045b6159fc..3115ae334f 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -7,6 +7,7 @@ export default class CompsManager extends EventEmitter { #telemetryObjects = {}; #telemetryCollections = {}; #managerLoadedPromise; + #dataFrame = {}; constructor(openmct, domainObject) { super(); @@ -47,10 +48,9 @@ export default class CompsManager extends EventEmitter { return underlyingTelemetry; } - #telemetryProcessor = (telemetryObjects) => { - // new data! - console.debug(`🎉 new data!`, telemetryObjects); - this.emit('underlyingTelemetryUpdated', telemetryObjects); + #telemetryProcessor = (newTelemetry, keyString) => { + console.debug(`🎉 new data for ${keyString}!`, newTelemetry); + this.emit('underlyingTelemetryUpdated', { [keyString]: newTelemetry }); }; #clearData() { @@ -68,7 +68,9 @@ export default class CompsManager extends EventEmitter { this.#telemetryCollections[keyString] = this.#openmct.telemetry.requestCollection(telemetryObject); - this.#telemetryCollections[keyString].on('add', this.#telemetryProcessor); + this.#telemetryCollections[keyString].on('add', (data) => { + this.#telemetryProcessor(data, keyString); + }); this.#telemetryCollections[keyString].on('clear', this.#clearData); await this.#telemetryCollections[keyString].load(); }; diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 66aaf1cdae..5692538889 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -6,41 +6,89 @@ onconnect = function (e) { port.onmessage = function (event) { console.debug('🧮 Comps Math Worker message:', event); - const { type, callbackID, telemetryForComps, expression } = event.data; - if (type === 'calculateRequest' || type === 'calculateSubscription') { - try { - // the reply type is different for request and subscription - const replyType = - type === 'calculateRequest' - ? 'calculationRequestResult' - : 'calculationSubscriptionResult'; - const result = calculate(telemetryForComps, expression); - port.postMessage({ type: replyType, callbackID, result }); - } catch (error) { - port.postMessage({ type: 'error', callbackID, error: error.message }); + try { + const { type, callbackID, telemetryForComps, newTelemetry, expression } = event.data; + if (type === 'calculateRequest') { + const result = calculateRequest(telemetryForComps, expression); + port.postMessage({ type: 'calculationRequestResult', callbackID, result }); + } else if (type === 'calculateSubscription') { + const result = calculateSubscription(telemetryForComps, newTelemetry, expression); + if (result.length) { + port.postMessage({ type: 'calculationSubscriptionResult', callbackID, result }); + } + } else if (type === 'init') { + port.postMessage({ type: 'ready' }); + } else { + throw new Error('Invalid message type'); } - } else if (type === 'init') { - port.postMessage({ type: 'ready' }); - } else { - port.postMessage({ type: 'error', callbackID, error: 'Invalid message type' }); + } catch (error) { + port.postMessage({ type: 'error', error }); } }; }; -function calculate(telemetryForComps, expression) { - const dataSet1 = Object.values(telemetryForComps)[0]; - const dataSet2 = Object.values(telemetryForComps)[1]; +function getFullDataFrame(telemetryForComps) { + const dataFrame = {}; + Object.keys(telemetryForComps).forEach((key) => { + const dataSet = telemetryForComps[key]; + const telemetryMap = new Map(dataSet.map((item) => [item.utc, item])); + dataFrame[key] = telemetryMap; + }); + return dataFrame; +} - // Organize data by utc for quick access - const utcMap1 = new Map(dataSet1.map((item) => [item.utc, item])); - const utcMap2 = new Map(dataSet2.map((item) => [item.utc, item])); +function getReducedDataFrame(telemetryForComps, newTelemetry) { + const reducedDataFrame = {}; + const fullDataFrame = getFullDataFrame(telemetryForComps); + // we can assume (due to telemetryCollections) that newTelmetry has at most one key + const newTelemetryKey = Object.keys(newTelemetry)[0]; + const newTelmetryData = newTelemetry[newTelemetryKey]; + // initalize maps for other telemetry + Object.keys(telemetryForComps).forEach((key) => { + if (key !== newTelemetryKey) { + reducedDataFrame[key] = new Map(); + } + }); + reducedDataFrame[newTelemetryKey] = new Map( + Object.values(newTelmetryData).map((item) => { + return [item.utc, item]; + }) + ); + // march through the new telemetry and look for corresponding telemetry in the other dataset + newTelmetryData.forEach((value) => { + const newTelemetryUtc = value.utc; + Object.keys(telemetryForComps).forEach((otherKey) => { + if (otherKey !== newTelemetryKey) { + const otherDataSet = fullDataFrame[otherKey]; + if (otherDataSet.has(newTelemetryUtc)) { + reducedDataFrame[otherKey].set(newTelemetryUtc, otherDataSet.get(newTelemetryUtc)); + } + } + }); + }); + return reducedDataFrame; +} + +function calculateSubscription(telemetryForComps, newTelemetry, expression) { + const dataFrame = getReducedDataFrame(telemetryForComps, newTelemetry); + return calculate(dataFrame, expression); +} + +function calculateRequest(telemetryForComps, expression) { + const dataFrame = getFullDataFrame(telemetryForComps); + return calculate(dataFrame, expression); +} + +function calculate(dataFrame, expression) { const sumResults = []; + // Iterate over the first dataset and check for matching utc in the other dataset + const firstDataSet = Object.values(dataFrame)[0]; + const secondDataSet = Object.values(dataFrame)[1]; - // Iterate over the first dataset and check for matching utc in the second dataset - for (const [utc, item1] of utcMap1.entries()) { - if (utcMap2.has(utc)) { - const item2 = utcMap2.get(utc); + for (const [utc, item1] of firstDataSet.entries()) { + if (secondDataSet.has(utc)) { + const item2 = secondDataSet.get(utc); const output = evaluate(expression, { a: item1.sin, b: item2.sin }); sumResults.push({ utc, output }); } diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 3edb532591..f6750106c4 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -76,6 +76,18 @@ export default class CompsTelemetryProvider { }); } + #computeOnNewTelemetry(specificCompsManager, newTelemetry, callbackID) { + const expression = specificCompsManager.getExpression(); + const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry(); + this.#sharedWorker.port.postMessage({ + type: 'calculateSubscription', + telemetryForComps, + newTelemetry, + expression, + callbackID + }); + } + subscribe(domainObject, callback) { const specificCompsManager = CompsManager.getCompsManager( domainObject, @@ -85,13 +97,7 @@ export default class CompsTelemetryProvider { const callbackID = this.#getCallbackID(); this.#subscriptionCallbacks[callbackID] = callback; specificCompsManager.on('underlyingTelemetryUpdated', (newTelemetry) => { - const expression = specificCompsManager.getExpression(); - this.#sharedWorker.port.postMessage({ - type: 'calculateSubscription', - telemetryForComps: newTelemetry, - expression, - callbackID - }); + this.#computeOnNewTelemetry(specificCompsManager, newTelemetry, callbackID); }); return () => { specificCompsManager.off('calculationUpdated', callback); From 37d222fd875a0c8a57fd80cac253b8e2ad760ade Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 6 Aug 2024 15:50:24 +0200 Subject: [PATCH 009/139] subscriptions work --- src/plugins/comps/CompsManager.js | 36 +++++++++++ src/plugins/comps/CompsMathWorker.js | 41 ++----------- src/plugins/comps/CompsMetadataProvider.js | 68 +++++++++++++++++++++ src/plugins/comps/CompsTelemetryProvider.js | 6 +- 4 files changed, 111 insertions(+), 40 deletions(-) create mode 100644 src/plugins/comps/CompsMetadataProvider.js diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 3115ae334f..c7ae271f6a 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -31,6 +31,42 @@ export default class CompsManager extends EventEmitter { } } + getFullDataFrame(newTelemetry) { + const dataFrame = {}; + // can assume on data item + const newTelemetryKey = Object.keys(newTelemetry)[0]; + const newTelemetryData = newTelemetry[newTelemetryKey]; + const otherTelemetryKeys = Object.keys(this.#telemetryCollections).filter( + (keyString) => keyString !== newTelemetryKey + ); + // initialize the data frame with the new telemetry data + dataFrame[newTelemetryKey] = newTelemetryData; + // initialize the other telemetry data + otherTelemetryKeys.forEach((keyString) => { + dataFrame[keyString] = []; + }); + + // march through the new telemetry data and add data to the frame from the other telemetry objects + // using LOCF + + newTelemetryData.forEach((newDatum) => { + otherTelemetryKeys.forEach((otherKeyString) => { + const otherCollection = this.#telemetryCollections[otherKeyString]; + let insertionPointForNewData = otherCollection._sortedIndex(newDatum); + const otherCollectionData = otherCollection.getAll(); + if (insertionPointForNewData && insertionPointForNewData >= otherCollectionData.length) { + insertionPointForNewData = otherCollectionData.length - 1; + } + // get the closest datum to the new datum + const closestDatum = otherCollectionData[insertionPointForNewData]; + if (closestDatum) { + dataFrame[otherKeyString].push(closestDatum); + } + }); + }); + return dataFrame; + } + #removeTelemetryObject = (telemetryObject) => { console.debug('❌ CompsManager: removeTelemetryObject', telemetryObject); const keyString = this.#openmct.objects.makeKeyString(telemetryObject.identifier); diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 5692538889..5331309f1e 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -7,12 +7,12 @@ onconnect = function (e) { port.onmessage = function (event) { console.debug('🧮 Comps Math Worker message:', event); try { - const { type, callbackID, telemetryForComps, newTelemetry, expression } = event.data; + const { type, callbackID, telemetryForComps, expression } = event.data; if (type === 'calculateRequest') { const result = calculateRequest(telemetryForComps, expression); port.postMessage({ type: 'calculationRequestResult', callbackID, result }); } else if (type === 'calculateSubscription') { - const result = calculateSubscription(telemetryForComps, newTelemetry, expression); + const result = calculateSubscription(telemetryForComps, expression); if (result.length) { port.postMessage({ type: 'calculationSubscriptionResult', callbackID, result }); } @@ -37,41 +37,8 @@ function getFullDataFrame(telemetryForComps) { return dataFrame; } -function getReducedDataFrame(telemetryForComps, newTelemetry) { - const reducedDataFrame = {}; - const fullDataFrame = getFullDataFrame(telemetryForComps); - // we can assume (due to telemetryCollections) that newTelmetry has at most one key - const newTelemetryKey = Object.keys(newTelemetry)[0]; - const newTelmetryData = newTelemetry[newTelemetryKey]; - // initalize maps for other telemetry - Object.keys(telemetryForComps).forEach((key) => { - if (key !== newTelemetryKey) { - reducedDataFrame[key] = new Map(); - } - }); - reducedDataFrame[newTelemetryKey] = new Map( - Object.values(newTelmetryData).map((item) => { - return [item.utc, item]; - }) - ); - - // march through the new telemetry and look for corresponding telemetry in the other dataset - newTelmetryData.forEach((value) => { - const newTelemetryUtc = value.utc; - Object.keys(telemetryForComps).forEach((otherKey) => { - if (otherKey !== newTelemetryKey) { - const otherDataSet = fullDataFrame[otherKey]; - if (otherDataSet.has(newTelemetryUtc)) { - reducedDataFrame[otherKey].set(newTelemetryUtc, otherDataSet.get(newTelemetryUtc)); - } - } - }); - }); - return reducedDataFrame; -} - -function calculateSubscription(telemetryForComps, newTelemetry, expression) { - const dataFrame = getReducedDataFrame(telemetryForComps, newTelemetry); +function calculateSubscription(telemetryForComps, expression) { + const dataFrame = getFullDataFrame(telemetryForComps); return calculate(dataFrame, expression); } diff --git a/src/plugins/comps/CompsMetadataProvider.js b/src/plugins/comps/CompsMetadataProvider.js new file mode 100644 index 0000000000..2a97eb2255 --- /dev/null +++ b/src/plugins/comps/CompsMetadataProvider.js @@ -0,0 +1,68 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2024, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +export default class CompsMetadataProvider { + constructor(openmct) { + this.openmct = openmct; + } + + supportsMetadata(domainObject) { + return domainObject.type === 'comps'; + } + + getDomains(domainObject) { + return this.openmct.time.getAllTimeSystems().map(function (ts, i) { + return { + key: ts.key, + name: ts.name, + format: ts.timeFormat, + hints: { + domain: i + } + }; + }); + } + + getMetadata(domainObject) { + return { + values: this.getDomains().concat([ + { + key: 'output', + source: 'output', + name: 'Output', + formatString: '%0.2f', + hints: { + range: 1 + } + }, + { + key: 'utc', + name: 'Time', + format: 'utc', + hints: { + domain: 1 + } + } + ]) + }; + } +} diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index f6750106c4..58eaf8d098 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -78,11 +78,11 @@ export default class CompsTelemetryProvider { #computeOnNewTelemetry(specificCompsManager, newTelemetry, callbackID) { const expression = specificCompsManager.getExpression(); - const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry(); + const telemetryForComps = specificCompsManager.getFullDataFrame(newTelemetry); + console.debug('🏟️ created new Data frame:', telemetryForComps); this.#sharedWorker.port.postMessage({ type: 'calculateSubscription', telemetryForComps, - newTelemetry, expression, callbackID }); @@ -127,7 +127,7 @@ export default class CompsTelemetryProvider { onSharedWorkerMessage(event) { console.log('📝 Shared worker message:', event.data); const { type, result, callbackID } = event.data; - if (type === 'calculationSubscriptionResult') { + if (type === 'calculationSubscriptionResult' && this.#subscriptionCallbacks[callbackID]) { this.#subscriptionCallbacks[callbackID](result); } else if (type === 'calculationRequestResult') { this.#requestPromises[callbackID].resolve(result); From a94c75261679883d5de1dfb2cab1cb82be634608 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 8 Aug 2024 15:35:30 +0200 Subject: [PATCH 010/139] slowing adding gui --- src/plugins/comps/CompsManager.js | 2 +- src/plugins/comps/components/CompsView.vue | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index c7ae271f6a..48ce6cf8b2 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -94,7 +94,7 @@ export default class CompsManager extends EventEmitter { } getExpression() { - return 'a + b'; + return 'a * b '; } #addTelemetryObject = async (telemetryObject) => { diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 3118fc1c27..2251f8c59f 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -21,7 +21,19 @@ --> diff --git a/src/plugins/comps/plugin.js b/src/plugins/comps/plugin.js index 4311e394bd..177b676621 100644 --- a/src/plugins/comps/plugin.js +++ b/src/plugins/comps/plugin.js @@ -28,7 +28,7 @@ export default function CompsPlugin() { return function install(openmct) { openmct.types.addType('comps', { - name: 'Comps', + name: 'Derived Telemetry', key: 'comps', description: 'Add one or more telemetry objects, apply a mathematical operation to them, and republish the result as a new telemetry object.', From a0a2ead5e715c88ec6c23c38a8587e1c7d44e69a Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 12 Aug 2024 17:18:25 -0500 Subject: [PATCH 012/139] rudimentary expression editor --- src/plugins/comps/CompsManager.js | 10 +++++++++- src/plugins/comps/CompsTelemetryProvider.js | 1 + src/plugins/comps/components/CompsView.vue | 12 +++++++++++- src/plugins/comps/plugin.js | 7 ++++++- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index dcee519bdd..d32cf19603 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -24,6 +24,14 @@ export default class CompsManager extends EventEmitter { this.#telemetryLoadedPromises = []; } + persist() { + this.#openmct.objects.mutate( + this.#domainObject, + 'configuration.comps', + this.#domainObject.configuration.comps + ); + } + getTelemetryObjects() { return this.#telemetryObjects; } @@ -132,7 +140,7 @@ export default class CompsManager extends EventEmitter { } getExpression() { - return 'a + b '; + return this.#domainObject.configuration.expression; } #waitForDebounce() { diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 59cb54efa5..b741149699 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -68,6 +68,7 @@ export default class CompsTelemetryProvider { '🏟️ 2 Telemetry for comps:', specificCompsManager.requestUnderlyingTelemetry() ); + console.debug('🏟️ expression:', expression); this.#requestPromises[callbackID] = { resolve, reject }; this.#sharedWorker.port.postMessage({ type: 'calculateRequest', diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 69c0313fe8..f8364cfc3c 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -65,7 +65,17 @@
-
+
+
{{ domainObject.configuration.expression }}
+
+ +
+
diff --git a/src/plugins/comps/plugin.js b/src/plugins/comps/plugin.js index 177b676621..bda4411c99 100644 --- a/src/plugins/comps/plugin.js +++ b/src/plugins/comps/plugin.js @@ -35,7 +35,12 @@ export default function CompsPlugin() { creatable: true, cssClass: 'icon-telemetry', initialize: function (domainObject) { - domainObject.configuration = {}; + domainObject.configuration = { + comps: { + expression: '', + parameters: [] + } + }; domainObject.composition = []; domainObject.telemetry = {}; } From e5719fc71b8a348461c1fd93a371f615c7a70d35 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 13 Aug 2024 09:54:45 -0500 Subject: [PATCH 013/139] correctly persist --- src/plugins/comps/CompsManager.js | 43 ++++++++++++++++++++-- src/plugins/comps/CompsMathWorker.js | 4 ++ src/plugins/comps/components/CompsView.vue | 21 +++++++---- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index d32cf19603..d4deb03b6f 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -18,10 +18,30 @@ export default class CompsManager extends EventEmitter { this.#domainObject = domainObject; } - async load() { - await this.#loadComposition(); - await Promise.all(this.#telemetryLoadedPromises); - this.#telemetryLoadedPromises = []; + addParameter(keyString) { + const random4Digit = Math.floor(1000 + Math.random() * 9000); + this.#domainObject.configuration.comps.parameters.push({ + keyString, + name: `New_Parameter_${random4Digit}`, + valueToUse: 'sin', + testValue: 0 + }); + this.persist(); + } + + deleteParameter(keyString) { + this.#domainObject.configuration.comps.parameters = + this.#domainObject.configuration.comps.parameters.filter( + (parameter) => parameter.keyString !== keyString + ); + // if there are no parameters referencing this parameter keyString, remove the telemetry object too + const parameterExists = this.#domainObject.configuration.comps.parameters.some( + (parameter) => parameter.keyString === keyString + ); + if (!parameterExists) { + this.#composition.remove(this.#telemetryObjects[keyString]); + } + this.persist(); } persist() { @@ -32,6 +52,12 @@ export default class CompsManager extends EventEmitter { ); } + async load() { + await this.#loadComposition(); + await Promise.all(this.#telemetryLoadedPromises); + this.#telemetryLoadedPromises = []; + } + getTelemetryObjects() { return this.#telemetryObjects; } @@ -167,6 +193,15 @@ export default class CompsManager extends EventEmitter { const telemetryLoadedPromise = this.#telemetryCollections[keyString].load(); this.#telemetryLoadedPromises.push(telemetryLoadedPromise); console.debug('📢 CompsManager: loaded telemetry collection', keyString); + + // check to see if we have a corresponding parameter + // if not, add one + const parameterExists = this.#domainObject.configuration.comps.parameters.some( + (parameter) => parameter.keyString === keyString + ); + if (!parameterExists) { + this.addParameter(keyString); + } }; static getCompsManager(domainObject, openmct, compsManagerPool) { diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 5331309f1e..ac262b12ce 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -1,5 +1,6 @@ import { evaluate } from 'mathjs'; +// eslint-disable-next-line no-undef onconnect = function (e) { const port = e.ports[0]; console.debug('🧮 Comps Math Worker connected'); @@ -52,6 +53,9 @@ function calculate(dataFrame, expression) { // Iterate over the first dataset and check for matching utc in the other dataset const firstDataSet = Object.values(dataFrame)[0]; const secondDataSet = Object.values(dataFrame)[1]; + if (!firstDataSet || !secondDataSet) { + return sumResults; + } for (const [utc, item1] of firstDataSet.entries()) { if (secondDataSet.has(utc)) { diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index f8364cfc3c..dbb31b1b6c 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -40,7 +40,7 @@
- From 1c68c7e044de0223ee1caf5a1d978841834f6d9c Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 3 Sep 2024 16:48:17 +0200 Subject: [PATCH 034/139] be consistent with output key --- src/plugins/comps/CompsMathWorker.js | 4 ++-- src/plugins/comps/CompsMetadataProvider.js | 4 ++-- src/plugins/comps/components/CompsView.vue | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index faa1636c87..8ddea694dc 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -83,8 +83,8 @@ function calculate(dataFrame, parameters, expression) { if (missingData) { return; } - const output = evaluate(expression, scope); - sumResults.push({ [referenceParameter.timeKey]: referenceTime, output }); + const compsOutput = evaluate(expression, scope); + sumResults.push({ [referenceParameter.timeKey]: referenceTime, compsOutput }); }); return sumResults; } diff --git a/src/plugins/comps/CompsMetadataProvider.js b/src/plugins/comps/CompsMetadataProvider.js index cc05bf9d30..6d859ef723 100644 --- a/src/plugins/comps/CompsMetadataProvider.js +++ b/src/plugins/comps/CompsMetadataProvider.js @@ -58,8 +58,8 @@ export default class CompsMetadataProvider { const metaDataToReturn = { values: this.getDomains().concat([ { - key: 'comps-output', - source: 'comps-output', + key: 'compsOutput', + source: 'compsOutput', name: 'Output', formatString: specificCompsManager.getOutputFormat(), hints: { diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 937a897366..d99427b493 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -193,7 +193,7 @@ function updateExpression() { function getValueFormatter() { const metaData = openmct.telemetry.getMetadata(domainObject); - const outputMetaDatum = metaData.values().find((metaDatum) => metaDatum.key === 'comps-output'); + const outputMetaDatum = metaData.values().find((metaDatum) => metaDatum.key === 'compsOutput'); return openmct.telemetry.getValueFormatter(outputMetaDatum); } From 5894363ba5d42bf24b0df8aa9237cc2b6df1b8f3 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 4 Sep 2024 15:28:00 +0200 Subject: [PATCH 035/139] add icons and fix errant telemetry --- src/api/telemetry/TelemetryCollection.js | 4 ++-- src/plugins/comps/CompsManager.js | 23 ++++++++++++++------- src/plugins/comps/CompsTelemetryProvider.js | 6 +++--- src/plugins/comps/components/CompsView.vue | 16 +++++++++++++- src/plugins/comps/components/comps.scss | 5 +++++ 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/api/telemetry/TelemetryCollection.js b/src/api/telemetry/TelemetryCollection.js index 0b1887f3cc..3b7cd9d935 100644 --- a/src/api/telemetry/TelemetryCollection.js +++ b/src/api/telemetry/TelemetryCollection.js @@ -485,9 +485,9 @@ export default class TelemetryCollection extends EventEmitter { this.boundedTelemetry = []; this.futureBuffer = []; - this.emit('clear'); + const telemetryLoadPromise = this._requestHistoricalTelemetry(); - this._requestHistoricalTelemetry(); + this.emit('clear', telemetryLoadPromise); } /** diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index f9f6ce3542..1d91c1b2fc 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -9,12 +9,14 @@ export default class CompsManager extends EventEmitter { #dataFrame = {}; #telemetryLoadedPromises = []; #loaded = false; + #compositionLoaded = false; #telemetryProcessors = {}; constructor(openmct, domainObject) { super(); this.#openmct = openmct; this.#domainObject = domainObject; + this.clearData = this.clearData.bind(this); } isValid() { @@ -110,13 +112,16 @@ export default class CompsManager extends EventEmitter { this.#domainObject = passedDomainObject; } - isLoaded() { - return this.#loaded; + isReady() { + return this.isValid() && this.#loaded; } async load() { - if (!this.#loaded) { + if (!this.#compositionLoaded) { await this.#loadComposition(); + this.#compositionLoaded = true; + } + if (!this.#loaded) { await Promise.all(this.#telemetryLoadedPromises); this.#telemetryLoadedPromises = []; this.#loaded = true; @@ -130,7 +135,7 @@ export default class CompsManager extends EventEmitter { if (!this.#telemetryCollections[keyString].loaded) { const specificTelemetryProcessor = this.#getTelemetryProcessor(keyString); this.#telemetryCollections[keyString].on('add', specificTelemetryProcessor); - this.#telemetryCollections[keyString].on('clear', this.#clearData); + this.#telemetryCollections[keyString].on('clear', this.clearData); this.#telemetryCollections[keyString].load(); } }); @@ -142,7 +147,7 @@ export default class CompsManager extends EventEmitter { const specificTelemetryProcessor = this.#telemetryProcessors[keyString]; delete this.#telemetryProcessors[keyString]; this.#telemetryCollections[keyString].off('add', specificTelemetryProcessor); - this.#telemetryCollections[keyString].off('clear', this.#clearData); + this.#telemetryCollections[keyString].off('clear', this.clearData); this.#telemetryCollections[keyString].destroy(); }); } @@ -236,8 +241,10 @@ export default class CompsManager extends EventEmitter { this.emit('underlyingTelemetryUpdated', { [keyString]: newTelemetry }); }; - #clearData() { - console.debug('Clear Data'); + clearData(telemetryLoadedPromise) { + console.debug('💨 Clear Data fired, need to wait for all telemetry collections to load'); + this.#loaded = false; + this.#telemetryLoadedPromises.push(telemetryLoadedPromise); } getOutputFormat() { @@ -256,7 +263,7 @@ export default class CompsManager extends EventEmitter { this.#openmct.telemetry.requestCollection(telemetryObject); this.#telemetryCollections[keyString].on('add', this.#getTelemetryProcessor(keyString)); - this.#telemetryCollections[keyString].on('clear', this.#clearData); + this.#telemetryCollections[keyString].on('clear', this.clearData); const telemetryLoadedPromise = this.#telemetryCollections[keyString].load(); this.#telemetryLoadedPromises.push(telemetryLoadedPromise); console.debug('📢 CompsManager: loaded telemetry collection', keyString); diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index d401b5e599..fb1a7083e9 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -77,17 +77,17 @@ export default class CompsTelemetryProvider { callbackID }; this.#sharedWorker.port.postMessage(payload); + console.debug('🧮 Comps Telemetry Provider: sending request request (bleh)', payload); }); }); } #computeOnNewTelemetry(specificCompsManager, newTelemetry, callbackID) { - if (!specificCompsManager.isValid() || !specificCompsManager.isLoaded()) { + if (!specificCompsManager.isReady()) { return; } const expression = specificCompsManager.getExpression(); const telemetryForComps = specificCompsManager.getFullDataFrame(newTelemetry); - // TODO: this is nasty. instead figure out why a proxy is getting in here const parameters = JSON.parse(JSON.stringify(specificCompsManager.getParameters())); const payload = { type: 'calculateSubscription', @@ -96,7 +96,7 @@ export default class CompsTelemetryProvider { parameters, callbackID }; - console.debug('🧮 Comps Telemetry Provider: sending calculation request', payload); + console.debug('🧮 Comps Telemetry Provider: sending subscription request', payload); this.#sharedWorker.port.postMessage(payload); } diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index d99427b493..2fe710e7e9 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -62,7 +62,17 @@ - {{ compsManager.getTelemetryObjectForParameter(parameter.keyString)?.name }} +
+
+
+ {{ compsManager.getTelemetryObjectForParameter(parameter.keyString)?.name }} +
+
 {{ parameter.name }}
Date: Wed, 4 Sep 2024 11:58:33 -0700 Subject: [PATCH 039/139] Style enhancements for Derived Telemetry object - Closes #7823 - Font files updated - do not merge! - New glyph and data URI background for object. --- src/styles/_constants.scss | 4 +- src/styles/_glyphs.scss | 707 ++++++---- src/styles/fonts/Open MCT Symbols 16px.json | 1349 ++++++++++++++----- src/styles/fonts/Open-MCT-Symbols-16px.ttf | Bin 26764 -> 26988 bytes src/styles/fonts/Open-MCT-Symbols-16px.woff | Bin 26840 -> 27064 bytes 5 files changed, 1518 insertions(+), 542 deletions(-) diff --git a/src/styles/_constants.scss b/src/styles/_constants.scss index f8e00420d0..cf5d59a5a1 100755 --- a/src/styles/_constants.scss +++ b/src/styles/_constants.scss @@ -277,8 +277,9 @@ $glyph-icon-bar-chart: '\eb2c'; $glyph-icon-map: '\eb2d'; $glyph-icon-plan: '\eb2e'; $glyph-icon-timelist: '\eb2f'; -$glyph-icon-notebook-shift-log: '\eb31'; $glyph-icon-plot-scatter: '\eb30'; +$glyph-icon-notebook-shift-log: '\eb31'; +$glyph-icon-derived-telemetry: '\eb32'; /************************** GLYPHS AS DATA URI */ // Only objects have been converted, for use in Create menu and folder views @@ -335,3 +336,4 @@ $bg-icon-telemetry-aggregate: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns $bg-icon-trash: url("data:image/svg+xml;charset=UTF-8,%3csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='512px' height='512px' viewBox='0 0 512 512' enable-background='new 0 0 512 512' xml:space='preserve'%3e%3cpath d='M416,64h-96.18V32c0-17.6-14.4-32-32-32h-64c-17.6,0-32,14.4-32,32v32H96c-52.8,0-96,36-96,80s0,80,0,80h32v192 c0,52.8,43.2,96,96,96h256c52.8,0,96-43.2,96-96V224h32c0,0,0-36,0-80S468.8,64,416,64z M160,416H96V224h64V416z M288,416h-64V224 h64V416z M416,416h-64V224h64V416z'/%3e%3c/svg%3e"); $bg-icon-eye-open: url("data:image/svg+xml;charset=UTF-8,%3csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 512 512' style='enable-background:new 0 0 512 512;' xml:space='preserve'%3e%3cstyle type='text/css'%3e .st0%7bfill:%2300A14B;%7d %3c/style%3e%3ctitle%3eicon-eye-open-v2%3c/title%3e%3cg%3e%3cpath class='st0' d='M256,58.2c-122.9,0-226.1,84-255.4,197.8C29.9,369.7,133.1,453.8,256,453.8s226.1-84,255.4-197.8 C482.1,142.3,378.9,58.2,256,58.2z M414.6,294.2c-11.3,17.2-25.3,32.4-41.5,45.2c-16.4,12.9-34.5,22.8-54,29.7 c-20.2,7.1-41.4,10.7-63,10.7s-42.9-3.6-63-10.7c-19.5-6.9-37.7-16.9-54-29.7c-16.2-12.8-30.2-27.9-41.5-45.2 c-7.9-12-14.4-24.8-19.3-38.2c5-13.4,11.5-26.2,19.3-38.2c11.3-17.2,25.3-32.4,41.5-45.2c16.4-12.9,34.5-22.8,54-29.7 c20.2-7.1,41.4-10.7,63-10.7s42.9,3.6,63,10.7c19.5,6.9,37.7,16.9,54,29.7c16.2,12.8,30.2,27.9,41.5,45.2 c7.9,12,14.4,24.8,19.3,38.2C429,269.4,422.5,282.2,414.6,294.2z'/%3e%3ccircle class='st0' cx='256' cy='256' r='96'/%3e%3c/g%3e%3c/svg%3e"); $bg-icon-camera: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3ctitle%3eicon-camera-v2%3c/title%3e%3cpath d='M448,128H384L320,0H192L128,128H64A64.2,64.2,0,0,0,0,192V448a64.2,64.2,0,0,0,64,64H448a64.2,64.2,0,0,0,64-64V192A64.2,64.2,0,0,0,448,128ZM256,432A128,128,0,1,1,384,304,128,128,0,0,1,256,432Z'/%3e%3c/svg%3e"); +$bg-icon-derived-telemetry: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='512' height='512' fill='none'%3e%3cg fill='%23000' clip-path='url(%23a)'%3e%3cpath d='M54.68 261.23c2.59-5.63 5.2-11.73 7.8-18.36C83.71 188.64 120.64 123.99 176 123.99c26.2 0 50.71 14.58 72.85 43.34 18.67 24.25 32.42 54.46 40.67 75.54 19.26 49.19 39.34 70.15 46.48 72.96 7.14-2.81 27.22-23.77 46.48-72.96 11.71-29.9 28.19-62.96 49.9-86.62l-24.92-94.4C398.48 27.83 362.52 0 327.54 0H49.32C14.35 0-6.92 27.83 2.06 61.85l52.62 199.38Z'/%3e%3cpath d='M457.32 250.77a347.06 347.06 0 0 0-7.8 18.36C428.29 323.36 391.36 388.01 336 388.01c-26.2 0-50.71-14.58-72.85-43.34-18.67-24.25-32.42-54.46-40.67-75.54-19.26-49.19-39.34-70.15-46.48-72.96-7.14 2.81-27.22 23.76-46.48 72.96-11.71 29.9-28.19 62.96-49.9 86.62l24.92 94.4c8.98 34.02 44.94 61.85 79.92 61.85h278.22c34.98 0 56.25-27.83 47.27-61.85l-52.62-199.38h-.01Z'/%3e%3c/g%3e%3cdefs%3e%3cclipPath id='a'%3e%3cpath fill='%23fff' d='M0 0h512v512H0z'/%3e%3c/clipPath%3e%3c/defs%3e%3c/svg%3e"); diff --git a/src/styles/_glyphs.scss b/src/styles/_glyphs.scss index 750eba7e29..3ac76a9c50 100755 --- a/src/styles/_glyphs.scss +++ b/src/styles/_glyphs.scss @@ -21,704 +21,935 @@ *****************************************************************************/ @font-face { - // Use https://icomoon.io/app with `Icomoon.Open MCT Symbols 2018.json` to generate font files - font-family: 'symbolsfont'; - src: url('./fonts/Open-MCT-Symbols-16px.woff') format('woff'), + // Use https://icomoon.io/app with `Icomoon.Open MCT Symbols 2018.json` to generate font files + font-family: 'symbolsfont'; + src: url('./fonts/Open-MCT-Symbols-16px.woff') format('woff'), url('./fonts/Open-MCT-Symbols-16px.ttf') format('truetype'); - font-weight: normal; - font-style: normal; + font-weight: normal; + font-style: normal; } @font-face { - // Use https://icomoon.io/app with icomoon-project-Open-MCT-Symbols-12px.json to generate font files - font-family: 'symbolsfont-12px'; - src: url('./fonts/Open-MCT-Symbols-12px.woff') format('woff'), + // Use https://icomoon.io/app with icomoon-project-Open-MCT-Symbols-12px.json to generate font files + font-family: 'symbolsfont-12px'; + src: url('./fonts/Open-MCT-Symbols-12px.woff') format('woff'), url('./fonts/Open-MCT-Symbols-12px.ttf') format('truetype'); - font-weight: normal; - font-style: normal; + font-weight: normal; + font-style: normal; } /************************** 16 PX CLASSES */ .icon-alert-rect { - @include glyphBefore($glyph-icon-alert-rect); + @include glyphBefore($glyph-icon-alert-rect); } + .icon-alert-triangle { - @include glyphBefore($glyph-icon-alert-triangle); + @include glyphBefore($glyph-icon-alert-triangle); } + .icon-arrow-up { - @include glyphBefore($glyph-icon-arrow-up); + @include glyphBefore($glyph-icon-arrow-up); } + .icon-arrow-double-up { - @include glyphBefore($glyph-icon-arrow-double-up); + @include glyphBefore($glyph-icon-arrow-double-up); } + .icon-arrow-tall-up { - @include glyphBefore($glyph-icon-arrow-tall-up); + @include glyphBefore($glyph-icon-arrow-tall-up); } + .icon-arrow-right { - @include glyphBefore($glyph-icon-arrow-right); + @include glyphBefore($glyph-icon-arrow-right); } + .icon-arrow-right-equilateral { - @include glyphBefore($glyph-icon-arrow-right-equilateral); + @include glyphBefore($glyph-icon-arrow-right-equilateral); } + .icon-arrow-down { - @include glyphBefore($glyph-icon-arrow-down); + @include glyphBefore($glyph-icon-arrow-down); } + .icon-arrow-double-down { - @include glyphBefore($glyph-icon-arrow-double-down); + @include glyphBefore($glyph-icon-arrow-double-down); } + .icon-arrow-tall-down { - @include glyphBefore($glyph-icon-arrow-tall-down); + @include glyphBefore($glyph-icon-arrow-tall-down); } + .icon-arrow-left { - @include glyphBefore($glyph-icon-arrow-left); + @include glyphBefore($glyph-icon-arrow-left); } + .icon-asterisk { - @include glyphBefore($glyph-icon-asterisk); + @include glyphBefore($glyph-icon-asterisk); } + .icon-bell { - @include glyphBefore($glyph-icon-bell); + @include glyphBefore($glyph-icon-bell); } + .icon-box-round-corners { - @include glyphBefore($glyph-icon-box-round-corners); + @include glyphBefore($glyph-icon-box-round-corners); } + .icon-box-with-arrow { - @include glyphBefore($glyph-icon-box-with-arrow); + @include glyphBefore($glyph-icon-box-with-arrow); } + .icon-check { - @include glyphBefore($glyph-icon-check); + @include glyphBefore($glyph-icon-check); } + .icon-connectivity { - @include glyphBefore($glyph-icon-connectivity); + @include glyphBefore($glyph-icon-connectivity); } + .icon-database-in-brackets { - @include glyphBefore($glyph-icon-database-in-brackets); + @include glyphBefore($glyph-icon-database-in-brackets); } + .icon-eye-open { - @include glyphBefore($glyph-icon-eye-open); + @include glyphBefore($glyph-icon-eye-open); } + .icon-gear { - @include glyphBefore($glyph-icon-gear); + @include glyphBefore($glyph-icon-gear); } + .icon-gear-after { - @include glyphAfter($glyph-icon-gear); + @include glyphAfter($glyph-icon-gear); } + .icon-hourglass { - @include glyphBefore($glyph-icon-hourglass); + @include glyphBefore($glyph-icon-hourglass); } + .icon-info { - @include glyphBefore($glyph-icon-info); + @include glyphBefore($glyph-icon-info); } + .icon-link { - @include glyphBefore($glyph-icon-link); + @include glyphBefore($glyph-icon-link); } + .icon-lock { - @include glyphBefore($glyph-icon-lock); + @include glyphBefore($glyph-icon-lock); } + .icon-minus { - @include glyphBefore($glyph-icon-minus); + @include glyphBefore($glyph-icon-minus); } + .icon-people { - @include glyphBefore($glyph-icon-people); + @include glyphBefore($glyph-icon-people); } + .icon-person { - @include glyphBefore($glyph-icon-person); + @include glyphBefore($glyph-icon-person); } + .icon-plus { - @include glyphBefore($glyph-icon-plus); + @include glyphBefore($glyph-icon-plus); } + .icon-plus-in-rect { - @include glyphBefore($glyph-icon-plus-in-rect); + @include glyphBefore($glyph-icon-plus-in-rect); } + .icon-trash { - @include glyphBefore($glyph-icon-trash); + @include glyphBefore($glyph-icon-trash); } + .icon-x { - @include glyphBefore($glyph-icon-x); + @include glyphBefore($glyph-icon-x); } + .icon-brackets { - @include glyphBefore($glyph-icon-brackets); + @include glyphBefore($glyph-icon-brackets); } + .icon-crosshair { - @include glyphBefore($glyph-icon-crosshair); + @include glyphBefore($glyph-icon-crosshair); } + .icon-grippy { - @include glyphBefore($glyph-icon-grippy); + @include glyphBefore($glyph-icon-grippy); } + .icon-grid { - @include glyphBefore($glyph-icon-grid); + @include glyphBefore($glyph-icon-grid); } + .icon-grippy-ew { - @include glyphBefore($glyph-icon-grippy-ew); + @include glyphBefore($glyph-icon-grippy-ew); } + .icon-columns { - @include glyphBefore($glyph-icon-columns); + @include glyphBefore($glyph-icon-columns); } + .icon-rows { - @include glyphBefore($glyph-icon-rows); + @include glyphBefore($glyph-icon-rows); } + .icon-filter { - @include glyphBefore($glyph-icon-filter); + @include glyphBefore($glyph-icon-filter); } + .icon-filter-outline { - @include glyphBefore($glyph-icon-filter-outline); + @include glyphBefore($glyph-icon-filter-outline); } + .icon-suitcase { - @include glyphBefore($glyph-icon-suitcase); + @include glyphBefore($glyph-icon-suitcase); } + .icon-cursor-lock { - @include glyphBefore($glyph-icon-cursor-lock); + @include glyphBefore($glyph-icon-cursor-lock); } + .icon-flag { - @include glyphBefore($glyph-icon-flag); + @include glyphBefore($glyph-icon-flag); } + .icon-eye-disabled { - @include glyphBefore($glyph-icon-eye-disabled); + @include glyphBefore($glyph-icon-eye-disabled); } + .icon-notebook-page { - @include glyphBefore($glyph-icon-notebook-page); + @include glyphBefore($glyph-icon-notebook-page); } + .icon-unlocked { - @include glyphBefore($glyph-icon-unlocked); + @include glyphBefore($glyph-icon-unlocked); } + .icon-circle { - @include glyphBefore($glyph-icon-circle); + @include glyphBefore($glyph-icon-circle); } + .icon-draft { - @include glyphBefore($glyph-icon-draft); + @include glyphBefore($glyph-icon-draft); } + .icon-question-mark { - @include glyphBefore($glyph-icon-question-mark); + @include glyphBefore($glyph-icon-question-mark); } + .icon-circle-slash { - @include glyphBefore($glyph-icon-circle-slash); + @include glyphBefore($glyph-icon-circle-slash); } + .icon-status-poll-check { - @include glyphBefore($glyph-icon-status-poll-check); + @include glyphBefore($glyph-icon-status-poll-check); } + .icon-status-poll-caution { - @include glyphBefore($glyph-icon-status-poll-caution); + @include glyphBefore($glyph-icon-status-poll-caution); } + .icon-status-poll-circle-slash { - @include glyphBefore($glyph-icon-status-poll-circle-slash); + @include glyphBefore($glyph-icon-status-poll-circle-slash); } + .icon-status-poll-question-mark { - @include glyphBefore($glyph-icon-status-poll-question-mark); + @include glyphBefore($glyph-icon-status-poll-question-mark); } + .icon-status-poll-edit { - @include glyphBefore($glyph-icon-status-poll-edit); + @include glyphBefore($glyph-icon-status-poll-edit); } + .icon-stale { - @include glyphBefore($glyph-icon-stale); + @include glyphBefore($glyph-icon-stale); } + .icon-arrows-right-left { - @include glyphBefore($glyph-icon-arrows-right-left); + @include glyphBefore($glyph-icon-arrows-right-left); } + .icon-arrows-up-down { - @include glyphBefore($glyph-icon-arrows-up-down); + @include glyphBefore($glyph-icon-arrows-up-down); } + .icon-bullet { - @include glyphBefore($glyph-icon-bullet); + @include glyphBefore($glyph-icon-bullet); } + .icon-calendar { - @include glyphBefore($glyph-icon-calendar); + @include glyphBefore($glyph-icon-calendar); } + .icon-chain-links { - @include glyphBefore($glyph-icon-chain-links); + @include glyphBefore($glyph-icon-chain-links); } + .icon-download { - @include glyphBefore($glyph-icon-download); + @include glyphBefore($glyph-icon-download); } + .icon-duplicate { - @include glyphBefore($glyph-icon-duplicate); + @include glyphBefore($glyph-icon-duplicate); } + .icon-folder-new { - @include glyphBefore($glyph-icon-folder-new); + @include glyphBefore($glyph-icon-folder-new); } + .icon-fullscreen-collapse { - @include glyphBefore($glyph-icon-fullscreen-collapse); + @include glyphBefore($glyph-icon-fullscreen-collapse); } + .icon-fullscreen-expand { - @include glyphBefore($glyph-icon-fullscreen-expand); + @include glyphBefore($glyph-icon-fullscreen-expand); } + .icon-layers { - @include glyphBefore($glyph-icon-layers); + @include glyphBefore($glyph-icon-layers); } + .icon-line-horz { - @include glyphBefore($glyph-icon-line-horz); + @include glyphBefore($glyph-icon-line-horz); } + .icon-magnify { - @include glyphBefore($glyph-icon-magnify); + @include glyphBefore($glyph-icon-magnify); } + .icon-magnify-in { - @include glyphBefore($glyph-icon-magnify-in); + @include glyphBefore($glyph-icon-magnify-in); } + .icon-magnify-out { - @include glyphBefore($glyph-icon-magnify-out); + @include glyphBefore($glyph-icon-magnify-out); } + .icon-menu-hamburger { - @include glyphBefore($glyph-icon-menu-hamburger); + @include glyphBefore($glyph-icon-menu-hamburger); } + .icon-move { - @include glyphBefore($glyph-icon-move); + @include glyphBefore($glyph-icon-move); } + .icon-new-window { - @include glyphBefore($glyph-icon-new-window); + @include glyphBefore($glyph-icon-new-window); } + .icon-paint-bucket { - @include glyphBefore($glyph-icon-paint-bucket); + @include glyphBefore($glyph-icon-paint-bucket); } + .icon-pencil { - @include glyphBefore($glyph-icon-pencil); + @include glyphBefore($glyph-icon-pencil); } + .icon-pencil-in-brackets { - @include glyphBefore($glyph-icon-pencil-in-brackets); + @include glyphBefore($glyph-icon-pencil-in-brackets); } + .icon-play { - @include glyphBefore($glyph-icon-play); + @include glyphBefore($glyph-icon-play); } + .icon-pause { - @include glyphBefore($glyph-icon-pause); + @include glyphBefore($glyph-icon-pause); } + .icon-plot-resource { - @include glyphBefore($glyph-icon-plot-resource); + @include glyphBefore($glyph-icon-plot-resource); } + .icon-pointer-left { - @include glyphBefore($glyph-icon-pointer-left); + @include glyphBefore($glyph-icon-pointer-left); } + .icon-pointer-right { - @include glyphBefore($glyph-icon-pointer-right); + @include glyphBefore($glyph-icon-pointer-right); } + .icon-refresh { - @include glyphBefore($glyph-icon-refresh); + @include glyphBefore($glyph-icon-refresh); } + .icon-save { - @include glyphBefore($glyph-icon-save); + @include glyphBefore($glyph-icon-save); } + .icon-save-as { - @include glyphBefore($glyph-icon-save-as); + @include glyphBefore($glyph-icon-save-as); } + .icon-sine { - @include glyphBefore($glyph-icon-sine); + @include glyphBefore($glyph-icon-sine); } + .icon-font { - @include glyphBefore($glyph-icon-font); + @include glyphBefore($glyph-icon-font); } + .icon-thumbs-strip { - @include glyphBefore($glyph-icon-thumbs-strip); + @include glyphBefore($glyph-icon-thumbs-strip); } + .icon-two-parts-both { - @include glyphBefore($glyph-icon-two-parts-both); + @include glyphBefore($glyph-icon-two-parts-both); } + .icon-two-parts-one-only { - @include glyphBefore($glyph-icon-two-parts-one-only); + @include glyphBefore($glyph-icon-two-parts-one-only); } + .icon-resync { - @include glyphBefore($glyph-icon-resync); + @include glyphBefore($glyph-icon-resync); } + .icon-reset { - @include glyphBefore($glyph-icon-reset); + @include glyphBefore($glyph-icon-reset); } + .icon-x-in-circle { - @include glyphBefore($glyph-icon-x-in-circle); + @include glyphBefore($glyph-icon-x-in-circle); } + .icon-brightness { - @include glyphBefore($glyph-icon-brightness); + @include glyphBefore($glyph-icon-brightness); } + .icon-contrast { - @include glyphBefore($glyph-icon-contrast); + @include glyphBefore($glyph-icon-contrast); } + .icon-expand { - @include glyphBefore($glyph-icon-expand); + @include glyphBefore($glyph-icon-expand); } + .icon-list-view { - @include glyphBefore($glyph-icon-list-view); + @include glyphBefore($glyph-icon-list-view); } + .icon-grid-snap-to { - @include glyphBefore($glyph-icon-grid-snap-to); + @include glyphBefore($glyph-icon-grid-snap-to); } + .icon-grid-snap-no { - @include glyphBefore($glyph-icon-grid-snap-no); + @include glyphBefore($glyph-icon-grid-snap-no); } + .icon-frame-show { - @include glyphBefore($glyph-icon-frame-show); + @include glyphBefore($glyph-icon-frame-show); } + .icon-frame-hide { - @include glyphBefore($glyph-icon-frame-hide); + @include glyphBefore($glyph-icon-frame-hide); } + .icon-import { - @include glyphBefore($glyph-icon-import); + @include glyphBefore($glyph-icon-import); } + .icon-export { - @include glyphBefore($glyph-icon-export); + @include glyphBefore($glyph-icon-export); } + .icon-font-size { - @include glyphBefore($glyph-icon-font-size); + @include glyphBefore($glyph-icon-font-size); } + .icon-clear-data { - @include glyphBefore($glyph-icon-clear-data); + @include glyphBefore($glyph-icon-clear-data); } + .icon-history { - @include glyphBefore($glyph-icon-history); + @include glyphBefore($glyph-icon-history); } + .icon-arrow-nav-to-parent { - @include glyphBefore($glyph-icon-arrow-nav-to-parent); + @include glyphBefore($glyph-icon-arrow-nav-to-parent); } + .icon-crosshair-in-circle { - @include glyphBefore($glyph-icon-crosshair-in-circle); + @include glyphBefore($glyph-icon-crosshair-in-circle); } + .icon-target { - @include glyphBefore($glyph-icon-target); + @include glyphBefore($glyph-icon-target); } + .icon-items-collapse { - @include glyphBefore($glyph-icon-items-collapse); + @include glyphBefore($glyph-icon-items-collapse); } + .icon-items-expand { - @include glyphBefore($glyph-icon-items-expand); + @include glyphBefore($glyph-icon-items-expand); } + .icon-3-dots { - @include glyphBefore($glyph-icon-3-dots); + @include glyphBefore($glyph-icon-3-dots); } + .icon-grid-on { - @include glyphBefore($glyph-icon-grid-on); + @include glyphBefore($glyph-icon-grid-on); } + .icon-grid-off { - @include glyphBefore($glyph-icon-grid-off); + @include glyphBefore($glyph-icon-grid-off); } + .icon-camera { - @include glyphBefore($glyph-icon-camera); + @include glyphBefore($glyph-icon-camera); } + .icon-folders-collapse { - @include glyphBefore($glyph-icon-folders-collapse); + @include glyphBefore($glyph-icon-folders-collapse); } + .icon-activity { - @include glyphBefore($glyph-icon-activity); + @include glyphBefore($glyph-icon-activity); } + .icon-activity-mode { - @include glyphBefore($glyph-icon-activity-mode); + @include glyphBefore($glyph-icon-activity-mode); } + .icon-autoflow-tabular { - @include glyphBefore($glyph-icon-autoflow-tabular); + @include glyphBefore($glyph-icon-autoflow-tabular); } + .icon-clock { - @include glyphBefore($glyph-icon-clock); + @include glyphBefore($glyph-icon-clock); } + .icon-database { - @include glyphBefore($glyph-icon-database); + @include glyphBefore($glyph-icon-database); } + .icon-database-query { - @include glyphBefore($glyph-icon-database-query); + @include glyphBefore($glyph-icon-database-query); } + .icon-dataset { - @include glyphBefore($glyph-icon-dataset); + @include glyphBefore($glyph-icon-dataset); } + .icon-datatable { - @include glyphBefore($glyph-icon-datatable); + @include glyphBefore($glyph-icon-datatable); } + .icon-dictionary { - @include glyphBefore($glyph-icon-dictionary); + @include glyphBefore($glyph-icon-dictionary); } + .icon-folder { - @include glyphBefore($glyph-icon-folder); + @include glyphBefore($glyph-icon-folder); } + .icon-image { - @include glyphBefore($glyph-icon-image); + @include glyphBefore($glyph-icon-image); } + .icon-layout { - @include glyphBefore($glyph-icon-layout); + @include glyphBefore($glyph-icon-layout); } + .icon-object { - @include glyphBefore($glyph-icon-object); + @include glyphBefore($glyph-icon-object); } + .icon-object-unknown { - @include glyphBefore($glyph-icon-object-unknown); + @include glyphBefore($glyph-icon-object-unknown); } + .icon-packet { - @include glyphBefore($glyph-icon-packet); + @include glyphBefore($glyph-icon-packet); } + .icon-page { - @include glyphBefore($glyph-icon-page); + @include glyphBefore($glyph-icon-page); } + .icon-plot-overlay { - @include glyphBefore($glyph-icon-plot-overlay); + @include glyphBefore($glyph-icon-plot-overlay); } + .icon-plot-stacked { - @include glyphBefore($glyph-icon-plot-stacked); + @include glyphBefore($glyph-icon-plot-stacked); } + .icon-session { - @include glyphBefore($glyph-icon-session); + @include glyphBefore($glyph-icon-session); } + .icon-tabular { - @include glyphBefore($glyph-icon-tabular); + @include glyphBefore($glyph-icon-tabular); } + .icon-tabular-lad { - @include glyphBefore($glyph-icon-tabular-lad); + @include glyphBefore($glyph-icon-tabular-lad); } + .icon-tabular-lad-set { - @include glyphBefore($glyph-icon-tabular-lad-set); + @include glyphBefore($glyph-icon-tabular-lad-set); } + .icon-tabular-realtime { - @include glyphBefore($glyph-icon-tabular-realtime); + @include glyphBefore($glyph-icon-tabular-realtime); } + .icon-tabular-scrolling { - @include glyphBefore($glyph-icon-tabular-scrolling); + @include glyphBefore($glyph-icon-tabular-scrolling); } + .icon-telemetry { - @include glyphBefore($glyph-icon-telemetry); + @include glyphBefore($glyph-icon-telemetry); } + .icon-timeline { - @include glyphBefore($glyph-icon-timeline); + @include glyphBefore($glyph-icon-timeline); } + .icon-timer { - @include glyphBefore($glyph-icon-timer); + @include glyphBefore($glyph-icon-timer); } + .icon-topic { - @include glyphBefore($glyph-icon-topic); + @include glyphBefore($glyph-icon-topic); } + .icon-box-with-dashed-lines { - @include glyphBefore($glyph-icon-box-with-dashed-lines); + @include glyphBefore($glyph-icon-box-with-dashed-lines); } + .icon-summary-widget { - @include glyphBefore($glyph-icon-summary-widget); + @include glyphBefore($glyph-icon-summary-widget); } + .icon-notebook { - @include glyphBefore($glyph-icon-notebook); + @include glyphBefore($glyph-icon-notebook); } + .icon-tabs-view { - @include glyphBefore($glyph-icon-tabs-view); + @include glyphBefore($glyph-icon-tabs-view); } + .icon-flexible-layout { - @include glyphBefore($glyph-icon-flexible-layout); + @include glyphBefore($glyph-icon-flexible-layout); } + .icon-generator-telemetry { - @include glyphBefore($glyph-icon-generator-telemetry); + @include glyphBefore($glyph-icon-generator-telemetry); } + .icon-generator-events { - @include glyphBefore($glyph-icon-generator-events); + @include glyphBefore($glyph-icon-generator-events); } + .icon-gauge { - @include glyphBefore($glyph-icon-gauge); + @include glyphBefore($glyph-icon-gauge); } + .icon-spectra { - @include glyphBefore($glyph-icon-spectra); + @include glyphBefore($glyph-icon-spectra); } + .icon-spectra-telemetry { - @include glyphBefore($glyph-icon-spectra-telemetry); + @include glyphBefore($glyph-icon-spectra-telemetry); } + .icon-command { - @include glyphBefore($glyph-icon-command); + @include glyphBefore($glyph-icon-command); } + .icon-conditional { - @include glyphBefore($glyph-icon-conditional); + @include glyphBefore($glyph-icon-conditional); } + .icon-condition-widget { - @include glyphBefore($glyph-icon-condition-widget); + @include glyphBefore($glyph-icon-condition-widget); } + .icon-alphanumeric { - @include glyphBefore($glyph-icon-alphanumeric); + @include glyphBefore($glyph-icon-alphanumeric); } + .icon-image-telemetry { - @include glyphBefore($glyph-icon-image-telemetry); + @include glyphBefore($glyph-icon-image-telemetry); } + .icon-telemetry-aggregate { - @include glyphBefore($glyph-icon-telemetry-aggregate); + @include glyphBefore($glyph-icon-telemetry-aggregate); } + .icon-bar-chart { - @include glyphBefore($glyph-icon-bar-chart); + @include glyphBefore($glyph-icon-bar-chart); } + .icon-map { - @include glyphBefore($glyph-icon-map); + @include glyphBefore($glyph-icon-map); } + .icon-plan { - @include glyphBefore($glyph-icon-plan); + @include glyphBefore($glyph-icon-plan); } + .icon-timelist { - @include glyphBefore($glyph-icon-timelist); -} -.icon-notebook-shift-log { - @include glyphBefore($glyph-icon-notebook-shift-log); + @include glyphBefore($glyph-icon-timelist); } + .icon-plot-scatter { - @include glyphBefore($glyph-icon-plot-scatter); + @include glyphBefore($glyph-icon-plot-scatter); +} + +.icon-notebook-shift-log { + @include glyphBefore($glyph-icon-notebook-shift-log); +} + +.icon-derived-telemetry { + @include glyphBefore($glyph-icon-derived-telemetry); } /************************** 12 PX CLASSES */ // TODO: sync with 16px redo as of 10/25/18 .icon-filter-12px { - @include glyphBefore($glyph-icon-filter, 'symbolsfont-12px'); + @include glyphBefore($glyph-icon-filter, 'symbolsfont-12px'); } + .icon-filter-outline-12px { - @include glyphBefore($glyph-icon-filter-outline, 'symbolsfont-12px'); + @include glyphBefore($glyph-icon-filter-outline, 'symbolsfont-12px'); } + .icon-crosshair-12px { - @include glyphBefore($glyph-icon-crosshair, 'symbolsfont-12px'); + @include glyphBefore($glyph-icon-crosshair, 'symbolsfont-12px'); } + .icon-folder-12px { - @include glyphBefore($glyph-icon-folder, 'symbolsfont-12px'); + @include glyphBefore($glyph-icon-folder, 'symbolsfont-12px'); } + .icon-list-view-12px { - @include glyphBefore($glyph-icon-list-view, 'symbolsfont-12px'); + @include glyphBefore($glyph-icon-list-view, 'symbolsfont-12px'); } + .icon-grippy-12px { - @include glyphBefore($glyph-icon-grippy, 'symbolsfont-12px'); + @include glyphBefore($glyph-icon-grippy, 'symbolsfont-12px'); } /************************** GLYPH BG CLASSES */ .bg-icon-alert-rect { - @include glyphBg($bg-icon-alert-rect); + @include glyphBg($bg-icon-alert-rect); } + .bg-icon-alert-triangle { - @include glyphBg($bg-icon-alert-triangle); + @include glyphBg($bg-icon-alert-triangle); } + .bg-icon-bell { - @include glyphBg($bg-icon-bell); + @include glyphBg($bg-icon-bell); } + .bg-icon-info { - @include glyphBg($bg-icon-info); + @include glyphBg($bg-icon-info); } + .bg-icon-plus { - @include glyphBg($bg-icon-plus); + @include glyphBg($bg-icon-plus); } + .bg-icon-grippy-ew { - @include glyphBg($bg-icon-grippy-ew); + @include glyphBg($bg-icon-grippy-ew); } + .bg-icon-chain-links { - @include glyphBg($bg-icon-chain-links); + @include glyphBg($bg-icon-chain-links); } + .bg-icon-clock { - @include glyphBg($bg-icon-clock); + @include glyphBg($bg-icon-clock); } + .bg-icon-database { - @include glyphBg($bg-icon-database); + @include glyphBg($bg-icon-database); } + .bg-icon-database-query { - @include glyphBg($bg-icon-database-query); + @include glyphBg($bg-icon-database-query); } + .bg-icon-dataset { - @include glyphBg($bg-icon-dataset); + @include glyphBg($bg-icon-dataset); } + .bg-icon-datatable { - @include glyphBg($bg-icon-datatable); + @include glyphBg($bg-icon-datatable); } + .bg-icon-dictionary { - @include glyphBg($bg-icon-dictionary); + @include glyphBg($bg-icon-dictionary); } + .bg-icon-folder { - @include glyphBg($bg-icon-folder); + @include glyphBg($bg-icon-folder); } + .bg-icon-image { - @include glyphBg($bg-icon-image); + @include glyphBg($bg-icon-image); } + .bg-icon-layout { - @include glyphBg($bg-icon-layout); + @include glyphBg($bg-icon-layout); } + .bg-icon-object { - @include glyphBg($bg-icon-object); + @include glyphBg($bg-icon-object); } + .bg-icon-object-unknown { - @include glyphBg($bg-icon-object-unknown); + @include glyphBg($bg-icon-object-unknown); } + .bg-icon-packet { - @include glyphBg($bg-icon-packet); + @include glyphBg($bg-icon-packet); } + .bg-icon-page { - @include glyphBg($bg-icon-page); + @include glyphBg($bg-icon-page); } + .bg-icon-plot-overlay { - @include glyphBg($bg-icon-plot-overlay); + @include glyphBg($bg-icon-plot-overlay); } + .bg-icon-plot-stacked { - @include glyphBg($bg-icon-plot-stacked); + @include glyphBg($bg-icon-plot-stacked); } + .bg-icon-session { - @include glyphBg($bg-icon-session); + @include glyphBg($bg-icon-session); } + .bg-icon-tabular { - @include glyphBg($bg-icon-tabular); + @include glyphBg($bg-icon-tabular); } + .bg-icon-tabular-lad { - @include glyphBg($bg-icon-tabular-lad); + @include glyphBg($bg-icon-tabular-lad); } + .bg-icon-tabular-lad-set { - @include glyphBg($bg-icon-tabular-lad-set); + @include glyphBg($bg-icon-tabular-lad-set); } + .bg-icon-tabular-scrolling { - @include glyphBg($bg-icon-tabular-scrolling); + @include glyphBg($bg-icon-tabular-scrolling); } + .bg-icon-telemetry { - @include glyphBg($bg-icon-telemetry); + @include glyphBg($bg-icon-telemetry); } + .bg-icon-timeline { - @include glyphBg($bg-icon-timeline); + @include glyphBg($bg-icon-timeline); } + .bg-icon-timer { - @include glyphBg($bg-icon-timer); + @include glyphBg($bg-icon-timer); } + .bg-icon-box-with-dashed-lines { - @include glyphBg($bg-icon-box-with-dashed-lines); + @include glyphBg($bg-icon-box-with-dashed-lines); } + .bg-icon-summary-widget { - @include glyphBg($bg-icon-summary-widget); + @include glyphBg($bg-icon-summary-widget); } + .bg-icon-notebook { - @include glyphBg($bg-icon-notebook); + @include glyphBg($bg-icon-notebook); } + .bg-icon-tabs-view { - @include glyphBg($bg-icon-tabs-view); + @include glyphBg($bg-icon-tabs-view); } + .bg-icon-flexible-layout { - @include glyphBg($bg-icon-flexible-layout); + @include glyphBg($bg-icon-flexible-layout); } + .bg-icon-generator-telemetry { - @include glyphBg($bg-icon-generator-telemetry); + @include glyphBg($bg-icon-generator-telemetry); } + .bg-icon-generator-events { - @include glyphBg($bg-icon-generator-events); + @include glyphBg($bg-icon-generator-events); } + .bg-icon-gauge { - @include glyphBg($bg-icon-gauge); + @include glyphBg($bg-icon-gauge); } + .bg-icon-spectra { - @include glyphBg($bg-icon-spectra); + @include glyphBg($bg-icon-spectra); } + .bg-icon-spectra-telemetry { - @include glyphBg($bg-icon-spectra-telemetry); + @include glyphBg($bg-icon-spectra-telemetry); } + .bg-icon-command { - @include glyphBg($bg-icon-command); + @include glyphBg($bg-icon-command); } + .bg-icon-conditional { - @include glyphBg($bg-icon-conditional); + @include glyphBg($bg-icon-conditional); } + .bg-icon-condition-widget { - @include glyphBg($bg-icon-condition-widget); + @include glyphBg($bg-icon-condition-widget); } + .bg-icon-bar-chart { - @include glyphBg($bg-icon-bar-chart); + @include glyphBg($bg-icon-bar-chart); } + .bg-icon-map { - @include glyphBg($bg-icon-map); + @include glyphBg($bg-icon-map); } + .bg-icon-plan { - @include glyphBg($bg-icon-plan); + @include glyphBg($bg-icon-plan); } + .bg-icon-timelist { - @include glyphBg($bg-icon-timelist); + @include glyphBg($bg-icon-timelist); } + .bg-icon-plot-scatter { - @include glyphBg($bg-icon-plot-scatter); + @include glyphBg($bg-icon-plot-scatter); } + .bg-icon-notebook-shift-log { - @include glyphBg($bg-icon-notebook-shift-log); + @include glyphBg($bg-icon-notebook-shift-log); } + .bg-icon-telemetry-aggregate { - @include glyphBg($bg-icon-telemetry-aggregate); + @include glyphBg($bg-icon-telemetry-aggregate); } + .bg-icon-trash { - @include glyphBg($bg-icon-trash); + @include glyphBg($bg-icon-trash); } + .bg-icon-eye-open { - @include glyphBg($bg-icon-eye-open); + @include glyphBg($bg-icon-eye-open); } + .bg-icon-camera { - @include glyphBg($bg-icon-camera); + @include glyphBg($bg-icon-camera); +} + +.bg-icon-derived-telemetry { + @include glyphBg($bg-icon-derived-telemetry); } diff --git a/src/styles/fonts/Open MCT Symbols 16px.json b/src/styles/fonts/Open MCT Symbols 16px.json index 5f4e667125..3e2cf924cb 100644 --- a/src/styles/fonts/Open MCT Symbols 16px.json +++ b/src/styles/fonts/Open MCT Symbols 16px.json @@ -2,7 +2,7 @@ "metadata": { "name": "Open MCT Symbols 16px", "lastOpened": 0, - "created": 1674103729548 + "created": 1725468793547 }, "iconSets": [ { @@ -1328,19 +1328,27 @@ "tempChar": "" }, { - "order": 214, + "order": 218, "id": 184, "name": "icon-notebook-restricted", "prevSize": 16, "code": 60209, "tempChar": "" + }, + { + "order": 217, + "id": 186, + "name": "icon-telemetry-derived", + "prevSize": 16, + "code": 60210, + "tempChar": "" } ], "id": 0, "metadata": { "name": "Open MCT Symbols 16px", "importSize": { - "width": 512, + "width": 576, "height": 512 }, "designer": "Charles Hacskaylo" @@ -1355,7 +1363,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-alert-rect-v2"], + "tags": [ + "icon-alert-rect-v2" + ], "colorPermutations": { "12552552551": [] } @@ -1367,97 +1377,137 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-alert-triangle-v2"], + "tags": [ + "icon-alert-triangle-v2" + ], "colorPermutations": { "12552552551": [] } }, { "id": 112, - "paths": ["M512 256l-512 512h1024z"], + "paths": [ + "M512 256l-512 512h1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrow-up"], + "tags": [ + "icon-arrow-up" + ], "colorPermutations": { "12552552551": [] } }, { "id": 94, - "paths": ["M510 510l512 512h-1024z", "M510-2l512 512h-1024z"], + "paths": [ + "M510 510l512 512h-1024z", + "M510-2l512 512h-1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrow-double-up"], + "tags": [ + "icon-arrow-double-up" + ], "colorPermutations": { "12552552551": [] } }, { "id": 96, - "paths": ["M512 0l512 1024h-1024z"], + "paths": [ + "M512 0l512 1024h-1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrow-tall-up"], + "tags": [ + "icon-arrow-tall-up" + ], "colorPermutations": { "12552552551": [] } }, { "id": 111, - "paths": ["M768 512l-512-512v1024z"], + "paths": [ + "M768 512l-512-512v1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrow-right"], + "tags": [ + "icon-arrow-right" + ], "colorPermutations": { "12552552551": [] } }, { "id": 18, - "paths": ["M962 512l-896 512v-1024z"], + "paths": [ + "M962 512l-896 512v-1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrow-right-equilateral"], + "tags": [ + "icon-arrow-right-equilateral" + ], "colorPermutations": { "12552552551": [] } }, { "id": 113, - "paths": ["M512 768l512-512h-1024z"], + "paths": [ + "M512 768l512-512h-1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrow-down"], + "tags": [ + "icon-arrow-down" + ], "colorPermutations": { "12552552551": [] } }, { "id": 93, - "paths": ["M510 510l-512-512h1024z", "M510 1022l-512-512h1024z"], + "paths": [ + "M510 510l-512-512h1024z", + "M510 1022l-512-512h1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrow-double-down"], + "tags": [ + "icon-arrow-double-down" + ], "colorPermutations": { "12552552551": [] } }, { "id": 95, - "paths": ["M512 1024l-512-1024h1024z"], + "paths": [ + "M512 1024l-512-1024h1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrow-tall-down"], + "tags": [ + "icon-arrow-tall-down" + ], "colorPermutations": { "12552552551": [] } }, { "id": 114, - "paths": ["M256 512l512 512v-1024z"], + "paths": [ + "M256 512l512 512v-1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrow-left"], + "tags": [ + "icon-arrow-left" + ], "colorPermutations": { "12552552551": [] } @@ -1469,7 +1519,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-asterisk"], + "tags": [ + "icon-asterisk" + ], "colorPermutations": { "12552552551": [] } @@ -1482,7 +1534,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-bell"], + "tags": [ + "icon-bell" + ], "colorPermutations": { "12552552551": [] } @@ -1494,7 +1548,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-box-round-corners"], + "tags": [ + "icon-box-round-corners" + ], "colorPermutations": { "12552552551": [] } @@ -1507,17 +1563,23 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-box-with-arrow-cursor"], + "tags": [ + "icon-box-with-arrow-cursor" + ], "colorPermutations": { "12552552551": [] } }, { "id": 120, - "paths": ["M1024 0l-640 640-384-384v384l384 384 640-640z"], + "paths": [ + "M1024 0l-640 640-384-384v384l384 384 640-640z" + ], "attrs": [], "grid": 16, - "tags": ["icon-check"], + "tags": [ + "icon-check" + ], "colorPermutations": { "12552552551": [] } @@ -1531,7 +1593,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-connectivity"], + "tags": [ + "icon-connectivity" + ], "colorPermutations": { "12552552551": [] } @@ -1546,7 +1610,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-database-in-brackets"], + "tags": [ + "icon-database-in-brackets" + ], "colorPermutations": { "12552552551": [] } @@ -1559,7 +1625,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-eye-open-v2"], + "tags": [ + "icon-eye-open-v2" + ], "colorPermutations": { "12552552551": [] } @@ -1571,7 +1639,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-gear"], + "tags": [ + "icon-gear" + ], "colorPermutations": { "12552552551": [] } @@ -1584,7 +1654,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-hourglass"], + "tags": [ + "icon-hourglass" + ], "colorPermutations": { "12552552551": [] } @@ -1596,17 +1668,23 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-info"], + "tags": [ + "icon-info" + ], "colorPermutations": { "12552552551": [] } }, { "id": 75, - "paths": ["M1024 512l-512-512v307.2l-512 204.8v256h512v256z"], + "paths": [ + "M1024 512l-512-512v307.2l-512 204.8v256h512v256z" + ], "attrs": [], "grid": 16, - "tags": ["icon-link-v2"], + "tags": [ + "icon-link-v2" + ], "colorPermutations": { "12552552551": [] } @@ -1616,13 +1694,19 @@ "paths": [ "M702 384h-62v-128c0-141.385-114.615-256-256-256s-256 114.615-256 256v0 128h-64c-35.301 0.113-63.887 28.699-64 63.989v512.011c0.113 35.301 28.699 63.887 63.989 64h638.011c35.301-0.113 63.887-28.699 64-63.989v-512.011c-0.113-35.301-28.699-63.887-63.989-64h-0.011zM256 384v-128c0-70.692 57.308-128 128-128s128 57.308 128 128v0 128z" ], - "attrs": [{}], + "attrs": [ + {} + ], "grid": 16, - "tags": ["icon-lock"], + "tags": [ + "icon-lock" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] }, "width": 768 }, @@ -1633,7 +1717,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-minus"], + "tags": [ + "icon-minus" + ], "colorPermutations": { "12552552551": [] } @@ -1648,7 +1734,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-people"], + "tags": [ + "icon-people" + ], "colorPermutations": { "12552552551": [] } @@ -1661,7 +1749,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-person"], + "tags": [ + "icon-person" + ], "colorPermutations": { "12552552551": [] } @@ -1673,7 +1763,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-plus"], + "tags": [ + "icon-plus" + ], "colorPermutations": { "12552552551": [] } @@ -1683,13 +1775,19 @@ "paths": [ "M830 0h-636c-106.6 0-194 87.2-194 194v636c0 106.8 87.4 194 194 194h636c106.6 0 194-87.2 194-194v-636c0-106.8-87.4-194-194-194zM896 608c0 17.673-14.327 32-32 32v0h-224v224c0 17.673-14.327 32-32 32v0h-192c-17.673 0-32-14.327-32-32v0-224h-224c-17.673 0-32-14.327-32-32v0-192c0-17.673 14.327-32 32-32v0h224v-224c0-17.673 14.327-32 32-32v0h192c17.673 0 32 14.327 32 32v0 224h224c17.673 0 32 14.327 32 32v0z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-plus-in-rect"], + "tags": [ + "icon-plus-in-rect" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -1699,7 +1797,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-trash"], + "tags": [ + "icon-trash" + ], "colorPermutations": { "12552552551": [] } @@ -1711,7 +1811,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-x-heavy"], + "tags": [ + "icon-x-heavy" + ], "colorPermutations": { "12552552551": [] } @@ -1724,7 +1826,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-brackets"], + "tags": [ + "icon-brackets" + ], "colorPermutations": { "12552552551": [] } @@ -1739,7 +1843,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-crosshair"], + "tags": [ + "icon-crosshair" + ], "colorPermutations": { "12552552551": [] } @@ -1763,7 +1869,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-grippy-v2"], + "tags": [ + "icon-grippy-v2" + ], "colorPermutations": { "12552552551": [] } @@ -1778,7 +1886,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-grid-v2"], + "tags": [ + "icon-grid-v2" + ], "colorPermutations": { "12552552551": [] } @@ -1790,13 +1900,23 @@ "M448 0h128v1024h-128v-1024z", "M192 0h128v1024h-128v-1024z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-grippy-ew"], + "tags": [ + "icon-grippy-ew" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -1806,13 +1926,23 @@ "M384 0h256v1024h-256v-1024z", "M768 0h256v1024h-256v-1024z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-columns"], + "tags": [ + "icon-columns" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -1822,13 +1952,23 @@ "M0 384h1024v256h-1024v-256z", "M0 768h1024v256h-1024v-256z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-rows"], + "tags": [ + "icon-rows" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -1836,13 +1976,19 @@ "paths": [ "M896 0h-768c-70.601 0.227-127.773 57.399-128 127.978l-0 0.022v768c0.227 70.601 57.399 127.773 127.978 128l0.022 0h256v-512l-192-192h640l-192 192v512h256c70.601-0.227 127.773-57.399 128-127.978l0-0.022v-768c-0.227-70.601-57.399-127.773-127.978-128l-0.022-0z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-filter"], + "tags": [ + "icon-filter" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -1850,13 +1996,19 @@ "paths": [ "M896 0h-768c-70.601 0.227-127.773 57.399-128 127.978l-0 0.022v768c0.227 70.601 57.399 127.773 127.978 128l0.022 0h768c70.601-0.227 127.773-57.399 128-127.978l0-0.022v-768c-0.227-70.601-57.399-127.773-127.978-128l-0.022-0zM896 895.8h-256v-383.8l192-192h-640l192 192v384h-256v-767.8h768z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-filter-outline"], + "tags": [ + "icon-filter-outline" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -1866,13 +2018,23 @@ "M0 320v640c0.102 35.305 28.695 63.898 63.99 64l0.010 0h64v-768h-64c-35.305 0.102-63.898 28.695-64 63.99l-0 0.010z", "M960 256h-64v768h64c35.305-0.102 63.898-28.695 64-63.99l0-0.010v-640c-0.102-35.305-28.695-63.898-63.99-64l-0.010-0z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-suitcase"], + "tags": [ + "icon-suitcase" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -1880,14 +2042,20 @@ "paths": [ "M704 320h-64v-64c0-141.385-114.615-256-256-256s-256 114.615-256 256v0 64h-64c-35.301 0.113-63.887 28.699-64 63.989l-0 0.011v576c0.113 35.301 28.699 63.887 63.989 64l0.011 0h640c35.301-0.113 63.887-28.699 64-63.989l0-0.011v-576c-0.113-35.301-28.699-63.887-63.989-64l-0.011-0zM256 256c0-70.692 57.308-128 128-128s128 57.308 128 128v0 64h-256zM533.4 896l-128-128-43 85-170.4-383.6 383.6 170.2-85 43 128 128z" ], - "attrs": [{}], + "attrs": [ + {} + ], "width": 768, "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-cursor-locked"], + "tags": [ + "icon-cursor-locked" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -1895,13 +2063,19 @@ "paths": [ "M192 640h832l-192-320 192-320h-896c-70.606 0.215-127.785 57.394-128 127.979l-0 0.021v896h192z" ], - "attrs": [{}], + "attrs": [ + {} + ], "grid": 16, - "tags": ["icon-flag"], + "tags": [ + "icon-flag" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -1911,13 +2085,23 @@ "M814.76 415.080q7.52 10 14.44 20.52c14.737 21.984 27.741 47.184 37.759 73.847l0.841 2.553c-10.859 29.216-23.863 54.416-39.447 77.748l0.847-1.348c-23.221 34.963-50.705 64.8-82.207 89.793l-0.793 0.607c-57.762 45.834-130.437 75.216-209.743 80.049l-1.057 0.051-114.46 140.86c27.346 4.988 58.817 7.84 90.955 7.84 0.037 0 0.074-0 0.111-0l-0.005 0c245.8 0 452.2-168 510.8-395.6-21.856-82.93-60.906-154.847-113.325-214.773l0.525 0.613z", "M832 0l-832 1024h192l832-1024h-192z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-eye-disabled"], + "tags": [ + "icon-eye-disabled" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -1925,13 +2109,19 @@ "paths": [ "M830 62h-830l-4 702c0 106.6 87.4 194 194 194h640c106.6 0 194-87.4 194-194v-508c0-106.8-87.4-194-194-194zM832 446l-384 384-192-192v-256l192 192 384-384v256z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-notebook-page"], + "tags": [ + "icon-notebook-page" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -1939,13 +2129,19 @@ "paths": [ "M768 0c-141.339 0.114-255.886 114.661-256 255.989l-0 0.011v128h-448c-35.301 0.113-63.887 28.699-64 63.989l-0 0.011v512c0.113 35.301 28.699 63.887 63.989 64l0.011 0h638c35.301-0.113 63.887-28.699 64-63.989l0-0.011v-512c-0.113-35.301-28.699-63.887-63.989-64l-0.011-0h-62v-128c0-70.692 57.308-128 128-128s128 57.308 128 128v0 128h128v-128c-0.114-141.339-114.661-255.886-255.989-256l-0.011-0z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-unlocked"], + "tags": [ + "icon-unlocked" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -1953,13 +2149,19 @@ "paths": [ "M1024 512c0 282.77-229.23 512-512 512s-512-229.23-512-512c0-282.77 229.23-512 512-512s512 229.23 512 512z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-circle"], + "tags": [ + "icon-circle" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -1968,13 +2170,21 @@ "M876.34 635.58l-49.9 49.88-19.26 19.5-26 8.7-423.040 144.2 144.2-423.28 8.84-25.78 150-149.88-85.6-149.78c-34.92-61.12-92-61.12-127 0l-422.78 739.72c-34.94 61.14-5.92 111.14 64.48 111.14h843.44c70.4 0 99.42-50 64.48-111.14z", "M973.18 242.84c-19.32-19.3-40.66-34.62-60.16-43.16-34.42-15.12-52.38-4.54-60.1 3.16l-258.12 258.12-82.8 243.040 243-82.8 3.36-3.4 254.76-254.76c4.94-4.94 10.88-13.88 10.88-28.3 0-25.34-19.5-60.56-50.82-91.9zM631 619.82l-34.88-34.86 34.64-101.6 9.24-3.36h32v64h64v32l-3.42 9.26z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "grid": 16, - "tags": ["icon-draft"], + "tags": [ + "icon-draft" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -1982,13 +2192,19 @@ "paths": [ "M512 0c-282.78 0-512 229.22-512 512s229.22 512 512 512 512-229.22 512-512-229.22-512-512-512zM263.1 263.1c66.48-66.48 154.88-103.1 248.9-103.1 66.74 0 130.64 18.48 185.9 52.96l-484.94 484.94c-34.5-55.24-52.96-119.16-52.96-185.9 0-94.020 36.62-182.42 103.1-248.9zM760.9 760.9c-66.48 66.48-154.88 103.1-248.9 103.1-66.74 0-130.64-18.48-185.9-52.96l484.94-484.94c34.5 55.24 52.96 119.16 52.96 185.9 0 94.020-36.62 182.42-103.1 248.9z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-circle-slash"], + "tags": [ + "icon-circle-slash" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -1996,14 +2212,20 @@ "paths": [ "M136.86 52.26c54.080-34.82 120.58-52.26 199.44-52.26 103.6 0 189.7 24.76 258.24 74.28s102.82 122.88 102.82 220.060c0 59.6-14.86 109.8-44.58 150.6-17.38 24.76-50.76 56.4-100.14 94.9l-48.68 37.82c-26.54 20.64-44.14 44.7-52.82 72.2-5.5 17.44-8.46 44.48-8.92 81.14h-186.4c2.74-77.48 10.060-131 21.94-160.58s42.5-63.62 91.88-102.12l50.060-39.2c16.46-12.38 29.72-25.9 39.78-40.58 18.28-25.2 27.42-52.96 27.42-83.22 0-34.84-10.18-66.6-30.52-95.24-20.36-28.64-57.52-42.98-111.48-42.98s-90.68 17.66-112.88 52.96c-22.18 35.32-33.26 71.98-33.26 110.040h-198.76c5.5-130.64 51.12-223.24 136.86-277.82zM251.020 825.24h205.62v198.74h-205.62v-198.74z" ], - "attrs": [{}], + "attrs": [ + {} + ], "width": 697, "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-question-mark"], + "tags": [ + "icon-question-mark" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -2011,13 +2233,19 @@ "paths": [ "M512 0c-282.76 0-512 214.9-512 480 0 92.26 27.8 178.44 75.92 251.6l-75.92 292.4 313.5-101.42c61.040 24.1 128.12 37.42 198.5 37.42 282.76 0 512-214.9 512-480s-229.24-480-512-480zM768 448l-320 320-192-192v-192l192 192 320-320v192z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-status-poll-check"], + "tags": [ + "icon-status-poll-check" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -2027,13 +2255,23 @@ "M457.14 417.86l24.2 122.64h61.32l24.2-122.64v-163.5h-109.72v163.5z", "M471.12 581.36h81.76v81.76h-81.76v-81.76z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-status-poll-caution"], + "tags": [ + "icon-status-poll-caution" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -2043,13 +2281,23 @@ "M512 256c-59.84 0-116.080 23.3-158.4 65.6-42.3 42.3-65.6 98.56-65.6 158.4 0 43.5 12.32 85.080 35.3 120.82l309.52-309.52c-35.72-22.98-77.32-35.3-120.82-35.3z", "M512 0c-282.76 0-512 214.9-512 480 0 92.26 27.8 178.44 75.92 251.6l-75.92 292.4 313.5-101.42c61.040 24.1 128.12 37.42 198.5 37.42 282.76 0 512-214.9 512-480s-229.24-480-512-480zM512 800c-176.74 0-320-143.26-320-320s143.26-320 320-320 320 143.26 320 320-143.26 320-320 320z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-status-poll-circle-slash"], + "tags": [ + "icon-status-poll-circle-slash" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -2057,13 +2305,19 @@ "paths": [ "M512 0c-282.76 0-512 214.9-512 480 0 92.26 27.8 178.44 75.92 251.6l-75.92 292.4 313.5-101.42c61.040 24.1 128.12 37.42 198.5 37.42 282.76 0 512-214.9 512-480s-229.24-480-512-480zM579.020 832h-141.36v-136.64h141.36v136.64zM713.84 433.9c-11.94 17.020-34.9 38.78-68.84 65.24l-33.48 26c-18.24 14.18-30.34 30.74-36.32 49.64-3.78 11.98-5.82 30.58-6.14 55.8h-128.12c1.88-53.26 6.92-90.060 15.080-110.4 8.18-20.34 29.22-43.74 63.16-70.22l34.42-26.94c11.3-8.52 20.42-17.8 27.34-27.9 12.56-17.34 18.86-36.4 18.86-57.2 0-23.94-7-45.78-20.98-65.48-14-19.7-39.54-29.54-76.64-29.54s-62.34 12.14-77.6 36.4c-15.24 24.28-22.88 49.48-22.88 75.64h-136.64c3.78-89.84 35.14-153.5 94.080-191.020 37.18-23.94 82.9-35.94 137.12-35.94 71.22 0 130.42 17.020 177.54 51.060s70.68 84.48 70.68 151.3c0 40.98-10.22 75.5-30.66 103.54z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-status-poll-question-mark"], + "tags": [ + "icon-status-poll-question-mark" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -2072,13 +2326,21 @@ "M1000.080 334.64l-336.6 336.76-20.52 6.88-450.96 153.72 160.68-471.52 332.34-332.34c-54.040-18.2-112.28-28.14-173.020-28.14-282.76 0-512 214.9-512 480 0 92.26 27.8 178.44 75.92 251.6l-75.92 292.4 313.5-101.42c61.040 24.1 128.12 37.42 198.5 37.42 282.76 0 512-214.9 512-480 0-50.68-8.4-99.5-23.92-145.36z", "M408.42 395.24l-2.16 6.3-111.7 327.9 334.12-113.86 4.62-4.68 350.28-350.28c6.8-6.78 14.96-19.1 14.96-38.9 0-34.86-26.82-83.28-69.88-126.38-26.54-26.54-55.9-47.6-82.7-59.34-47.34-20.8-72.020-6.24-82.64 4.36l-354.9 354.88zM470.56 421.42h44v88h88v44l-4.7 12.72-139.68 47.54-47.94-47.94 47.6-139.72 12.72-4.6z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-status-poll-edit"], + "tags": [ + "icon-status-poll-edit" + ], "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -2086,31 +2348,47 @@ "paths": [ "M832 0h-640c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h640c105.6 0 192-86.4 192-192v-640c0-105.6-86.4-192-192-192zM681.38 365.14c0.68-20.46-2.22-37.7-8.7-51.68-6.5-13.98-15.7-25.4-27.64-34.28-11.94-8.86-26.1-15.18-42.48-18.94-16.38-3.74-33.78-5.62-52.2-5.62-15.020 0-30.2 1.54-45.54 4.6s-29.16 8.18-41.44 15.36-22.18 16.56-29.68 28.14c-7.52 11.62-11.26 25.94-11.26 42.98s6.66 32.6 19.96 44.52c13.3 11.94 29.34 21.84 48.1 29.68 18.76 7.86 38.020 14 57.82 18.42 19.78 4.44 35.82 8.020 48.1 10.74 28.66 7.52 54.92 16.22 78.8 26.1 23.88 9.9 44.52 22.68 61.92 38.38s30.86 34.8 40.42 57.32c9.54 22.52 14.32 50.16 14.32 82.9 0 43.68-9.040 80.86-27.12 111.56s-41.28 55.62-69.6 74.7c-28.32 19.1-60.22 32.92-95.7 41.44s-70.62 12.8-105.42 12.8c-102.34 0-178.6-20.8-228.74-62.44-50.16-41.6-75.22-107.1-75.22-196.5h152.5c-1.38 25.94 1.7 47.58 9.22 64.98 7.5 17.4 18.42 31.22 32.74 41.44 14.32 10.24 31.38 17.58 51.18 22 19.78 4.44 41.28 6.66 64.48 6.66 16.38 0 32.74-2.040 49.12-6.14s31.22-10.24 44.52-18.42c13.3-8.18 24.22-18.76 32.76-31.72 8.52-12.94 12.8-28.66 12.8-47.080s-5.46-32.24-16.38-43.5c-10.92-11.26-25.080-20.98-42.48-29.16s-37.2-15.36-59.36-21.5c-22.18-6.14-44.52-12.62-67.040-19.44-23.2-6.82-45.72-15-67.54-24.56-21.84-9.54-41.44-21.82-58.84-36.84-17.4-15-31.38-33.42-41.96-55.26-10.58-21.82-15.86-48.44-15.86-79.82 0-40.94 8.52-75.74 25.58-104.4 17.040-28.66 39.22-52.020 66.52-70.1 27.28-18.080 58.16-31.38 92.62-39.92 34.44-8.52 69.42-12.8 104.9-12.8 37.52 0 72.82 4.26 105.92 12.8 33.080 8.54 62.080 22.36 87 41.44 24.9 19.1 44.68 43.5 59.36 73.18 14.66 29.68 22 65.68 22 107.98h-152.5z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-stale"], + "tags": [ + "icon-stale" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { "id": 105, - "paths": ["M1024 512l-448 512v-1024z", "M448 0l-448 512 448 512z"], + "paths": [ + "M1024 512l-448 512v-1024z", + "M448 0l-448 512 448 512z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrows-right-left"], + "tags": [ + "icon-arrows-right-left" + ], "colorPermutations": { "12552552551": [] } }, { "id": 106, - "paths": ["M512 0l512 448h-1024z", "M0 576l512 448 512-448z"], + "paths": [ + "M512 0l512 448h-1024z", + "M0 576l512 448 512-448z" + ], "attrs": [], "grid": 16, - "tags": ["icon-arrows-up-down"], + "tags": [ + "icon-arrows-up-down" + ], "colorPermutations": { "12552552551": [] } @@ -2122,7 +2400,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-bullet"], + "tags": [ + "icon-bullet" + ], "colorPermutations": { "12552552551": [] } @@ -2134,7 +2414,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-calendar"], + "tags": [ + "icon-calendar" + ], "colorPermutations": { "12552552551": [] } @@ -2146,7 +2428,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-chain-links"], + "tags": [ + "icon-chain-links" + ], "colorPermutations": { "12552552551": [] } @@ -2159,7 +2443,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-download"], + "tags": [ + "icon-download" + ], "colorPermutations": { "12552552551": [] } @@ -2172,7 +2458,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-duplicate"], + "tags": [ + "icon-duplicate" + ], "colorPermutations": { "12552552551": [] } @@ -2185,7 +2473,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-folder-new-v2.5"], + "tags": [ + "icon-folder-new-v2.5" + ], "colorPermutations": { "12552552551": [] } @@ -2200,7 +2490,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-fullscreen-collapse"], + "tags": [ + "icon-fullscreen-collapse" + ], "colorPermutations": { "12552552551": [] } @@ -2215,7 +2507,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-fullscreen-expand"], + "tags": [ + "icon-fullscreen-expand" + ], "colorPermutations": { "12552552551": [] } @@ -2228,7 +2522,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-layers"], + "tags": [ + "icon-layers" + ], "colorPermutations": { "12552552551": [] } @@ -2240,7 +2536,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-line-horz"], + "tags": [ + "icon-line-horz" + ], "colorPermutations": { "12552552551": [] } @@ -2252,7 +2550,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-magnify-v2"], + "tags": [ + "icon-magnify-v2" + ], "colorPermutations": { "12552552551": [] } @@ -2266,7 +2566,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-magnify-in-v2"], + "tags": [ + "icon-magnify-in-v2" + ], "colorPermutations": { "12552552551": [] } @@ -2279,7 +2581,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-magnify-out-v2"], + "tags": [ + "icon-magnify-out-v2" + ], "colorPermutations": { "12552552551": [] } @@ -2293,7 +2597,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-menu-v2.2"], + "tags": [ + "icon-menu-v2.2" + ], "colorPermutations": { "12552552551": [] } @@ -2306,7 +2612,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-move"], + "tags": [ + "icon-move" + ], "colorPermutations": { "12552552551": [] } @@ -2319,7 +2627,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-new-window"], + "tags": [ + "icon-new-window" + ], "colorPermutations": { "12552552551": [] } @@ -2333,7 +2643,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-paint-bucket-v2"], + "tags": [ + "icon-paint-bucket-v2" + ], "colorPermutations": { "12552552551": [] } @@ -2345,7 +2657,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-pencil"], + "tags": [ + "icon-pencil" + ], "colorPermutations": { "12552552551": [] } @@ -2359,27 +2673,38 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-pencil-edit-in-place"], + "tags": [ + "icon-pencil-edit-in-place" + ], "colorPermutations": { "12552552551": [] } }, { "id": 90, - "paths": ["M1024 512l-1024 512v-1024z"], + "paths": [ + "M1024 512l-1024 512v-1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-play"], + "tags": [ + "icon-play" + ], "colorPermutations": { "12552552551": [] } }, { "id": 88, - "paths": ["M126-2h256v1024h-256v-1024z", "M638-2h256v1024h-256v-1024z"], + "paths": [ + "M126-2h256v1024h-256v-1024z", + "M638-2h256v1024h-256v-1024z" + ], "attrs": [], "grid": 16, - "tags": ["icon-pause"], + "tags": [ + "icon-pause" + ], "colorPermutations": { "12552552551": [] } @@ -2392,27 +2717,37 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-plot-resource"], + "tags": [ + "icon-plot-resource" + ], "colorPermutations": { "12552552551": [] } }, { "id": 80, - "paths": ["M766 1024l-256-512 256-512h-256l-256 512 256 512z"], + "paths": [ + "M766 1024l-256-512 256-512h-256l-256 512 256 512z" + ], "attrs": [], "grid": 16, - "tags": ["icon-pointer-left"], + "tags": [ + "icon-pointer-left" + ], "colorPermutations": { "12552552551": [] } }, { "id": 81, - "paths": ["M254 0l256 512-256 512h256l256-512-256-512z"], + "paths": [ + "M254 0l256 512-256 512h256l256-512-256-512z" + ], "attrs": [], "grid": 16, - "tags": ["icon-pointer-right"], + "tags": [ + "icon-pointer-right" + ], "colorPermutations": { "12552552551": [] } @@ -2424,7 +2759,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-refresh-v1.5"], + "tags": [ + "icon-refresh-v1.5" + ], "colorPermutations": { "12552552551": [] } @@ -2437,7 +2774,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-save-v2"], + "tags": [ + "icon-save-v2" + ], "colorPermutations": { "12552552551": [] } @@ -2451,7 +2790,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-save-as"], + "tags": [ + "icon-save-as" + ], "colorPermutations": { "12552552551": [] } @@ -2463,7 +2804,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-sine"], + "tags": [ + "icon-sine" + ], "colorPermutations": { "12552552551": [] } @@ -2475,7 +2818,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-font"], + "tags": [ + "icon-font" + ], "colorPermutations": { "12552552551": [] } @@ -2490,7 +2835,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-thumbs-strip"], + "tags": [ + "icon-thumbs-strip" + ], "colorPermutations": { "12552552551": [] } @@ -2502,7 +2849,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-two-parts-both"], + "tags": [ + "icon-two-parts-both" + ], "colorPermutations": { "12552552551": [] } @@ -2514,7 +2863,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-two-parts-one-only"], + "tags": [ + "icon-two-parts-one-only" + ], "colorPermutations": { "12552552551": [] } @@ -2527,7 +2878,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-resync"], + "tags": [ + "icon-resync" + ], "colorPermutations": { "12552552551": [] } @@ -2539,7 +2892,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-reset"], + "tags": [ + "icon-reset" + ], "colorPermutations": { "12552552551": [] } @@ -2551,7 +2906,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-x-in-circle"], + "tags": [ + "icon-x-in-circle" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { @@ -2573,7 +2930,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-brightness"], + "tags": [ + "icon-brightness" + ], "colorPermutations": { "12552552551": [] } @@ -2585,7 +2944,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-contrast"], + "tags": [ + "icon-contrast" + ], "colorPermutations": { "12552552551": [] } @@ -2600,7 +2961,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-expand"], + "tags": [ + "icon-expand" + ], "colorPermutations": { "12552552551": [] } @@ -2615,7 +2978,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-list-view"], + "tags": [ + "icon-list-view" + ], "colorPermutations": { "12552552551": [] } @@ -2632,7 +2997,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-grid-snap-to"], + "tags": [ + "icon-grid-snap-to" + ], "colorPermutations": { "12552552551": [] } @@ -2650,7 +3017,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-grid-snap-no"], + "tags": [ + "icon-grid-snap-no" + ], "colorPermutations": { "12552552551": [] } @@ -2663,7 +3032,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-frame-show"], + "tags": [ + "icon-frame-show" + ], "colorPermutations": { "12552552551": [] } @@ -2678,7 +3049,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-frame-hide"], + "tags": [ + "icon-frame-hide" + ], "colorPermutations": { "12552552551": [] } @@ -2691,7 +3064,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-import"], + "tags": [ + "icon-import" + ], "colorPermutations": { "12552552551": [] } @@ -2704,7 +3079,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-export"], + "tags": [ + "icon-export" + ], "colorPermutations": { "12552552551": [] } @@ -2715,14 +3092,22 @@ "M1226.4 320h-176l-76.22 203.24 77 205.34 87.22-232.58 90.74 242h-174.44l49.5 132h174.44l57.76 154h154l-264-704z", "M384 0l-384 1024h224l84-224h408l84 224h224l-384-1024zM380 608l132-352 132 352z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "grid": 16, - "tags": ["icon-font-size-alt1"], + "tags": [ + "icon-font-size-alt1" + ], "width": 1504, "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -2731,13 +3116,21 @@ "M632 312l-120 120-120-120-80 80 120 120-120 120 80 80 120-120 120 120 80-80-120-120 120-120-80-80z", "M512 0c-282.76 0-512 86-512 192v640c0 106 229.24 192 512 192s512-86 512-192v-640c0-106-229.24-192-512-192zM512 832c-176.731 0-320-143.269-320-320s143.269-320 320-320c176.731 0 320 143.269 320 320v0c0 176.731-143.269 320-320 320v0z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-clear-data"], + "tags": [ + "icon-clear-data" + ], "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -2746,13 +3139,21 @@ "M576 64c-247.4 0-448 200.6-448 448h-128l192 192 192-192h-128c0-85.4 33.2-165.8 93.8-226.2 60.4-60.6 140.8-93.8 226.2-93.8s165.8 33.2 226.2 93.8c60.6 60.4 93.8 140.8 93.8 226.2s-33.2 165.8-93.8 226.2c-60.4 60.6-140.8 93.8-226.2 93.8s-165.8-33.2-226.2-93.8l-90.6 90.6c81 81 193 131.2 316.8 131.2 247.4 0 448-200.6 448-448s-200.6-448-448-448z", "M576 272c-26.6 0-48 21.4-48 48v211.8l142 142c9.4 9.4 21.6 14 34 14s24.6-4.6 34-14c18.8-18.8 18.8-49.2 0-67.8l-114-114v-172c0-26.6-21.4-48-48-48z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-history"], + "tags": [ + "icon-history" + ], "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -2760,14 +3161,20 @@ "paths": [ "M643.427 825.261c-81.955-0.697-148.179-67.065-148.642-149.010l-0-0.044v-395.828l296.871 247.393v-197.914l-395.828-329.857-395.828 328.62v197.502l296.871-246.156v396.241c0 190.905 155.239 346.556 346.144 346.968l412.321 0.825 0.412-197.914z" ], - "attrs": [{}], + "attrs": [ + {} + ], "width": 1056, "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-arrow-up-to-parent"], + "tags": [ + "icon-arrow-up-to-parent" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -2775,13 +3182,19 @@ "paths": [ "M512 0c-282.8 0-512 229.2-512 512s229.2 512 512 512 512-229.2 512-512-229.2-512-512-512zM783.6 783.6c-54.634 54.8-125.77 93.12-205.322 106.874l-2.278 0.326v-250.8h-128v250.8c-161.302-28.062-286.738-153.497-314.468-312.5l-0.332-2.3h250.8v-128h-250.8c28.062-161.302 153.497-286.738 312.5-314.468l2.3-0.332v250.8h128v-250.8c161.302 28.062 286.738 153.497 314.468 312.5l0.332 2.3h-250.8v128h250.8c-14.080 81.83-52.4 152.966-107.191 207.591l-0.009 0.009z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-crosshair-in-circle"], + "tags": [ + "icon-crosshair-in-circle" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -2790,13 +3203,21 @@ "M512 384c70.692 0 128 57.308 128 128s-57.308 128-128 128c-70.692 0-128-57.308-128-128v0c0.114-70.647 57.353-127.886 127.989-128l0.011-0zM512 256c-141.385 0-256 114.615-256 256s114.615 256 256 256c141.385 0 256-114.615 256-256v0c-0.114-141.339-114.661-255.886-255.989-256l-0.011-0z", "M512 128c211.87 0.128 383.575 171.912 383.575 383.8 0 211.967-171.833 383.8-383.8 383.8s-383.8-171.833-383.8-383.8c0-105.99 42.963-201.945 112.425-271.4l-0 0c69.21-69.437 164.944-112.401 270.713-112.401 0.312 0 0.624 0 0.936 0.001l-0.048-0zM512 0c-282.8 0-512 229.2-512 512s229.2 512 512 512 512-229.2 512-512-229.2-512-512-512z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-target"], + "tags": [ + "icon-target" + ], "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -2805,13 +3226,21 @@ "M45.2 658.8h229.6l-274.8 274.6 90.6 90.6 274.6-274.8v229.6h128v-448h-448v128z", "M1024 90.6l-90.6-90.6-274.6 274.8v-229.6h-128v448h448v-128h-229.6l274.8-274.6z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-items-collapse"], + "tags": [ + "icon-items-collapse" + ], "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -2820,13 +3249,21 @@ "M448 896h-229.4l274.6-274.8-90.4-90.4-274.8 274.6v-229.4h-128v448h448v-128z", "M530.8 402.8l90.4 90.4 274.8-274.6v229.4h128v-448h-448v128h229.4l-274.6 274.8z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-items-expand"], + "tags": [ + "icon-items-expand" + ], "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -2836,13 +3273,23 @@ "M640 512c0 70.692-57.308 128-128 128s-128-57.308-128-128c0-70.692 57.308-128 128-128s128 57.308 128 128z", "M1024 512c0 70.692-57.308 128-128 128s-128-57.308-128-128c0-70.692 57.308-128 128-128s128 57.308 128 128z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-3-dots"], + "tags": [ + "icon-3-dots" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -2850,13 +3297,19 @@ "paths": [ "M1024 384v-128h-256v-256h-128v256h-256v-256h-128v256h-256v128h256v256h-256v128h256v256h128v-256h256v256h128v-256h256v-128h-256v-256zM640 640h-256v-256h256z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-grid-on"], + "tags": [ + "icon-grid-on" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -2868,13 +3321,27 @@ "M840 384h184v-128h-80l-104 128z", "M832 0l-832 1024h192l832-1024h-192z" ], - "attrs": [{}, {}, {}, {}, {}], + "attrs": [ + {}, + {}, + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-grid-off"], + "tags": [ + "icon-grid-off" + ], "colorPermutations": { - "12552552551": [{}, {}, {}, {}, {}] + "12552552551": [ + {}, + {}, + {}, + {}, + {} + ] } }, { @@ -2882,13 +3349,19 @@ "paths": [ "M896 256h-128l-128-256h-256l-128 256h-128c-70.601 0.227-127.773 57.399-128 127.978l-0 0.022v512c0.227 70.601 57.399 127.773 127.978 128l0.022 0h768c70.601-0.227 127.773-57.399 128-127.978l0-0.022v-512c-0.227-70.601-57.399-127.773-127.978-128l-0.022-0zM512 864c-141.385 0-256-114.615-256-256s114.615-256 256-256c141.385 0 256 114.615 256 256v0c0 141.385-114.615 256-256 256v0z" ], - "attrs": [{}], + "attrs": [ + {} + ], "grid": 16, - "tags": ["icon-camera"], + "tags": [ + "icon-camera" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -2897,13 +3370,21 @@ "M896 320v448c-0.215 70.606-57.394 127.785-127.979 128l-0.021 0h-576c0.215 70.606 57.394 127.785 127.979 128l0.021 0h576c70.606-0.215 127.785-57.394 128-127.979l0-0.021v-448c-0.215-70.606-57.394-127.785-127.979-128l-0.021-0z", "M832 704v-448c-0.215-70.606-57.394-127.785-127.979-128l-0.021-0h-192l-101.5-82.74c-24.88-24.9-74.040-45.26-109.24-45.26h-237.26c-35.305 0.102-63.898 28.695-64 63.99l-0 0.010v640c0.215 70.606 57.394 127.785 127.979 128l0.021 0h576c70.606-0.215 127.785-57.394 128-127.979l0-0.021zM128 644v-516l256 260z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "grid": 16, - "tags": ["icon-folders-collapse"], + "tags": [ + "icon-folders-collapse" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -2913,7 +3394,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-activity"], + "tags": [ + "icon-activity" + ], "colorPermutations": { "12552552551": [] } @@ -2925,7 +3408,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-activity-mode"], + "tags": [ + "icon-activity-mode" + ], "colorPermutations": { "12552552551": [] } @@ -2939,7 +3424,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-autoflow-tabular"], + "tags": [ + "icon-autoflow-tabular" + ], "colorPermutations": { "12552552551": [] } @@ -2951,7 +3438,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-clock-v1.5"], + "tags": [ + "icon-clock-v1.5" + ], "colorPermutations": { "12552552551": [] } @@ -2964,7 +3453,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-database"], + "tags": [ + "icon-database" + ], "colorPermutations": { "12552552551": [] } @@ -2977,7 +3468,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-database-query"], + "tags": [ + "icon-database-query" + ], "colorPermutations": { "12552552551": [] } @@ -2990,7 +3483,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-dataset"], + "tags": [ + "icon-dataset" + ], "colorPermutations": { "12552552551": [] } @@ -3003,7 +3498,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-datatable"], + "tags": [ + "icon-datatable" + ], "colorPermutations": { "12552552551": [] } @@ -3015,7 +3512,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-dictionary"], + "tags": [ + "icon-dictionary" + ], "colorPermutations": { "12552552551": [] } @@ -3028,7 +3527,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-folder-v2.5"], + "tags": [ + "icon-folder-v2.5" + ], "colorPermutations": { "12552552551": [] } @@ -3041,7 +3542,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-image"], + "tags": [ + "icon-image" + ], "colorPermutations": { "12552552551": [] } @@ -3055,7 +3558,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-layout"], + "tags": [ + "icon-layout" + ], "colorPermutations": { "12552552551": [] } @@ -3067,7 +3572,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-object"], + "tags": [ + "icon-object" + ], "colorPermutations": { "12552552551": [] } @@ -3077,13 +3584,19 @@ "paths": [ "M511.98 0l-511.98 320v384l512 320 512-320v-384l-512.020-320zM586.22 896h-141.36v-136.64h141.36v136.64zM721.040 497.9c-11.94 17.020-34.9 38.78-68.84 65.24l-33.48 26c-18.24 14.18-30.34 30.74-36.32 49.64-3.78 11.98-5.82 30.58-6.14 55.8h-128.12c1.88-53.26 6.92-90.060 15.080-110.4 8.18-20.34 29.22-43.74 63.16-70.22l34.42-26.94c11.3-8.52 20.42-17.8 27.34-27.9 12.56-17.34 18.86-36.4 18.86-57.2 0-23.94-7-45.78-20.98-65.48-14-19.7-39.54-29.54-76.64-29.54s-62.34 12.14-77.6 36.4c-15.24 24.28-22.88 49.48-22.88 75.64h-136.64c3.78-89.84 35.14-153.5 94.080-191.020 37.18-23.94 82.9-35.94 137.12-35.94 71.22 0 130.42 17.020 177.54 51.060s70.68 84.48 70.68 151.3c0 40.98-10.22 75.5-30.66 103.54z" ], - "attrs": [{}], + "attrs": [ + {} + ], "grid": 16, - "tags": ["icon-object-unknown"], + "tags": [ + "icon-object-unknown" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -3093,7 +3606,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-packet"], + "tags": [ + "icon-packet" + ], "colorPermutations": { "12552552551": [] } @@ -3106,7 +3621,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-page"], + "tags": [ + "icon-page" + ], "colorPermutations": { "12552552551": [] } @@ -3119,7 +3636,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-plot-overlay"], + "tags": [ + "icon-plot-overlay" + ], "colorPermutations": { "12552552551": [] } @@ -3133,7 +3652,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-plot-stacked"], + "tags": [ + "icon-plot-stacked" + ], "colorPermutations": { "12552552551": [] } @@ -3148,7 +3669,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-session-v2.5"], + "tags": [ + "icon-session-v2.5" + ], "colorPermutations": { "12552552551": [] } @@ -3160,7 +3683,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-tabular"], + "tags": [ + "icon-tabular" + ], "colorPermutations": { "12552552551": [] } @@ -3173,7 +3698,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-tabular-lad"], + "tags": [ + "icon-tabular-lad" + ], "colorPermutations": { "12552552551": [] } @@ -3187,7 +3714,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-tabular-lad-set"], + "tags": [ + "icon-tabular-lad-set" + ], "colorPermutations": { "12552552551": [] } @@ -3199,7 +3728,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-tabular-realtime-v2"], + "tags": [ + "icon-tabular-realtime-v2" + ], "colorPermutations": { "12552552551": [] } @@ -3209,13 +3740,19 @@ "paths": [ "M896 0h-768c-70.606 0.215-127.785 57.394-128 127.979l-0 0.021v768c0.215 70.606 57.394 127.785 127.979 128l0.021 0h768c70.606-0.215 127.785-57.394 128-127.979l0-0.021v-768c-0.215-70.606-57.394-127.785-127.979-128l-0.021-0zM768 256v192h-192v-192zM576 512h192v192h-192zM512 704h-192v-192h192zM512 256v192h-192v-192zM64 256h192v192h-192zM64 512h192v192h-192zM128 960c-35.255-0.225-63.775-28.745-64-63.978l-0-0.022v-128h192v192zM320 960v-192h192v192zM704 960h-128v-192h192v192zM941.14 941.14c-11.511 11.644-27.483 18.856-45.139 18.86l-64.001 0v-64h128c-0.004 17.657-7.216 33.629-18.854 45.134l-0.006 0.006zM960 768h-128v-512h128z" ], - "attrs": [{}], + "attrs": [ + {} + ], "grid": 16, - "tags": ["icon-tabular-scrolling"], + "tags": [ + "icon-tabular-scrolling" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -3226,7 +3763,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-telemetry-v2"], + "tags": [ + "icon-telemetry-v2" + ], "colorPermutations": { "12552552551": [] } @@ -3236,13 +3775,19 @@ "paths": [ "M832 0h-640c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h640c105.6 0 192-86.4 192-192v-640c0-105.6-86.4-192-192-192zM128 320v-128h256v128zM256 448h384v128h-384zM896 832h-448v-128h448zM896 576h-128v-128h128zM896 320h-384v-128h384z" ], - "attrs": [{}], + "attrs": [ + {} + ], "grid": 16, - "tags": ["icon-timeline"], + "tags": [ + "icon-timeline" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -3252,7 +3797,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-timer-v1.5"], + "tags": [ + "icon-timer-v1.5" + ], "colorPermutations": { "12552552551": [] } @@ -3267,7 +3814,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-topic-v2.5"], + "tags": [ + "icon-topic-v2.5" + ], "colorPermutations": { "12552552551": [] } @@ -3287,7 +3836,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-box-with-dashed-lines-v2"], + "tags": [ + "icon-box-with-dashed-lines-v2" + ], "colorPermutations": { "12552552551": [] } @@ -3299,7 +3850,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-summary-widget"], + "tags": [ + "icon-summary-widget" + ], "colorPermutations": { "12552552551": [] } @@ -3312,7 +3865,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-notebook"], + "tags": [ + "icon-notebook" + ], "colorPermutations": { "12552552551": [] } @@ -3323,13 +3878,21 @@ "M0 896c0.227 70.601 57.399 127.773 127.978 128l0.022 0h768c70.601-0.227 127.773-57.399 128-127.978l0-0.022v-608h-512l-50.2-225.6c-7.6-34.2-42.6-62.4-77.8-62.4h-256c-70.601 0.227-127.773 57.399-128 127.978l-0 0.022zM832 768h-640v-256h640z", "M480 0c35.2 0 70.2 28.2 77.8 62.4l36 161.6h430.2v-96c-0.227-70.601-57.399-127.773-127.978-128l-0.022-0z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "grid": 16, - "tags": ["icon-tabs-view"], + "tags": [ + "icon-tabs-view" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -3343,7 +3906,9 @@ ], "attrs": [], "grid": 16, - "tags": ["icon-flexible-layout"], + "tags": [ + "icon-flexible-layout" + ], "colorPermutations": { "12552552551": [] } @@ -3356,13 +3921,25 @@ "M512 640l135-59c-4.485 0.614-9.689 0.977-14.972 1l-0.028 0c-39.4 0-76-21.8-109.2-65-28-36.4-48.8-81.6-61-113.4-29-73.8-59-105.2-69.8-109.4-10.8 4.2-40.8 35.6-69.8 109.4-16.4 42.2-39.2 88.4-68.8 123.2z", "M1024 480l-512 224-512-224v320l512 224 512-224v-320z" ], - "attrs": [{}, {}, {}, {}], + "attrs": [ + {}, + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-generator-sine"], + "tags": [ + "icon-generator-sine" + ], "colorPermutations": { - "12552552551": [{}, {}, {}, {}] + "12552552551": [ + {}, + {}, + {}, + {} + ] } }, { @@ -3375,13 +3952,29 @@ "M658.2 576h-292.4l146.2 64 146.2-64z", "M512 704l-512-224v320l512 224 512-224v-320l-512 224z" ], - "attrs": [{}, {}, {}, {}, {}, {}], + "attrs": [ + {}, + {}, + {}, + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-generator-event"], + "tags": [ + "icon-generator-event" + ], "colorPermutations": { - "12552552551": [{}, {}, {}, {}, {}, {}] + "12552552551": [ + {}, + {}, + {}, + {}, + {}, + {} + ] } }, { @@ -3389,13 +3982,19 @@ "paths": [ "M512 0c-282.8 0-512 229.2-512 512 0 226.4 147 418.4 350.6 486l257.4-486v503c236.8-45 416-253 416-503 0-282.8-229.2-512-512-512zM754.8 527.8c-58.967-68.597-145.842-111.772-242.8-111.772s-183.833 43.176-242.445 111.35l-0.355 0.422-146-125c8.6-10 17.4-19.6 26.8-28.8 92.628-92.679 220.619-150.006 362-150.006s269.372 57.326 361.997 150.003l0.003 0.003c9.4 9.2 18.2 18.8 26.8 28.8z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-gauge-v2"], + "tags": [ + "icon-gauge-v2" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -3405,13 +4004,23 @@ "M830 0h-636c-106.6 0-194 87.2-194 194v318l400-60.2 112-195.8 109.8 192h402.2v-254c-0.227-107.052-86.948-193.773-193.978-194l-0.022-0z", "M1024 640v-64l-384-64 384 128z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-spectra"], + "tags": [ + "icon-spectra" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -3421,13 +4030,23 @@ "M768 704h-512l102.4-179.2-354.4 50.6c31.2 252.8 246.8 448.6 508 448.6 201.6 0 376-116.6 459.6-286l-273.4-156.2z", "M640 512l384 128v-64l-384-64z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-telemetry-spectra"], + "tags": [ + "icon-telemetry-spectra" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -3436,13 +4055,21 @@ "M370.2 459.4c9.326 8.53 19.666 16.261 30.729 22.914l0.871 0.486c-11.077-19.209-17.664-42.221-17.8-66.76l-0-0.040c0-39.6 17.8-77.6 50.2-107.4 37-34 87.4-52.6 141.8-52.6 40.2 0 78.2 10.2 110.2 29.2-8.918-15.653-19.693-29.040-32.268-40.482l-0.132-0.118c-37-34-87.4-52.6-141.8-52.6s-104.8 18.6-141.8 52.6c-32.4 29.8-50.2 67.8-50.2 107.4s17.8 77.6 50.2 107.4z", "M885.4 269.6c-40.6-154.6-192.4-269.6-373.4-269.6s-332.8 115-373.4 269.6c-86 80-138.6 187.8-138.6 306.4 0 247.4 229.2 448 512 448s512-200.6 512-448c0-118.6-52.6-226.4-138.6-306.4zM512 128c141.2 0 256 100.4 256 224s-114.8 224-256 224-256-100.4-256-224 114.8-224 256-224zM512 832c-175.4 0-318.4-127.8-320-285.4 68.8 94.8 186.4 157.4 320 157.4s251.2-62.6 320-157.4c-1.6 157.6-144.6 285.4-320 285.4z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-pushbutton"], + "tags": [ + "icon-pushbutton" + ], "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -3450,13 +4077,19 @@ "paths": [ "M512 0c-282.76 0-512 229.24-512 512s229.24 512 512 512 512-229.24 512-512-229.24-512-512-512zM512 768l-384-256 384-256 384 256z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-conditional"], + "tags": [ + "icon-conditional" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -3464,13 +4097,19 @@ "paths": [ "M832 0h-640c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h640c105.6 0 192-86.4 192-192v-640c0-105.6-86.4-192-192-192zM512 768l-384-256 384-256 384 256z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-condition-widget"], + "tags": [ + "icon-condition-widget" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -3479,13 +4118,21 @@ "M535.6 530.6c-8.4 1.6-17.2 3-26.2 4s-18.2 2.4-27.2 4c-10.196 1.861-18.808 4.010-27.21 6.633l1.61-0.433c-8.609 2.674-16.105 6.348-22.89 10.987l0.29-0.187c-6.693 4.517-12.283 10.107-16.663 16.585l-0.137 0.215c-4.6 6.8-7.4 15.6-8.8 26s-0.4 18.4 2.4 25.2c2.746 6.688 7.224 12.195 12.881 16.122l0.119 0.078c5.967 4.053 13.057 6.94 20.704 8.161l0.296 0.039c7.592 1.527 16.319 2.4 25.25 2.4 0.123 0 0.246-0 0.369-0l-0.019 0c22.2 0 39.6-3.6 52.6-11s23.2-16.2 30.2-26.4c6.273-8.873 11.271-19.191 14.426-30.285l0.174-0.715c1.853-6.809 3.601-15.41 4.855-24.169l0.145-1.231 5.2-41.6c-5.4 4.217-11.723 7.564-18.583 9.689l-0.417 0.111c-6.489 2.241-14.362 4.255-22.444 5.662l-0.956 0.138z", "M1024 384v-192h-152l24-192h-192l-24 192h-256l24-192h-192l-24 192h-232v192h208l-32 256h-176v192h152l-24 192h192l24-192h256l-24 192h192l24-192h232v-192h-208l32-256zM702.8 411.8l-26.4 211.8c-2.231 15.809-3.537 34.122-3.6 52.727l-0 0.073c0 16.8 2.2 29.4 6.4 37.8h-113.4c-1.342-5.556-2.338-12.122-2.781-18.84l-0.019-0.36c-0.261-3.524-0.409-7.634-0.409-11.778 0-2.962 0.076-5.907 0.226-8.832l-0.017 0.41c-18.663 17.401-41.395 30.694-66.597 38.289l-1.203 0.311c-22.627 6.956-48.639 10.974-75.586 11l-0.014 0c-0.764 0.011-1.666 0.018-2.569 0.018-18.098 0-35.598-2.563-52.156-7.345l1.325 0.328c-15.991-4.512-29.851-12.090-41.545-22.122l0.145 0.122c-11.233-9.982-19.792-22.733-24.624-37.192l-0.176-0.608c-5.2-15.2-6.4-33.4-3.8-54.4s9.4-42.2 19.4-57.2c9.524-14.399 21.535-26.346 35.532-35.512l0.468-0.288c13.387-8.662 28.922-15.533 45.512-19.765l1.088-0.235c13.436-3.792 30.801-7.554 48.47-10.41l2.93-0.39c17-2.6 33.8-4.6 50.4-6.2 16.628-1.527 31.69-4.070 46.349-7.643l-2.149 0.443c13-3 23.6-7.6 31.6-13.6s12.6-15 13.6-26.4 0.8-21.8-2.4-28.8c-2.849-6.902-7.542-12.56-13.468-16.517l-0.132-0.083c-6.217-4.011-13.604-6.78-21.543-7.774l-0.257-0.026c-7.897-1.277-17-2.007-26.274-2.007-0.537 0-1.073 0.002-1.609 0.007l0.082-0.001c-22 0-40 4.6-53.8 14.2s-23 25.2-28 47.2h-111.8c4.8-26.2 14.2-48 27.8-65.4 13.475-16.978 29.89-30.968 48.574-41.377l0.826-0.423c18.192-10.038 39.297-17.806 61.619-22.175l1.381-0.225c20.488-4.162 44.053-6.563 68.171-6.6l0.029-0c21.8 0.005 43.239 1.532 64.222 4.479l-2.422-0.279c20.641 2.809 39.324 8.783 56.401 17.461l-1.001-0.461c15.909 8.108 28.858 20.031 37.967 34.601l0.233 0.399c9 15 12.2 34.8 9 59.6z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "grid": 16, - "tags": ["icon-alphanumeric"], + "tags": [ + "icon-alphanumeric" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -3494,13 +4141,21 @@ "M512 0c-282.8 0-512 229.2-512 512s229.2 512 512 512 512-229.2 512-512-229.2-512-512-512zM783.6 783.6c-69.581 69.675-165.757 112.776-272 112.776-212.298 0-384.4-172.102-384.4-384.4s172.102-384.4 384.4-384.4c212.298 0 384.4 172.102 384.4 384.4 0 0.008-0 0.017-0 0.025l0-0.001c0.001 0.264 0.001 0.575 0.001 0.887 0 105.769-42.964 201.503-112.391 270.703l-0.010 0.010z", "M704 384l-128 128-192-192-192 192c0 176.731 143.269 320 320 320s320-143.269 320-320v0z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-image-telemetry"], + "tags": [ + "icon-image-telemetry" + ], "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -3510,13 +4165,23 @@ "M754 436.56c-14 41.44-37.48 100.8-69.2 148.36-38.56 57.78-82.32 87.080-130 87.080s-91.5-29.3-130-87.080c-31.72-47.56-55.14-106.92-69.2-148.36-30.88-90.96-63.14-134.98-78-146.54-14.94 11.56-47.2 55.58-78 146.54-14.38 41.44-37.8 100.8-69.6 148.36q-27.8 41.7-59.12 63.5c75.7 111.378 201.81 183.58 344.783 183.58 0.119 0 0.237-0 0.356-0l-0.019 0c229.76 0 416-186.24 416-416 0-0.071 0-0.156 0-0.24 0-39.119-5.396-76.977-15.484-112.871l0.704 2.931c-16.78 21.74-40.4 63.34-63.22 130.74z", "M921.56 334.62c4.098 24.449 6.44 52.617 6.44 81.332 0 0.017-0 0.034-0 0.051l0-0.003c0 0.095 0 0.208 0 0.32 0 282.593-229.087 511.68-511.68 511.68-0.113 0-0.225-0-0.338-0l0.018 0c-0.014 0-0.031 0-0.048 0-28.716 0-56.884-2.342-84.325-6.845l2.993 0.405c72.483 63.623 168.109 102.44 272.802 102.44 0.203 0 0.406-0 0.61-0l-0.031 0c229.76 0 416-186.24 416-416 0-0.172 0-0.375 0-0.578 0-104.692-38.817-200.319-102.844-273.271l0.404 0.47z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-telemetry-aggregate"], + "tags": [ + "icon-telemetry-aggregate" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -3524,13 +4189,19 @@ "paths": [ "M832 0h-640c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h640c105.6 0 192-86.4 192-192v-640c0-105.6-86.4-192-192-192zM267.64 896h-139.64v-448h139.64zM477.1 896h-139.64v-768h139.64zM686.54 896h-139.64v-320h139.64zM896 896h-139.64v-640h139.64z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-bar-graph"], + "tags": [ + "icon-bar-graph" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -3540,13 +4211,23 @@ "M320 912l387.2 96.8v-896l-387.2-96.8v896z", "M259.2 0.8l-3.2-0.8-128 62.6c-70.4 34.42-128 120.2-128 190.6v640c0 70.4 57.6 99.82 128 65.4l128-62.6 3.2 0.8z" ], - "attrs": [{}, {}, {}], + "attrs": [ + {}, + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-map"], + "tags": [ + "icon-map" + ], "colorPermutations": { - "12552552551": [{}, {}, {}] + "12552552551": [ + {}, + {}, + {} + ] } }, { @@ -3555,13 +4236,21 @@ "M256 192v-64c0.215-70.606 57.394-127.785 127.979-128l0.021-0h256c70.606 0.215 127.785 57.394 128 127.979l0 0.021v64z", "M832 128v128h-640v-128c-105.6 0-192 86.4-192 192v512c0 105.6 86.4 192 192 192h640c105.6 0 192-86.4 192-192v-512c0-105.6-86.4-192-192-192zM128 576v-128h256v128zM640 832h-384v-128h384zM896 832h-128v-128h128zM896 576h-384v-128h384z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "grid": 16, - "tags": ["icon-plan"], + "tags": [ + "icon-plan" + ], "isMulticolor": false, "isMulticolor2": false, "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] } }, { @@ -3569,13 +4258,19 @@ "paths": [ "M896 0h-768c-70.606 0.215-127.785 57.394-128 127.979l-0 0.021v768c0.215 70.606 57.394 127.785 127.979 128l0.021 0h768c70.606-0.215 127.785-57.394 128-127.979l0-0.021v-768c-0.215-70.606-57.394-127.785-127.979-128l-0.021-0zM426.94 533.46c-8.054 15.864-24.249 26.545-42.938 26.545-7.823 0-15.209-1.871-21.734-5.191l0.273 0.126-154.54-77.28v-221.66c0-26.51 21.49-48 48-48s48 21.49 48 48v0 162.34l101.46 50.72c15.864 8.054 26.545 24.249 26.545 42.938 0 7.823-1.871 15.209-5.191 21.734l0.126-0.273zM896 896h-320v-128h320zM896 704h-320v-128h320zM896 512h-320v-128h320zM896 320h-320v-128h320z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-timelist"], + "tags": [ + "icon-timelist" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -3583,13 +4278,19 @@ "paths": [ "M192 0c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h640c105.6 0 192-86.4 192-192v-640c0-105.6-86.4-192-192-192zM128 352c0-53.019 42.981-96 96-96s96 42.981 96 96c0 53.019-42.981 96-96 96v0c-53.019 0-96-42.981-96-96v0zM288 832c-53.019 0-96-42.981-96-96s42.981-96 96-96c53.019 0 96 42.981 96 96v0c0 53.019-42.981 96-96 96v0zM544 640c-53.019 0-96-42.981-96-96s42.981-96 96-96c53.019 0 96 42.981 96 96v0c0 53.019-42.981 96-96 96v0zM544 320c-53.019 0-96-42.981-96-96s42.981-96 96-96c53.019 0 96 42.981 96 96v0c0 53.019-42.981 96-96 96v0zM800 832c-53.019 0-96-42.981-96-96s42.981-96 96-96c53.019 0 96 42.981 96 96v0c0 53.019-42.981 96-96 96v0z" ], - "attrs": [{}], + "attrs": [ + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-plot-scatter"], + "tags": [ + "icon-plot-scatter" + ], "colorPermutations": { - "12552552551": [{}] + "12552552551": [ + {} + ] } }, { @@ -3598,21 +4299,63 @@ "M896 110.72c0-79.9-55.38-127.32-123.080-105.36l-772.92 250.64h896v-145.28z", "M896 320h-896v576c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v-448c0-70.4-57.6-128-128-128zM256 832h-128v-128h128v128zM256 640h-128v-128h128v128zM896 832h-512v-128h512v128zM896 640h-512v-128h512v128z" ], - "attrs": [{}, {}], + "attrs": [ + {}, + {} + ], "isMulticolor": false, "isMulticolor2": false, "grid": 16, - "tags": ["icon-notebook-restricted"], + "tags": [ + "icon-notebook-restricted" + ], "colorPermutations": { - "12552552551": [{}, {}] + "12552552551": [ + {}, + {} + ] + } + }, + { + "id": 187, + "paths": [ + "M109.36 522.46c5.18-11.26 10.4-23.46 15.6-36.72 42.46-108.46 116.32-237.76 227.040-237.76 52.4 0 101.42 29.16 145.7 86.68 37.34 48.5 64.84 108.92 81.34 151.080 38.52 98.38 78.68 140.3 92.96 145.92 14.28-5.62 54.44-47.54 92.96-145.92 23.42-59.8 56.38-125.92 99.8-173.24l-49.84-188.8c-17.96-68.040-89.88-123.7-159.84-123.7h-556.44c-69.94 0-112.48 55.66-94.52 123.7l105.24 398.76z", + "M914.64 501.54c-5.18 11.26-10.4 23.46-15.6 36.72-42.46 108.46-116.32 237.76-227.040 237.76-52.4 0-101.42-29.16-145.7-86.68-37.34-48.5-64.84-108.92-81.34-151.080-38.52-98.38-78.68-140.3-92.96-145.92-14.28 5.62-54.44 47.52-92.96 145.92-23.42 59.8-56.38 125.92-99.8 173.24l49.84 188.8c17.96 68.040 89.88 123.7 159.84 123.7h556.44c69.96 0 112.5-55.66 94.54-123.7l-105.26-398.76z" + ], + "attrs": [ + {}, + {} + ], + "width": 1152, + "grid": 16, + "tags": [ + "icon-telemetry-derived" + ], + "isMulticolor": false, + "isMulticolor2": false, + "colorPermutations": { + "12552552551": [ + {}, + {} + ] } } ], "invisible": false, "colorThemes": [ [ - [0, 0, 0, 1], - [255, 255, 255, 1] + [ + 0, + 0, + 0, + 1 + ], + [ + 255, + 255, + 255, + 1 + ] ] ], "colorThemeIdx": 0 @@ -3664,4 +4407,4 @@ } }, "uid": -1 -} +} \ No newline at end of file diff --git a/src/styles/fonts/Open-MCT-Symbols-16px.ttf b/src/styles/fonts/Open-MCT-Symbols-16px.ttf index ace20d91a7c494dabdddb59386cb24c45e7226c8..093bda98a3828a67513e949109026aa22c47953e 100644 GIT binary patch delta 2168 zcma)7drVVj6hHUgwiJ-k7A#B_RZYj#G?cV-Ayed%+ z;8otf`^mP{kx3KE&jNUpJ9c_oE%%kr1NdG>yQ2dYv0XB>`>vy$+0ngs|7lm`H#y+sc~F@Nu=6z}Y3law?}PW?2Y|L&3`ptXdFh=+p?=5_t zF%l#-QO0rx9>O32J`hG~J`#>RC4|xK6rZ!@fd>z>AOxrbN*)jvqE!M$a{;nPZ4*&u zl`t_I;E-1mEm|x_FKD?SD;9E!M1Ew21UFZe;M!3FFJ@;Cj5fd;)Hi&f{=*k2kh8J14~mBpod4XT8z)c z+#`yUlsix96;eOJ*cA8}g52BRZ7@)4t59t0h%0x+?jOdY#x zqyrkvxP#c1IUe=1nCz(7ZfZdsH+528ajo*QLa3R}q7*e|rkh`0l>}Eax7{>8BA4n6%SMkMbQOaTcKx0S3fGtXsRX_X-;MDxGrJjzVg?x z7JY^IeA+6h_~A-QI>n_jqkA3Rb-Ag@33mx%*!>0K=WE=EimG}H^;NmBjnLV(R=QkU z=ccA^={|{-FT4b&tG`Cwg_?Whx4wlO_zlPtn%c0A1WoM|3r96l`zjh78*|9u+eGK4 zsq05PT8G)#tvVWxryemhUY|lv-)^SIwPDLeL`?%t>U_g7G?z6VnmgKMI21kmsc93M z99wJAbYyEikHXDns%Y}DXNbnLotVeB??SY+AOXA3LfN}^+(`(66x5)BC7{Pg_=UQ~ ztl#Ug(M|`1S$ydlVGTf18Rv933G6maik_n{O87PBaTx}qEG3C4JSjs8E(T3@gUw;? zmdGVajb>Gb(PFMPF3nz~D~yjX)Tvh*Y>I7#e_tq%^cuHR>aJO_E#o75b+tXbC;1_>>tFV{cRxtef(f$Lr&|(Be}{PS9|5MrTYKoQ zfv%C+NI-fGAEp_vRdH_4PB#3oGkz0m^Ql;(KSsP-{VI0Vr(k*h)Q4m(2W-Zd!-iU` zSfF(c%lE72qonLJe+lYKSXpbfXwUbjae>f8YZIr=KT3ana1OqQ1Th`Y9`8sBx!N}H F{{VtEgWmuE delta 2069 zcmah}drVVT7(b_%_VSQtu>!RPDg^-r1T69pO7XF2EC^aO7_n3YQ63YwI9TePGj7oZ zH%?|U++3!HEhJkOo4Lg;*x{yTThO^|CYq^n4-;i(e{9KSNW0&6TX27v>?Zd+_j~=m z=RH%`_^aRX{fsllVwl1tR#e|qSR7v#IR}!@@ow{UyZdl-2Htx6TmAt zBRh6KzhmKrI|sqP0`p~^?e6Valdd-ybNivUbwUu;rON{UH~6g1?!Eg){E?>^YXhF< z{oTEuTK7N7?Ga#q2@qGedtV>>l-*`*2L;UNad)?8-a9@8z6uTneZBpAktm+d-K1xd z6nNcV!@n{$;E2q-b`sn;W8DN7-1d|jo$v4VrLBI5yq!)RbMhk;j zqYz{i&(yF0BQ`*Q!9ehU6p#*x6Po;uk1aH88aUIi;2fY5n2>j(1aGd8o)U9FH}P0E zF|BamMyNU#iYm;KkslBhQhvFLp`FP9IXwZNBhF)tWZ+Mspc7I(SHwf91Jo5!2E3t& zm++mW&DJqHs_~0zElhkvS}m7(@J}fy&GC)s^c+SX%AbLDMGDY>N{6Fz@O>_7K*t%J znW%^^gJ4heo3b4d{fL+pvkMZhO7F*9!uOduFUtC$kbalCMMdl$YTit`TZ8^4%A%{;C^qDN0VhKq;7)mLyv$PrZqbd!QQs13RX@$m?-VECvwp|C`R#vY@c?wZ7#r3kY2tBlH z0ab9OoZK`Ot7iTHXGJdr;}x{^d6k2pqm{IZj;j4(%!^gEvNhcNxaCKoJF$GNir)tO z1tPKfDh6s~R~;2OQCA5XsQU)=>lJmNaVwkP+P1O=W%y36Dx~Au>N+awmgz!NrX*pYse=>+j^Rtp|PJ2io=bFCT=xSbDT|} zzVW7cWc1?(`dwWc&x0CV)TuMBBT!d2zZ4p6I+|h@zie6$m2Go9REIVn_l|Rse{ztrWd$+r8L9re#UYz|xo*zwm2~b49<~na^=)YEwt}uaDYW zG7y}T6->JS3O&Nr`ugT3BjoiW9%mui<2>pSie*6OYc~x`4>(o BMQ{KB diff --git a/src/styles/fonts/Open-MCT-Symbols-16px.woff b/src/styles/fonts/Open-MCT-Symbols-16px.woff index 8a93d16893b87e173212ca1f5cbe49daff86b250..8e4fbd6343c50ffb21a5068df3e0d8c053b13814 100644 GIT binary patch delta 2087 zcma)7ZA?>F7(Vyj7HGjr3l;?1L7^Zm7Dwe<1VK=71BHp;CfJs51&lc6G=Yj6OIYTz zon&#BWhU<5-1xC3&W{Xr%P?`v+|;=Rle(}(H^1UYMzV#qd*0jD{aKbZJq7EN4YjpQVEFZ(VX?|{FHq?O=jnItV@&9QsDp;E^g?B~ zYlyh7v5pCk`0l+gcY(XXm@AP+^4l}ko=z9`xPO68Ar0H3_&0h$GUiFcI+KQ`FUs1} zf8Zdv4UCB&(Kt~N{B7@`2YU6Lk72Zh#ve!GGy7c!;kbJfHj;rfc9z{9aP@bBLx7@# zM*7{!2m1zx4j`lBPxK_rBq_+_gbE>_KO-~%-xJo>24(Ov6B#Qi5uih*_+K0h2E8iU zyObsHpY(}5Uo4NtUg?e`^I@?uDkzhfeIR-v6#-{eM}ckXtcaTlHB@}FYPF!`6qID&ou~u>N`FS52cC}Mz&Z_~Uz4qtnT6%@ ziv}yt({76x8P}5SY3;kP;gv4Jb6e~lFjo{TjJu3^AnpjHTzUxU_>xb-tkXRYlyy{1 zuapVTe%&N_J{0d#s7k2L#gpk2eHpM>PxE7XO3JUN&83D>;5ox2usOjF980*b4xPvT z#6hg*5)T90mbJoSh@W0|f*7L@Xh`xQqZQ1;7neW9e@$x9&?<-JF{i@xCclE}JW7s6 zSiXhjl2VtHt5{q~y-Ew&L{4W+Rx&S9!1E>w(q{frN#QZFS}=E$YFiq`J(V^TEwdz+ z4G;b*J8w$w0(&lf2gu;RV`OGx#f(|`xl9u;%%F3)l5rRKN#=A!Z`kSt z@u9UHsLkpn&q_-k%JPA6WYhV-lg&-x#?-6Oc9Cwu8xb6nMi6=JO3G#b%8zNk7yy%% zLwSYfjiI?>cO>U$Xu53_%z}-|F=LOV9Ixe4^4eABfitUi0L_l|N+GBzx*QZvN*-+v zKyn=NF zR9v}$nqr~gR#@+5;SX3(6_G4ZbPEn=i!&(BKnYRxrL~a?%B6!Kv}M$_!)4Sm^JSC3 zV{1plwhZM;B1--{%io0TUilU@Pbzcstr|0LS@%6SM+K!gS8+QwbjWt4mHbsUzEC*? z|9$I~cWb1I0-dco3uwolbmAbj7W+B|xg zH&s(IHuD!6+|J=Mchp@6CvLe%ab4jFR*-kIq$?X?_?q;e`p!s!(Cw3eqv96VNn;k}eytM@M zwbmvP?VidiSff&v*1k6FU;;&#i-(q#^MZ% zEqk+NMNXWlAU3wZWOzC~U$?8^uNwtLOM0cO|5Orlp(G5)7_>PyTaDXj%(Z7WrPWod z)zx*Yc4d6#+`QQt*q<1d|EoB3Ei?6Uc}Y~qtL;nI{?1~Ri=52`S_kMxr)O|6=v80C zn^Nq~)13;*NroSP=&|yE$H*5w$$YCPj<4|O_z332h1RLj%Jnav<srJnfvDCHGbn~KIhfi>T1RrzRnvgR`1_t2FAtbTP^P`H1Ch|b+_zfjCaD+N{!Dt zTh`IiOWco`M@L#h$M)CS!TrM6mSxlyoWFUfv#kYdym9a;pq6>L;r&jK;Hogsq-N?e zW_EV(-UALXq%Wuig3-se_xRxFX-j};1GRtEu|Rjr9t3WuWYYC^l8x23q}CKkG= zW!xFOzq6-zH+FP##!tpbmO~4LyK*g8MR8OI z@Mu&a^oFAjV%%iNGBP)^4vHfNxM;%$16O$XZ#gW-X}67L4yQ-TY2b-y0jx0*j+(L! zDzmeNBADb5c`<8^904UJ4#yP2d?w~2#f`{8L~e@R2Ii8E1#uTK4#gc%%wZw_C3lO% zPkjq!Mf@gY6o@ZXMzAVVR<+UiL5jRLp+yOTazp4=0!dpFOMnfDG#*H#O^qgQ0v0Fj z2cAkA1U8tRK)?B(;T*23LhQ2iV1CQ857;!jk**B9S)7^uDKW_!FeydDj-FWCy@JW5)GIUzq*2fdX$~dG+_D=7I-W*J z=Gwkj60n7b*wuusgIt@^Des~5UPWaoEE^FqciGulb50~cO0e+Kt#>jB~G827{d=SSS&A^zft%`A~V#VGpjlV2h z*>wLOWQ(-v;)_DrO;?M=`on&?U-paY1+wXq1;nh z8LQJzsb(|Y0xjvKH^@8Cq#t_oHjMk4AtR(Ml*5TFcaXy;Ej><-=gcrS!2fvE);w$Z zKP*;%{Mguo*Zb)eq&_?uRt;BCz7}6z`SB?`*`_|4qgki=aA>NhXNy%lfwPF8T2na} zpZVrF+*5XaJ^7m-^B;-Wg5q7DMSSIpPYF*x=B|g6zQa=Swa;z}MobAJy|pmI_?RQ< z_DANF8?`EE&f{*NRSfu&#lzMT?!d}o(cYE=KD~9b_OPvi Date: Wed, 4 Sep 2024 11:58:57 -0700 Subject: [PATCH 040/139] Style enhancements for Derived Telemetry object - Closes #7823 - Tweak to object description. --- src/plugins/comps/plugin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/comps/plugin.js b/src/plugins/comps/plugin.js index c42ea40c17..4bfa62eede 100644 --- a/src/plugins/comps/plugin.js +++ b/src/plugins/comps/plugin.js @@ -32,9 +32,9 @@ export default function CompsPlugin() { name: 'Derived Telemetry', key: 'comps', description: - 'Add one or more telemetry objects, apply a mathematical operation to them, and republish the result as a new telemetry object.', + 'Add one or more telemetry end points, apply a mathematical operation to them, and output the result as new telemetry.', creatable: true, - cssClass: 'icon-telemetry', + cssClass: 'icon-derived-telemetry', initialize: function (domainObject) { domainObject.configuration = { comps: { From 2793da40ec7641f7aa7cfdf1efbd275682bbb17e Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Wed, 4 Sep 2024 17:32:43 -0700 Subject: [PATCH 041/139] Enhancements for Derived Telemetry object - Closes #7823 - Added new `ObjectPathString.vue` UI component, based on `ObjectPath.vue`. --- src/ui/components/ObjectPathString.vue | 171 +++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 src/ui/components/ObjectPathString.vue diff --git a/src/ui/components/ObjectPathString.vue b/src/ui/components/ObjectPathString.vue new file mode 100644 index 0000000000..6aa4bc9b22 --- /dev/null +++ b/src/ui/components/ObjectPathString.vue @@ -0,0 +1,171 @@ + + + + + From 1d686c2926c4c57eaf0389de7de1388065ef25a8 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Wed, 4 Sep 2024 17:33:36 -0700 Subject: [PATCH 042/139] Style enhancements for Derived Telemetry object - Closes #7823 - Significant mods for style and CSS classing. Still WIP, more coming. --- src/plugins/comps/components/CompsView.vue | 92 +++++++++++----------- src/plugins/comps/components/comps.scss | 78 ++++++++++++------ src/styles/_constants-espresso.scss | 2 +- src/styles/_controls.scss | 5 ++ 4 files changed, 109 insertions(+), 68 deletions(-) diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 2fe710e7e9..c37218a89c 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -21,7 +21,7 @@ --> diff --git a/src/plugins/comps/components/comps.scss b/src/plugins/comps/components/comps.scss index 27ea64ab98..3003c577d6 100644 --- a/src/plugins/comps/components/comps.scss +++ b/src/plugins/comps/components/comps.scss @@ -19,13 +19,34 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ +@mixin expressionMsg($fg, $bg) { + $op: 0.4; + color: rgba($fg, $op * 1.5); + background: rgba($bg, $op); +} + .c-comps { + display: flex; + flex-direction: column; + gap: $interiorMarginLg; + .is-editing & { padding: $interiorMargin; } - &__refs-and-controls { + &__output { + display: flex; + align-items: baseline; + gap: $interiorMargin; + &-label { + flex: 0 0 auto; + text-transform: uppercase; + } + + &-value { + flex: 0 1 auto; + } } &__section, @@ -42,20 +63,6 @@ grid-template-columns: max-content max-content min-content 1fr; padding: $interiorMargin; line-height: 170%; // Aligns text with controls like selects - - //&__definition, - //&__test-value { - // display: flex; - // align-items: flex-start; - // gap: $interiorMargin; - //} - // - //&__definition { - //} - // - //&__test-value { - // - //} } &__path-and-field { @@ -65,10 +72,37 @@ } &__expression { - textarea { - resize: vertical; + *[class*=value] { + font-family: monospace; + //font-size: 1.1em; + resize: vertical; // Only applies to textarea + } + div[class*=value] { + padding: $interiorMargin; + } + } + + &__expression-msg { + @include expressionMsg($colorOkFg, $colorOk); + border-radius: $basicCr; + display: flex; // Creates hanging indent from :before icon + padding: $interiorMarginSm $interiorMarginLg $interiorMarginSm $interiorMargin; + //text-wrap: normal; + max-width: max-content; + + &:before { + content: $glyph-icon-check; + font-family: symbolsfont; + margin-right: $interiorMarginSm; } + &.--bad { + @include expressionMsg($colorErrorFg, $colorError); + + &:before { + content: $glyph-icon-alert-triangle; + } + } } .--em { @@ -76,17 +110,3 @@ //font-weight: bold; } } - - -/************************************ OLD */ -.c-expression-output-good { - width: 100%; - margin-right: 10px; - color: green; -} - -.c-expression-output-bad { - width: 100%; - margin-right: 10px; - color: red; -} diff --git a/src/plugins/condition/components/ConditionSet.vue b/src/plugins/condition/components/ConditionSet.vue index bdefc5ff5c..cb473c10b9 100644 --- a/src/plugins/condition/components/ConditionSet.vue +++ b/src/plugins/condition/components/ConditionSet.vue @@ -23,9 +23,9 @@ + + diff --git a/src/plugins/condition/historicalTelemetryProvider.js b/src/plugins/condition/historicalTelemetryProvider.js index f5377d8231..d98b762e5b 100644 --- a/src/plugins/condition/historicalTelemetryProvider.js +++ b/src/plugins/condition/historicalTelemetryProvider.js @@ -1,8 +1,7 @@ export default class HistoricalTelemetryProvider { - constructor(openmct, telemetryObjects, compositionLoad, conditions, conditionSetDomainObject) { + constructor(openmct, telemetryObjects, conditions, conditionSetDomainObject) { this.openmct = openmct; this.telemetryObjects = telemetryObjects; - this.compositionLoad = compositionLoad; this.bounds = { start: null, end: null }; this.telemetryList = []; this.conditions = conditions; @@ -130,6 +129,50 @@ export default class HistoricalTelemetryProvider { return historicalTelemetryDateMap; } + async sortTelemetriesInWorker(historicalTelemetriesPool) { + const sortedTelemetries = await this.startWorker('sortTelemetries', { + historicalTelemetriesPool + }); + return sortedTelemetries; + } + + async startWorker(type, data) { + // eslint-disable-next-line no-undef + const workerUrl = `${this.openmct.getAssetPath()}${__OPENMCT_ROOT_RELATIVE__}historicalTelemetryWorker.js`; + const worker = new Worker(workerUrl); + + try { + const result = await this.getDataFromWorker(worker, type, data); + return result; + } catch (error) { + console.error('Error in condition manager getHistoricalData:', error); + throw error; + } finally { + worker.terminate(); + } + } + + getDataFromWorker(worker, type, data) { + return new Promise((resolve, reject) => { + worker.onmessage = (e) => { + if (e.data.type === 'result') { + resolve(e.data.data); + } else if (e.data.type === 'error') { + reject(new Error(e.data.error)); + } + }; + + worker.onerror = (error) => { + reject(error); + }; + + worker.postMessage({ + type, + data + }); + }); + } + evaluateConditionsByDate(historicalTelemetryDateMap, conditionCollectionMap) { const outputTelemetryDateMap = new Map(); historicalTelemetryDateMap.forEach((historicalTelemetryMap, timestamp) => { @@ -177,7 +220,6 @@ export default class HistoricalTelemetryProvider { condition, conditionCollectionMap ); - console.log(conditionOutput.value); outputTelemetryDateMap.set(timestamp, conditionOutput); } }); @@ -186,8 +228,6 @@ export default class HistoricalTelemetryProvider { } async getHistoricalInputsByDate() { - console.log('getHistoricalInputsByDate'); - console.log(this.conditions); const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection; const { @@ -197,7 +237,8 @@ export default class HistoricalTelemetryProvider { conditionCollectionMap } = await this.getAllTelemetries(conditionCollection); - const historicalTelemetryDateMap = this.sortTelemetriesByDate(historicalTelemetriesPool); + const historicalTelemetryDateMap = + await this.sortTelemetriesInWorker(historicalTelemetriesPool); const outputTelemetryDateMap = this.evaluateConditionsByDate( historicalTelemetryDateMap, conditionCollectionMap @@ -222,15 +263,10 @@ export default class HistoricalTelemetryProvider { async getHistoricalData() { console.log('getHistoricalData'); - await this.compositionLoad; this.setTimeBounds(this.openmct.time.getBounds()); const outputTelemetryMap = await this.getHistoricalInputsByDate(); const formattedOutputTelemetry = this.formatOutputData(outputTelemetryMap); - // const firstObjectKey = this.historicalTelemetryPoolMap.keys().next().value; - // const firstObjectValue = this.historicalTelemetryPoolMap.values().next().value; - // const formattedHistoricalData = this.formatHistoricalData(firstObjectKey, firstObjectValue); console.log(formattedOutputTelemetry); - // console.log(formattedHistoricalData); return formattedOutputTelemetry; } @@ -248,27 +284,4 @@ export default class HistoricalTelemetryProvider { }); return outputTelemetryList; } - - simpleTelemetryList(outputTelemetryMap) { - const outputTelemetryList = []; - outputTelemetryMap.forEach((outputMetadata, timestamp) => { - const { value } = outputMetadata; - outputTelemetryList.push(value); - }); - return outputTelemetryList; - } - - formatHistoricalData(historicalDataKey, telemetryDetails) { - const formattedData = []; - const { domainObject, historicalTelemetry } = telemetryDetails; - historicalTelemetry.forEach((value) => { - formattedData.push({ - id: domainObject.identifier, - output: value.sin, - conditionId: historicalDataKey, - utc: value.utc - }); - }); - return formattedData; - } } diff --git a/src/plugins/condition/historicalTelemetryWorker.js b/src/plugins/condition/historicalTelemetryWorker.js new file mode 100644 index 0000000000..017e9daa26 --- /dev/null +++ b/src/plugins/condition/historicalTelemetryWorker.js @@ -0,0 +1,33 @@ +import { makeKeyString } from '../../api/objects/object-utils.js'; + +function sortTelemetriesByDate(historicalTelemetriesPool) { + const historicalTelemetryDateMap = new Map(); + historicalTelemetriesPool.forEach((historicalTelemetryList) => { + const { historicalTelemetry, domainObject } = historicalTelemetryList; + const { identifier } = domainObject; + const telemetryIdentifier = makeKeyString(identifier); + historicalTelemetry.forEach((historicalTelemetryItem) => { + if (!historicalTelemetryDateMap.get(historicalTelemetryItem.utc)) { + const telemetryMap = new Map(); + telemetryMap.set(telemetryIdentifier, historicalTelemetryItem); + historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap); + } else { + const telemetryMap = historicalTelemetryDateMap.get(historicalTelemetryItem.utc); + telemetryMap.set(telemetryIdentifier, historicalTelemetryItem); + historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap); + } + }); + }); + return historicalTelemetryDateMap; +} + +self.onmessage = function (e) { + const { type, data } = e.data; + + if (type === 'sortTelemetries') { + const sortedTelemetries = sortTelemetriesByDate(data.historicalTelemetriesPool); + self.postMessage({ type: 'result', data: sortedTelemetries }); + } else { + self.postMessage({ type: 'error', error: 'Unknown message type' }); + } +}; diff --git a/src/plugins/condition/plugin.js b/src/plugins/condition/plugin.js index 365386ef68..5540746206 100644 --- a/src/plugins/condition/plugin.js +++ b/src/plugins/condition/plugin.js @@ -21,6 +21,7 @@ *****************************************************************************/ import { v4 as uuid } from 'uuid'; +import ConditionInspectorViewProvider from './ConditionInspectorViewProvider.js'; import ConditionSetCompositionPolicy from './ConditionSetCompositionPolicy.js'; import ConditionSetMetadataProvider from './ConditionSetMetadataProvider.js'; import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider.js'; @@ -37,6 +38,7 @@ export default function ConditionPlugin() { cssClass: 'icon-conditional', initialize: function (domainObject) { domainObject.configuration = { + shouldFetchHistorical: false, conditionTestData: [], conditionCollection: [ { @@ -61,5 +63,6 @@ export default function ConditionPlugin() { openmct.telemetry.addProvider(new ConditionSetMetadataProvider(openmct)); openmct.telemetry.addProvider(new ConditionSetTelemetryProvider(openmct)); openmct.objectViews.addProvider(new ConditionSetViewProvider(openmct)); + openmct.inspectorViews.addProvider(new ConditionInspectorViewProvider(openmct)); }; } From dfcfa4723752dc0fe75e145b185e769066e1fedf Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 24 Sep 2024 21:32:56 +0200 Subject: [PATCH 072/139] pass options on request to underlying collections --- src/plugins/comps/CompsManager.js | 12 ++++++++---- src/plugins/comps/CompsTelemetryProvider.js | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 48c218cb08..e049aeb286 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -8,6 +8,7 @@ export default class CompsManager extends EventEmitter { #telemetryCollections = {}; #dataFrame = {}; #telemetryLoadedPromises = []; + #telemetryOptions = {}; #loaded = false; #compositionLoaded = false; #telemetryProcessors = {}; @@ -110,8 +111,9 @@ export default class CompsManager extends EventEmitter { return this.#loaded; } - async load() { + async load(telemetryOptions) { if (!this.#compositionLoaded) { + this.#telemetryOptions = telemetryOptions; await this.#loadComposition(); this.#compositionLoaded = true; } @@ -206,7 +208,7 @@ export default class CompsManager extends EventEmitter { this.deleteParameter(keyString); }; - requestUnderlyingTelemetry() { + requestUnderlyingTelemetry(options) { const underlyingTelemetry = {}; Object.keys(this.#telemetryCollections).forEach((collectionKey) => { const collection = this.#telemetryCollections[collectionKey]; @@ -252,8 +254,10 @@ export default class CompsManager extends EventEmitter { #addTelemetryObject = (telemetryObject) => { const keyString = this.#openmct.objects.makeKeyString(telemetryObject.identifier); this.#telemetryObjects[keyString] = telemetryObject; - this.#telemetryCollections[keyString] = - this.#openmct.telemetry.requestCollection(telemetryObject); + this.#telemetryCollections[keyString] = this.#openmct.telemetry.requestCollection( + telemetryObject, + this.#telemetryOptions + ); this.#telemetryCollections[keyString].on('add', this.#getTelemetryProcessor(keyString)); this.#telemetryCollections[keyString].on('clear', this.clearData); diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 57519a4b1b..c1eb983624 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -61,7 +61,7 @@ export default class CompsTelemetryProvider { this.#openmct, this.#compsManagerPool ); - specificCompsManager.load().then(() => { + specificCompsManager.load(options).then(() => { const callbackID = this.#getCallbackID(); const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry(); const expression = specificCompsManager.getExpression(); From 4a301a15d2b6c8abe552ce46ecbb0d770d26465d Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 25 Sep 2024 13:19:00 +0200 Subject: [PATCH 073/139] ensure derived DERIVED telemetry loads in the proper order. also have telemetry collections prioritize request options over clock --- src/api/telemetry/TelemetryCollection.js | 12 +++++++-- src/plugins/comps/CompsManager.js | 27 +++++++++++++-------- src/plugins/comps/CompsTelemetryProvider.js | 2 +- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/api/telemetry/TelemetryCollection.js b/src/api/telemetry/TelemetryCollection.js index 2e736a1d6a..8ccae3210f 100644 --- a/src/api/telemetry/TelemetryCollection.js +++ b/src/api/telemetry/TelemetryCollection.js @@ -216,12 +216,20 @@ export default class TelemetryCollection extends EventEmitter { let hasDataBeforeStartBound = false; let size = this.options.size; let enforceSize = size !== undefined && this.options.enforceSize; + // prioritize request bounds over time context bounds + let boundsToUse = this.lastBounds; + if (this.options.start) { + boundsToUse.start = this.options.start; + } + if (this.options.end) { + boundsToUse.end = this.options.end; + } // loop through, sort and dedupe for (let datum of data) { parsedValue = this.parseTime(datum); - beforeStartOfBounds = parsedValue < this.lastBounds.start; - afterEndOfBounds = parsedValue > this.lastBounds.end; + beforeStartOfBounds = parsedValue < boundsToUse.start; + afterEndOfBounds = parsedValue > boundsToUse.end; if ( !afterEndOfBounds && diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index e049aeb286..e151c604e8 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -1,4 +1,5 @@ import { EventEmitter } from 'eventemitter3'; +import _ from 'lodash'; export default class CompsManager extends EventEmitter { #openmct; @@ -112,20 +113,23 @@ export default class CompsManager extends EventEmitter { } async load(telemetryOptions) { + // if our options change, we need to reload the composition + if (!_.isEqual(telemetryOptions, this.#telemetryOptions) && this.#loaded) { + this.#destroy(); + } + this.#telemetryOptions = telemetryOptions; if (!this.#compositionLoaded) { - this.#telemetryOptions = telemetryOptions; await this.#loadComposition(); this.#compositionLoaded = true; } if (!this.#loaded) { - await Promise.all(this.#telemetryLoadedPromises); + await this.startListeningToUnderlyingTelemetry(); this.#telemetryLoadedPromises = []; this.#loaded = true; } } async startListeningToUnderlyingTelemetry() { - this.#loaded = false; Object.keys(this.#telemetryCollections).forEach((keyString) => { if (!this.#telemetryCollections[keyString].loaded) { this.#telemetryCollections[keyString].on('add', this.#getTelemetryProcessor(keyString)); @@ -136,7 +140,15 @@ export default class CompsManager extends EventEmitter { }); await Promise.all(this.#telemetryLoadedPromises); this.#telemetryLoadedPromises = []; - this.#loaded = true; + } + + #destroy() { + this.stopListeningToUnderlyingTelemetry(); + this.#composition = null; + this.#telemetryCollections = {}; + this.#compositionLoaded = false; + this.#loaded = false; + this.#telemetryObjects = {}; } stopListeningToUnderlyingTelemetry() { @@ -208,7 +220,7 @@ export default class CompsManager extends EventEmitter { this.deleteParameter(keyString); }; - requestUnderlyingTelemetry(options) { + requestUnderlyingTelemetry() { const underlyingTelemetry = {}; Object.keys(this.#telemetryCollections).forEach((collectionKey) => { const collection = this.#telemetryCollections[collectionKey]; @@ -259,11 +271,6 @@ export default class CompsManager extends EventEmitter { this.#telemetryOptions ); - this.#telemetryCollections[keyString].on('add', this.#getTelemetryProcessor(keyString)); - this.#telemetryCollections[keyString].on('clear', this.clearData); - const telemetryLoadedPromise = this.#telemetryCollections[keyString].load(); - this.#telemetryLoadedPromises.push(telemetryLoadedPromise); - // check to see if we have a corresponding parameter // if not, add one const parameterExists = this.#domainObject.configuration.comps.parameters.some( diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index c1eb983624..56d0154a2f 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -117,7 +117,7 @@ export default class CompsTelemetryProvider { callbackID ); specificCompsManager.on('underlyingTelemetryUpdated', boundComputeOnNewTelemetry); - specificCompsManager.startListeningToUnderlyingTelemetry(); + specificCompsManager.load(); return () => { specificCompsManager.off('underlyingTelemetryUpdated', boundComputeOnNewTelemetry); delete this.#subscriptionCallbacks[callbackID]; From 101baa58e09ffdda7ccd16780b7e8e518b16ae2f Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Mon, 30 Sep 2024 00:20:48 -0500 Subject: [PATCH 074/139] Fix issue with missing data --- src/plugins/condition/historicalTelemetryWorker.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plugins/condition/historicalTelemetryWorker.js b/src/plugins/condition/historicalTelemetryWorker.js index 017e9daa26..fae6a5b913 100644 --- a/src/plugins/condition/historicalTelemetryWorker.js +++ b/src/plugins/condition/historicalTelemetryWorker.js @@ -7,14 +7,18 @@ function sortTelemetriesByDate(historicalTelemetriesPool) { const { identifier } = domainObject; const telemetryIdentifier = makeKeyString(identifier); historicalTelemetry.forEach((historicalTelemetryItem) => { - if (!historicalTelemetryDateMap.get(historicalTelemetryItem.utc)) { + let telemetryTimestamp = historicalTelemetryItem.utc; + if (historicalTelemetryItem.timestamp) { + telemetryTimestamp = new Date(historicalTelemetryItem.timestamp)?.getTime(); + } + if (!historicalTelemetryDateMap.get(telemetryTimestamp)) { const telemetryMap = new Map(); telemetryMap.set(telemetryIdentifier, historicalTelemetryItem); - historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap); + historicalTelemetryDateMap.set(telemetryTimestamp, telemetryMap); } else { - const telemetryMap = historicalTelemetryDateMap.get(historicalTelemetryItem.utc); + const telemetryMap = historicalTelemetryDateMap.get(telemetryTimestamp); telemetryMap.set(telemetryIdentifier, historicalTelemetryItem); - historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap); + historicalTelemetryDateMap.set(telemetryTimestamp, telemetryMap); } }); }); From 7896f36748cfcdf6e68b0a09a45a7e623a250e79 Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Mon, 30 Sep 2024 09:22:36 -0500 Subject: [PATCH 075/139] Update emitted values --- e2e/appActions.js | 17 ++++++++++ .../conditionSet/conditionSet.e2e.spec.js | 31 ++++++++++++++++++- src/plugins/condition/ConditionManager.js | 13 +++++--- .../condition/ConditionSetMetadataProvider.js | 23 +++++++++++--- .../condition/historicalTelemetryProvider.js | 11 +++++-- 5 files changed, 82 insertions(+), 13 deletions(-) diff --git a/e2e/appActions.js b/e2e/appActions.js index f1602bc3cd..1458635300 100644 --- a/e2e/appActions.js +++ b/e2e/appActions.js @@ -116,6 +116,22 @@ async function createDomainObjectWithDefaults(page, { type, name, parent = 'mine }; } +/** + * Retrieves the properties of an OpenMCT domain object by its identifier. + * + * @param {import('@playwright/test').Page} page - The Playwright page object. + * @param {string | identifier - The identifier or UUID of the domain object. + * @returns {Promise} An object containing the properties of the domain object. + */ +async function getDomainObject(page, identifier) { + const domainObject = await page.evaluate(async (objIdentifier) => { + const object = await window.openmct.objects.get(objIdentifier); + return object; + }, identifier); + + return domainObject; +} + /** * Generate a notification with the given options. * @param {import('@playwright/test').Page} page @@ -636,6 +652,7 @@ export { createPlanFromJSON, expandEntireTree, getCanvasPixels, + getDomainObject, navigateToObjectWithFixedTimeBounds, navigateToObjectWithRealTime, setEndOffset, diff --git a/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js b/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js index 6b76088b39..9ebe193431 100644 --- a/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js +++ b/e2e/tests/functional/plugins/conditionSet/conditionSet.e2e.spec.js @@ -29,7 +29,8 @@ import { fileURLToPath } from 'url'; import { createDomainObjectWithDefaults, - createExampleTelemetryObject + createExampleTelemetryObject, + getDomainObject } from '../../../../appActions.js'; import { expect, test } from '../../../../pluginFixtures.js'; @@ -468,6 +469,34 @@ test.describe('Basic Condition Set Use', () => { description: 'https://github.com/nasa/openmct/issues/7484' }); }); + + test('should toggle shouldFetchHistorical property in inspector', async ({ page }) => { + await page.goto(conditionSet.url); + await page.getByLabel('Edit Object').click(); + await page.getByRole('tab', { name: 'Config' }).click(); + let toggleSwitch = page.getByLabel('condition-historical-toggle'); + const initialState = await toggleSwitch.isChecked(); + expect(initialState).toBe(false); + + await toggleSwitch.click(); + let toggledState = await toggleSwitch.isChecked(); + expect(toggledState).toBe(true); + await page.click('button[title="Save"]'); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); + let conditionSetObject = await getDomainObject(page, conditionSet.uuid); + expect(conditionSetObject.configuration.shouldFetchHistorical).toBe(true); + + await page.getByLabel('Edit Object').click(); + await page.getByRole('tab', { name: 'Config' }).click(); + toggleSwitch = page.getByLabel('condition-historical-toggle'); + await toggleSwitch.click(); + toggledState = await toggleSwitch.isChecked(); + expect(toggledState).toBe(false); + await page.click('button[title="Save"]'); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); + conditionSetObject = await getDomainObject(page, conditionSet.uuid); + expect(conditionSetObject.configuration.shouldFetchHistorical).toBe(false); + }); }); test.describe('Condition Set Composition', () => { diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 859bf943e8..44818ed349 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -474,14 +474,15 @@ export default class ConditionManager extends EventEmitter { }); } - emitConditionSetResult(currentCondition, timestamp, outputValue) { + emitConditionSetResult(currentCondition, timestamp, outputValue, result) { this.emit( 'conditionSetResultUpdated', Object.assign( { - output: outputValue, id: this.conditionSetDomainObject.identifier, - conditionId: currentCondition.id + conditionId: currentCondition.id, + output: outputValue, + result }, timestamp ) @@ -509,6 +510,10 @@ export default class ConditionManager extends EventEmitter { async processCondition(timestamp, telemetryObject, telemetryData) { const currentCondition = this.getCurrentCondition(); + const conditionDetails = this.conditions.filter( + (condition) => condition.id === currentCondition.id + )?.[0]; + const conditionResult = currentCondition?.isDefault ? false : conditionDetails?.result; let telemetryValue = currentCondition.configuration.output; if (currentCondition?.configuration?.outputTelemetry) { const selectedOutputIdentifier = currentCondition?.configuration?.outputTelemetry; @@ -539,7 +544,7 @@ export default class ConditionManager extends EventEmitter { } } - this.emitConditionSetResult(currentCondition, timestamp, telemetryValue); + this.emitConditionSetResult(currentCondition, timestamp, telemetryValue, conditionResult); } getTestData(metadatum) { diff --git a/src/plugins/condition/ConditionSetMetadataProvider.js b/src/plugins/condition/ConditionSetMetadataProvider.js index 0d3190d49b..d49f9937a2 100644 --- a/src/plugins/condition/ConditionSetMetadataProvider.js +++ b/src/plugins/condition/ConditionSetMetadataProvider.js @@ -50,12 +50,23 @@ export default class ConditionSetMetadataProvider { }; }); + const resultEnum = [ + { + string: 'true', + value: true + }, + { + string: 'false', + value: false + } + ]; + return { values: this.getDomains().concat([ { - key: 'state', + key: 'output', source: 'output', - name: 'State', + name: 'Value', format: 'enum', enumerations: enumerations, hints: { @@ -63,9 +74,11 @@ export default class ConditionSetMetadataProvider { } }, { - key: 'output', - name: 'Value', - format: 'string', + key: 'result', + source: 'result', + name: 'Result', + format: 'enum', + enumerations: resultEnum, hints: { range: 2 } diff --git a/src/plugins/condition/historicalTelemetryProvider.js b/src/plugins/condition/historicalTelemetryProvider.js index d98b762e5b..a2a1abb058 100644 --- a/src/plugins/condition/historicalTelemetryProvider.js +++ b/src/plugins/condition/historicalTelemetryProvider.js @@ -43,6 +43,7 @@ export default class HistoricalTelemetryProvider { const conditionConfiguration = conditionCollectionMap.get(condition.id)?.configuration; const { outputTelemetry, outputMetadata } = conditionConfiguration; let output = {}; + output.result = true; if (outputTelemetry) { const outputTelemetryID = this.openmct.objects.makeKeyString(outputTelemetry); const outputTelemetryData = telemetryData.get(outputTelemetryID); @@ -203,9 +204,11 @@ export default class HistoricalTelemetryProvider { const { outputTelemetry, outputMetadata, output } = conditionConfiguration; if (isDefault) { const conditionOutput = { + condition, telemetry: null, value: output, - condition + result: false, + isDefault: true }; outputTelemetryDateMap.set(timestamp, conditionOutput); } @@ -274,12 +277,14 @@ export default class HistoricalTelemetryProvider { const outputTelemetryList = []; const domainObject = this.conditionSetDomainObject; outputTelemetryMap.forEach((outputMetadata, timestamp) => { - const { condition, telemetry, value } = outputMetadata; + const { condition, telemetry, value, result, isDefault } = outputMetadata; outputTelemetryList.push({ conditionId: condition.id, id: domainObject.identifier, output: value, - utc: timestamp + utc: timestamp, + result, + isDefault }); }); return outputTelemetryList; From 4b39ea232a215f20c8a99eb2b065d66daff6e159 Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Mon, 30 Sep 2024 18:53:08 -0500 Subject: [PATCH 076/139] Addressing feedback --- src/plugins/condition/ConditionManager.js | 2 +- .../condition/components/ConditionItem.vue | 16 +++++----------- src/plugins/condition/components/TestData.vue | 6 +----- .../condition/historicalTelemetryProvider.js | 8 -------- 4 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 44818ed349..41bba5c4e9 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -24,7 +24,7 @@ import { EventEmitter } from 'eventemitter3'; import { v4 as uuid } from 'uuid'; import Condition from './Condition.js'; -import HistoricalTelemetryProvider from './historicalTelemetryProvider.js'; +import HistoricalTelemetryProvider from './HistoricalTelemetryProvider.js'; import { getLatestTimestamp } from './utils/time.js'; export default class ConditionManager extends EventEmitter { diff --git a/src/plugins/condition/components/ConditionItem.vue b/src/plugins/condition/components/ConditionItem.vue index 250c517154..f33495bd08 100644 --- a/src/plugins/condition/components/ConditionItem.vue +++ b/src/plugins/condition/components/ConditionItem.vue @@ -352,18 +352,12 @@ export default { methods: { setOutputSelection() { let conditionOutput = this.condition.configuration.output; - if (conditionOutput) { - if ( - conditionOutput !== 'false' && - conditionOutput !== 'true' && - conditionOutput !== 'telemetry value' - ) { - this.selectedOutputSelection = 'string'; - } else { - this.selectedOutputSelection = conditionOutput; - } - } else if (conditionOutput === undefined) { + if (conditionOutput === undefined) { this.selectedOutputSelection = 'none'; + } else if (['false', 'true', 'telemetry value'].includes(conditionOutput)) { + this.selectedOutputSelection = conditionOutput; + } else { + this.selectedOutputSelection = 'string'; } }, setOutputValue() { diff --git a/src/plugins/condition/components/TestData.vue b/src/plugins/condition/components/TestData.vue index 1e6f695cf0..d087d948e7 100644 --- a/src/plugins/condition/components/TestData.vue +++ b/src/plugins/condition/components/TestData.vue @@ -63,7 +63,7 @@ :key="index" :value="telemetryOption.identifier" > - {{ telemetryPaths[index] || telemetryOption.name }} + {{ telemetryOption.path || telemetryOption.name }} @@ -201,10 +201,6 @@ export default { this.telemetryMetadataOptions[id] = []; } }); - this.telemetry.forEach(async (telemetryOption, index) => { - const telemetryPath = await this.getFullTelemetryPath(telemetryOption); - this.telemetryPaths[index] = telemetryPath; - }); }, addTestInput(testInput) { this.testInputs.push( diff --git a/src/plugins/condition/historicalTelemetryProvider.js b/src/plugins/condition/historicalTelemetryProvider.js index a2a1abb058..78cb79fce0 100644 --- a/src/plugins/condition/historicalTelemetryProvider.js +++ b/src/plugins/condition/historicalTelemetryProvider.js @@ -15,14 +15,6 @@ export default class HistoricalTelemetryProvider { this.bounds = bounds; } - refreshAllHistoricalTelemetries() { - const refreshPromises = []; - for (const [, value] of Object.entries(this.telemetryObjects)) { - refreshPromises.push(this.refreshHistoricalTelemetry(value)); - } - return Promise.all(refreshPromises); - } - async refreshHistoricalTelemetry(domainObject, identifier) { console.log('refreshHistoricalTelemetry'); if (!domainObject && identifier) { From b97555445e8ceedeaa94e3064200f2133aea8a20 Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Mon, 30 Sep 2024 19:10:24 -0500 Subject: [PATCH 077/139] Creating a const for telemetry value --- src/plugins/condition/ConditionManager.js | 3 ++- src/plugins/condition/components/ConditionItem.vue | 9 +++++---- src/plugins/condition/utils/constants.js | 2 ++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 41bba5c4e9..97969be777 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -25,6 +25,7 @@ import { v4 as uuid } from 'uuid'; import Condition from './Condition.js'; import HistoricalTelemetryProvider from './HistoricalTelemetryProvider.js'; +import { TELEMETRY_VALUE } from './utils/constants.js'; import { getLatestTimestamp } from './utils/time.js'; export default class ConditionManager extends EventEmitter { @@ -392,7 +393,7 @@ export default class ConditionManager extends EventEmitter { const currentCondition = this.getCurrentConditionLAD(conditionResults); let output = currentCondition?.configuration?.output; - if (output === 'telemetry value') { + if (output === TELEMETRY_VALUE) { const { outputTelemetry, outputMetadata } = currentCondition.configuration; const outputTelemetryObject = await this.openmct.objects.get(outputTelemetry); const telemetryOptions = { diff --git a/src/plugins/condition/components/ConditionItem.vue b/src/plugins/condition/components/ConditionItem.vue index f33495bd08..a7481a10fc 100644 --- a/src/plugins/condition/components/ConditionItem.vue +++ b/src/plugins/condition/components/ConditionItem.vue @@ -113,7 +113,7 @@ @change="persist" /> - + Date: Thu, 3 Oct 2024 01:56:28 -0500 Subject: [PATCH 084/139] Add back initialize on mount --- src/plugins/condition/components/ConditionItem.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/condition/components/ConditionItem.vue b/src/plugins/condition/components/ConditionItem.vue index 3ce3f2d21c..c47969b3c4 100644 --- a/src/plugins/condition/components/ConditionItem.vue +++ b/src/plugins/condition/components/ConditionItem.vue @@ -350,6 +350,7 @@ export default { }, mounted() { this.setOutputSelection(); + this.initializeMetadata(); }, methods: { setOutputSelection() { From 9b9c0f796b5abb2d61c176b9632015e59a438cee Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 3 Oct 2024 14:09:47 +0200 Subject: [PATCH 085/139] improvement in loading --- src/plugins/comps/CompsMathWorker.js | 4 ++-- src/plugins/comps/CompsTelemetryProvider.js | 26 +++++++++++++++++---- src/plugins/comps/components/CompsView.vue | 3 +-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 125b6648a2..adec37f357 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -31,7 +31,7 @@ onconnect = function (e) { function getFullDataFrame(telemetryForComps, parameters) { const dataFrame = {}; - Object.keys(telemetryForComps).forEach((key) => { + Object.keys(telemetryForComps)?.forEach((key) => { const parameter = parameters.find((p) => p.keyString === key); const dataSet = telemetryForComps[key]; const telemetryMap = new Map(dataSet.map((item) => [item[parameter.timeKey], item])); @@ -61,7 +61,7 @@ function calculate(dataFrame, parameters, expression) { const otherParameters = parameters.slice(1); // iterate over the reference telemetry data const referenceTelemetry = dataFrame[referenceParameter.keyString]; - referenceTelemetry.forEach((referenceTelemetryItem) => { + referenceTelemetry?.forEach((referenceTelemetryItem) => { const scope = { [referenceParameter.name]: referenceTelemetryItem[referenceParameter.valueToUse] }; diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 56d0154a2f..bf069fd36d 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -63,7 +63,9 @@ export default class CompsTelemetryProvider { ); specificCompsManager.load(options).then(() => { const callbackID = this.#getCallbackID(); - const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry(); + const telemetryForComps = JSON.parse( + JSON.stringify(specificCompsManager.requestUnderlyingTelemetry()) + ); const expression = specificCompsManager.getExpression(); const parameters = JSON.parse(JSON.stringify(specificCompsManager.getParameters())); if (!expression || !parameters) { @@ -78,6 +80,11 @@ export default class CompsTelemetryProvider { parameters, callbackID }; + console.debug( + `📝 Requesting calculation for ${domainObject.name} with callback ID ${callbackID}:`, + options, + payload + ); this.#sharedWorker.port.postMessage(payload); }); }); @@ -117,12 +124,22 @@ export default class CompsTelemetryProvider { callbackID ); specificCompsManager.on('underlyingTelemetryUpdated', boundComputeOnNewTelemetry); - specificCompsManager.load(); + const telemetryOptions = { + strategy: 'latest', + size: 1 + }; + specificCompsManager.load(telemetryOptions); + console.debug( + `📝 Starting subscription for ${domainObject.name} with callback ID ${callbackID}` + ); return () => { - specificCompsManager.off('underlyingTelemetryUpdated', boundComputeOnNewTelemetry); delete this.#subscriptionCallbacks[callbackID]; - // if this is the last subscription, tell the comp manager to stop listening + console.debug( + `🛑 Stopping subscription for ${domainObject.name} with callback ID ${callbackID}. We now have ${Object.keys(this.#subscriptionCallbacks).length} subscribers`, + this.#subscriptionCallbacks + ); specificCompsManager.stopListeningToUnderlyingTelemetry(); + specificCompsManager.off('underlyingTelemetryUpdated', boundComputeOnNewTelemetry); }; } @@ -157,6 +174,7 @@ export default class CompsTelemetryProvider { console.error('📝 Error calculating request:', event.data); this.#requestPromises[callbackID].resolve([]); } else { + console.debug(`🧮 Calculation request result for ${callbackID}:`, result); this.#requestPromises[callbackID].resolve(result); } delete this.#requestPromises[callbackID]; diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 58f3009011..ec8f1abeab 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -185,11 +185,10 @@ onBeforeMount(async () => { compsManager.on('parameterAdded', reloadParameters); compsManager.on('parameterRemoved', reloadParameters); compsManager.on('outputFormatChanged', updateOutputFormat); - await compsManager.load(); + await outputTelemetryCollection.load(telemetryOptions); // will implicitly load compsManager parameters.value = compsManager.getParameters(); expression.value = compsManager.getExpression(); outputFormat.value = compsManager.getOutputFormat(); - outputTelemetryCollection.load(); applyTestData(); }); From 8e5ac683605c4114670bac31c009bf562b9463d2 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 3 Oct 2024 14:09:47 +0200 Subject: [PATCH 086/139] improvement in loading --- src/plugins/comps/CompsMathWorker.js | 4 ++-- src/plugins/comps/CompsTelemetryProvider.js | 26 +++++++++++++++++---- src/plugins/comps/components/CompsView.vue | 3 +-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 125b6648a2..adec37f357 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -31,7 +31,7 @@ onconnect = function (e) { function getFullDataFrame(telemetryForComps, parameters) { const dataFrame = {}; - Object.keys(telemetryForComps).forEach((key) => { + Object.keys(telemetryForComps)?.forEach((key) => { const parameter = parameters.find((p) => p.keyString === key); const dataSet = telemetryForComps[key]; const telemetryMap = new Map(dataSet.map((item) => [item[parameter.timeKey], item])); @@ -61,7 +61,7 @@ function calculate(dataFrame, parameters, expression) { const otherParameters = parameters.slice(1); // iterate over the reference telemetry data const referenceTelemetry = dataFrame[referenceParameter.keyString]; - referenceTelemetry.forEach((referenceTelemetryItem) => { + referenceTelemetry?.forEach((referenceTelemetryItem) => { const scope = { [referenceParameter.name]: referenceTelemetryItem[referenceParameter.valueToUse] }; diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 56d0154a2f..bf069fd36d 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -63,7 +63,9 @@ export default class CompsTelemetryProvider { ); specificCompsManager.load(options).then(() => { const callbackID = this.#getCallbackID(); - const telemetryForComps = specificCompsManager.requestUnderlyingTelemetry(); + const telemetryForComps = JSON.parse( + JSON.stringify(specificCompsManager.requestUnderlyingTelemetry()) + ); const expression = specificCompsManager.getExpression(); const parameters = JSON.parse(JSON.stringify(specificCompsManager.getParameters())); if (!expression || !parameters) { @@ -78,6 +80,11 @@ export default class CompsTelemetryProvider { parameters, callbackID }; + console.debug( + `📝 Requesting calculation for ${domainObject.name} with callback ID ${callbackID}:`, + options, + payload + ); this.#sharedWorker.port.postMessage(payload); }); }); @@ -117,12 +124,22 @@ export default class CompsTelemetryProvider { callbackID ); specificCompsManager.on('underlyingTelemetryUpdated', boundComputeOnNewTelemetry); - specificCompsManager.load(); + const telemetryOptions = { + strategy: 'latest', + size: 1 + }; + specificCompsManager.load(telemetryOptions); + console.debug( + `📝 Starting subscription for ${domainObject.name} with callback ID ${callbackID}` + ); return () => { - specificCompsManager.off('underlyingTelemetryUpdated', boundComputeOnNewTelemetry); delete this.#subscriptionCallbacks[callbackID]; - // if this is the last subscription, tell the comp manager to stop listening + console.debug( + `🛑 Stopping subscription for ${domainObject.name} with callback ID ${callbackID}. We now have ${Object.keys(this.#subscriptionCallbacks).length} subscribers`, + this.#subscriptionCallbacks + ); specificCompsManager.stopListeningToUnderlyingTelemetry(); + specificCompsManager.off('underlyingTelemetryUpdated', boundComputeOnNewTelemetry); }; } @@ -157,6 +174,7 @@ export default class CompsTelemetryProvider { console.error('📝 Error calculating request:', event.data); this.#requestPromises[callbackID].resolve([]); } else { + console.debug(`🧮 Calculation request result for ${callbackID}:`, result); this.#requestPromises[callbackID].resolve(result); } delete this.#requestPromises[callbackID]; diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 58f3009011..ec8f1abeab 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -185,11 +185,10 @@ onBeforeMount(async () => { compsManager.on('parameterAdded', reloadParameters); compsManager.on('parameterRemoved', reloadParameters); compsManager.on('outputFormatChanged', updateOutputFormat); - await compsManager.load(); + await outputTelemetryCollection.load(telemetryOptions); // will implicitly load compsManager parameters.value = compsManager.getParameters(); expression.value = compsManager.getExpression(); outputFormat.value = compsManager.getOutputFormat(); - outputTelemetryCollection.load(); applyTestData(); }); From 154e8c695d021c474300f3d18396d7442ffabf07 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 3 Oct 2024 14:47:12 +0200 Subject: [PATCH 087/139] fix slow loading errors --- src/api/telemetry/TelemetryCollection.js | 31 ++++++++++++++++-------- src/plugins/comps/CompsManager.js | 12 ++++----- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/api/telemetry/TelemetryCollection.js b/src/api/telemetry/TelemetryCollection.js index 7cad1fe8bd..769b2923e4 100644 --- a/src/api/telemetry/TelemetryCollection.js +++ b/src/api/telemetry/TelemetryCollection.js @@ -73,6 +73,10 @@ export default class TelemetryCollection extends EventEmitter { this.isStrategyLatest = this.options.strategy === 'latest'; this.dataOutsideTimeBounds = false; this.modeChanged = false; + + console.debug( + `🫙 Created telemetry for ${this.domainObject.name} with bounds ${options.start} and ${options.end}` + ); } /** @@ -86,6 +90,16 @@ export default class TelemetryCollection extends EventEmitter { this._setTimeSystem(this.options.timeContext.getTimeSystem()); this.lastBounds = this.options.timeContext.getBounds(); + // prioritize passed options over time bounds + if (this.options.start) { + this.lastBounds.start = this.options.start; + } + if (this.options.end) { + this.lastBounds.end = this.options.end; + } + console.debug( + `🫙 Bounds for collection are start ${this.lastBounds.start} and end ${this.lastBounds.end}` + ); this._watchBounds(); this._watchTimeSystem(); this._watchTimeModeChange(); @@ -215,20 +229,13 @@ export default class TelemetryCollection extends EventEmitter { let hasDataBeforeStartBound = false; let size = this.options.size; let enforceSize = size !== undefined && this.options.enforceSize; - // prioritize request bounds over time context bounds - let boundsToUse = this.lastBounds; - if (this.options.start) { - boundsToUse.start = this.options.start; - } - if (this.options.end) { - boundsToUse.end = this.options.end; - } + console.debug(`🫙 Bounds are telemetry are currently`, this.lastBounds); // loop through, sort and dedupe for (let datum of data) { parsedValue = this.parseTime(datum); - beforeStartOfBounds = parsedValue < boundsToUse.start; - afterEndOfBounds = parsedValue > boundsToUse.end; + beforeStartOfBounds = parsedValue < this.lastBounds.start; + afterEndOfBounds = parsedValue > this.lastBounds.end; if ( !afterEndOfBounds && @@ -335,6 +342,10 @@ export default class TelemetryCollection extends EventEmitter { return; } + console.debug( + `🫙 Bounds CHANGED for ${this.domainObject.name} are start ${bounds.start} and end ${bounds.end}` + ); + let startChanged = this.lastBounds.start !== bounds.start; let endChanged = this.lastBounds.end !== bounds.end; diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 7875397078..59ee041c77 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -7,14 +7,11 @@ export default class CompsManager extends EventEmitter { #composition; #telemetryObjects = {}; #telemetryCollections = {}; - #dataFrame = {}; #telemetryLoadedPromises = []; #telemetryOptions = {}; #loaded = false; #compositionLoaded = false; #telemetryProcessors = {}; - // make id random 4 digit number - #id = Math.floor(Math.random() * 9000) + 1000; constructor(openmct, domainObject) { super(); @@ -111,8 +108,11 @@ export default class CompsManager extends EventEmitter { } async load(telemetryOptions) { - // if our options change, we need to reload the composition if (!_.isEqual(telemetryOptions, this.#telemetryOptions) && this.#loaded) { + console.debug( + `😩 Reloading comps manager ${this.#domainObject.name} due to telemetry options change`, + telemetryOptions + ); this.#destroy(); } this.#telemetryOptions = telemetryOptions; @@ -121,13 +121,13 @@ export default class CompsManager extends EventEmitter { this.#compositionLoaded = true; } if (!this.#loaded) { - await this.startListeningToUnderlyingTelemetry(); + await this.#startListeningToUnderlyingTelemetry(); this.#telemetryLoadedPromises = []; this.#loaded = true; } } - async startListeningToUnderlyingTelemetry() { + async #startListeningToUnderlyingTelemetry() { Object.keys(this.#telemetryCollections).forEach((keyString) => { if (!this.#telemetryCollections[keyString].loaded) { this.#telemetryCollections[keyString].on('add', this.#getTelemetryProcessor(keyString)); From 4bbbd17b6194a6c25cbc945c3b1785ce40cb52ed Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 3 Oct 2024 15:24:48 +0200 Subject: [PATCH 088/139] more telemetry collection changes to acommodate bound changes --- src/api/telemetry/TelemetryCollection.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/telemetry/TelemetryCollection.js b/src/api/telemetry/TelemetryCollection.js index 769b2923e4..10b6a6144b 100644 --- a/src/api/telemetry/TelemetryCollection.js +++ b/src/api/telemetry/TelemetryCollection.js @@ -342,15 +342,15 @@ export default class TelemetryCollection extends EventEmitter { return; } - console.debug( - `🫙 Bounds CHANGED for ${this.domainObject.name} are start ${bounds.start} and end ${bounds.end}` - ); - let startChanged = this.lastBounds.start !== bounds.start; let endChanged = this.lastBounds.end !== bounds.end; this.lastBounds = bounds; + // delete start/end if they are defined in options as we've got new bounds + delete this.options.start; + delete this.options.end; + if (isTick) { if (this.timeKey === undefined) { return; From 4a3b0b97f6e73b3f78139f4f939358035c99cb39 Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Thu, 3 Oct 2024 10:40:00 -0500 Subject: [PATCH 089/139] Compensate for missing data at certain timestamps --- src/plugins/condition/historicalTelemetryProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/condition/historicalTelemetryProvider.js b/src/plugins/condition/historicalTelemetryProvider.js index c78ec58e03..fb375975d7 100644 --- a/src/plugins/condition/historicalTelemetryProvider.js +++ b/src/plugins/condition/historicalTelemetryProvider.js @@ -41,7 +41,7 @@ export default class HistoricalTelemetryProvider { const outputTelemetryID = this.openmct.objects.makeKeyString(outputTelemetry); const outputTelemetryData = telemetryData.get(outputTelemetryID); output.telemetry = outputTelemetryData; - output.value = outputTelemetryData[outputMetadata]; + output.value = outputTelemetryData?.[outputMetadata] || undefined; output.condition = condition; } else if (conditionConfiguration?.output) { output.telemetry = null; From a739d61c88ca6044a8a1babe7595b85f1ac0c4c4 Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Thu, 3 Oct 2024 14:04:11 -0500 Subject: [PATCH 090/139] Rename file --- .../{historicalTelemetryProvider.js => HistoricalTelemetry.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/plugins/condition/{historicalTelemetryProvider.js => HistoricalTelemetry.js} (100%) diff --git a/src/plugins/condition/historicalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetry.js similarity index 100% rename from src/plugins/condition/historicalTelemetryProvider.js rename to src/plugins/condition/HistoricalTelemetry.js From 488178ad43efd73b35f959a5ef5c67d664f366f9 Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Thu, 3 Oct 2024 14:04:37 -0500 Subject: [PATCH 091/139] Rename file --- .../{HistoricalTelemetry.js => HistoricalTelemetryProvider.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/plugins/condition/{HistoricalTelemetry.js => HistoricalTelemetryProvider.js} (100%) diff --git a/src/plugins/condition/HistoricalTelemetry.js b/src/plugins/condition/HistoricalTelemetryProvider.js similarity index 100% rename from src/plugins/condition/HistoricalTelemetry.js rename to src/plugins/condition/HistoricalTelemetryProvider.js From 38316bd2f54cae9d420fb8ca3abcbb0c766e002a Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 4 Oct 2024 09:46:51 +0200 Subject: [PATCH 092/139] more debug just in case --- src/api/telemetry/TelemetryCollection.js | 23 ++++++++++++++++++----- src/plugins/comps/CompsManager.js | 2 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/api/telemetry/TelemetryCollection.js b/src/api/telemetry/TelemetryCollection.js index 10b6a6144b..2ff078caf4 100644 --- a/src/api/telemetry/TelemetryCollection.js +++ b/src/api/telemetry/TelemetryCollection.js @@ -75,7 +75,7 @@ export default class TelemetryCollection extends EventEmitter { this.modeChanged = false; console.debug( - `🫙 Created telemetry for ${this.domainObject.name} with bounds ${options.start} and ${options.end}` + `🫙 Created telemetry for ${this.domainObject.name} with bounds ${new Date(options.start).toISOString()} and ${new Date(options.end).toISOString()}` ); } @@ -98,7 +98,7 @@ export default class TelemetryCollection extends EventEmitter { this.lastBounds.end = this.options.end; } console.debug( - `🫙 Bounds for collection are start ${this.lastBounds.start} and end ${this.lastBounds.end}` + `🫙 Bounds for collection are start ${new Date(this.lastBounds.start).toISOString()} and end ${new Date(this.lastBounds.end).toISOString()}` ); this._watchBounds(); this._watchTimeSystem(); @@ -144,6 +144,9 @@ export default class TelemetryCollection extends EventEmitter { * @private */ async _requestHistoricalTelemetry() { + console.debug( + `🫙 Requesting historical telemetry with start ${new Date(this.lastBounds.start).toISOString()} and end ${new Date(this.lastBounds.end).toISOString()}}` + ); let options = this.openmct.telemetry.standardizeRequestOptions({ ...this.options }); const historicalProvider = this.openmct.telemetry.findRequestProvider( this.domainObject, @@ -229,7 +232,6 @@ export default class TelemetryCollection extends EventEmitter { let hasDataBeforeStartBound = false; let size = this.options.size; let enforceSize = size !== undefined && this.options.enforceSize; - console.debug(`🫙 Bounds are telemetry are currently`, this.lastBounds); // loop through, sort and dedupe for (let datum of data) { @@ -237,6 +239,13 @@ export default class TelemetryCollection extends EventEmitter { beforeStartOfBounds = parsedValue < this.lastBounds.start; afterEndOfBounds = parsedValue > this.lastBounds.end; + if (beforeStartOfBounds) { + console.debug( + `🫙 Datum is before start of bounds: ${new Date(parsedValue).toISOString()} < ${new Date(this.lastBounds.start).toISOString()}`, + this.options + ); + } + if ( !afterEndOfBounds && (!beforeStartOfBounds || (this.isStrategyLatest && this.openmct.telemetry.greedyLAD())) @@ -348,8 +357,12 @@ export default class TelemetryCollection extends EventEmitter { this.lastBounds = bounds; // delete start/end if they are defined in options as we've got new bounds - delete this.options.start; - delete this.options.end; + if (!isTick && startChanged) { + delete this.options.start; + } + if (!isTick && endChanged) { + delete this.options.end; + } if (isTick) { if (this.timeKey === undefined) { diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 59ee041c77..88721362f1 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -110,7 +110,7 @@ export default class CompsManager extends EventEmitter { async load(telemetryOptions) { if (!_.isEqual(telemetryOptions, this.#telemetryOptions) && this.#loaded) { console.debug( - `😩 Reloading comps manager ${this.#domainObject.name} due to telemetry options change`, + `😩 Reloading comps manager ${this.#domainObject.name} due to telemetry options change. New bounds are: ${new Date(telemetryOptions.start).toISOString()} to ${new Date(telemetryOptions.end).toISOString()}`, telemetryOptions ); this.#destroy(); From f718ccdf4eedcde468caf8723f1ad0d917031cc7 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 4 Oct 2024 11:14:45 +0200 Subject: [PATCH 093/139] stacked plots are overriding telemetry object configurations --- src/plugins/plot/stackedPlot/StackedPlotItem.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/plot/stackedPlot/StackedPlotItem.vue b/src/plugins/plot/stackedPlot/StackedPlotItem.vue index 1541b8c980..087175fec8 100644 --- a/src/plugins/plot/stackedPlot/StackedPlotItem.vue +++ b/src/plugins/plot/stackedPlot/StackedPlotItem.vue @@ -249,7 +249,8 @@ export default { ...persistedSeriesConfig.series } ], - yAxis: persistedSeriesConfig.yAxis + yAxis: persistedSeriesConfig.yAxis, + ...this.childObject.configuration } }, openmct: this.openmct, From 58d6cdb57417244025b3b83a30334e0d5099aa64 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 4 Oct 2024 11:29:00 +0200 Subject: [PATCH 094/139] some changes --- src/api/telemetry/TelemetryCollection.js | 4 ---- src/plugins/comps/CompsManager.js | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/api/telemetry/TelemetryCollection.js b/src/api/telemetry/TelemetryCollection.js index 2ff078caf4..231e141f9b 100644 --- a/src/api/telemetry/TelemetryCollection.js +++ b/src/api/telemetry/TelemetryCollection.js @@ -73,10 +73,6 @@ export default class TelemetryCollection extends EventEmitter { this.isStrategyLatest = this.options.strategy === 'latest'; this.dataOutsideTimeBounds = false; this.modeChanged = false; - - console.debug( - `🫙 Created telemetry for ${this.domainObject.name} with bounds ${new Date(options.start).toISOString()} and ${new Date(options.end).toISOString()}` - ); } /** diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 88721362f1..6d912ef397 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -108,9 +108,9 @@ export default class CompsManager extends EventEmitter { } async load(telemetryOptions) { - if (!_.isEqual(telemetryOptions, this.#telemetryOptions) && this.#loaded) { + if (!_.isEqual(telemetryOptions, this.#telemetryOptions)) { console.debug( - `😩 Reloading comps manager ${this.#domainObject.name} due to telemetry options change. New bounds are: ${new Date(telemetryOptions.start).toISOString()} to ${new Date(telemetryOptions.end).toISOString()}`, + `😩 Reloading comps manager ${this.#domainObject.name} due to telemetry options change.`, telemetryOptions ); this.#destroy(); From d859322a478a856f7e64f425398eff7b0f11d330 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 4 Oct 2024 14:29:52 +0200 Subject: [PATCH 095/139] add new flag to deal with plots asking for zoomed out data that should be ignoring clock --- src/api/telemetry/TelemetryCollection.js | 39 +++++++++++++++--------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/api/telemetry/TelemetryCollection.js b/src/api/telemetry/TelemetryCollection.js index 231e141f9b..addfa008f1 100644 --- a/src/api/telemetry/TelemetryCollection.js +++ b/src/api/telemetry/TelemetryCollection.js @@ -184,7 +184,7 @@ export default class TelemetryCollection extends EventEmitter { return; } - this._processNewTelemetry(historicalData); + this._processNewTelemetry(historicalData, false); } /** @@ -200,7 +200,7 @@ export default class TelemetryCollection extends EventEmitter { options.strategy = this.openmct.telemetry.SUBSCRIBE_STRATEGY.BATCH; this.unsubscribe = this.openmct.telemetry.subscribe( this.domainObject, - (datum) => this._processNewTelemetry(datum), + (datum) => this._processNewTelemetry(datum, true), options ); } @@ -211,9 +211,10 @@ export default class TelemetryCollection extends EventEmitter { * * @param {(Object|Object[])} telemetryData - telemetry data object or * array of telemetry data objects + * @param {boolean} isSubscriptionData - `true` if the telemetry data is new subscription data, * @private */ - _processNewTelemetry(telemetryData) { + _processNewTelemetry(telemetryData, isSubscriptionData = false) { if (telemetryData === undefined) { return; } @@ -228,16 +229,29 @@ export default class TelemetryCollection extends EventEmitter { let hasDataBeforeStartBound = false; let size = this.options.size; let enforceSize = size !== undefined && this.options.enforceSize; + const boundsToUse = this.lastBounds; + if (!isSubscriptionData && this.options.start) { + boundsToUse.start = this.options.start; + } + if (!isSubscriptionData && this.options.end) { + boundsToUse.end = this.options.end; + } // loop through, sort and dedupe for (let datum of data) { parsedValue = this.parseTime(datum); - beforeStartOfBounds = parsedValue < this.lastBounds.start; - afterEndOfBounds = parsedValue > this.lastBounds.end; + beforeStartOfBounds = parsedValue < boundsToUse.start; + afterEndOfBounds = parsedValue > boundsToUse.end; if (beforeStartOfBounds) { console.debug( - `🫙 Datum is before start of bounds: ${new Date(parsedValue).toISOString()} < ${new Date(this.lastBounds.start).toISOString()}`, + `🫙 Datum is BEFORE start of bounds: ${new Date(parsedValue).toISOString()} < ${new Date(this.lastBounds.start).toISOString()}`, + this.options + ); + } + if (afterEndOfBounds) { + console.debug( + `🫙 Datum is AFTER start of bounds: ${new Date(parsedValue).toISOString()} < ${new Date(this.lastBounds.start).toISOString()}`, this.options ); } @@ -352,14 +366,6 @@ export default class TelemetryCollection extends EventEmitter { this.lastBounds = bounds; - // delete start/end if they are defined in options as we've got new bounds - if (!isTick && startChanged) { - delete this.options.start; - } - if (!isTick && endChanged) { - delete this.options.end; - } - if (isTick) { if (this.timeKey === undefined) { return; @@ -427,7 +433,10 @@ export default class TelemetryCollection extends EventEmitter { this.emit('add', added, [this.boundedTelemetry.length]); } } else { - // user bounds change, reset + // user bounds change, reset and remove initial requested bounds (we're using new bounds) + delete this.options?.start; + delete this.options?.end; + this.lastBounds = bounds; this._reset(); } } From f239d4bb6dc5e32b45a77a4c92d8cda635d959e8 Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Fri, 4 Oct 2024 12:23:57 -0500 Subject: [PATCH 096/139] Update metadata provider --- src/plugins/condition/ConditionSetMetadataProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/condition/ConditionSetMetadataProvider.js b/src/plugins/condition/ConditionSetMetadataProvider.js index d49f9937a2..52d6d3ceb7 100644 --- a/src/plugins/condition/ConditionSetMetadataProvider.js +++ b/src/plugins/condition/ConditionSetMetadataProvider.js @@ -64,7 +64,7 @@ export default class ConditionSetMetadataProvider { return { values: this.getDomains().concat([ { - key: 'output', + key: 'value', source: 'output', name: 'Value', format: 'enum', From 395436a361b75ba5a33bd31e6cdb6fe0beede2fc Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 09:32:44 +0200 Subject: [PATCH 097/139] works --- src/api/telemetry/TelemetryCollection.js | 19 ------- src/plugins/comps/CompsManager.js | 53 +++++++++++++------- src/plugins/comps/CompsMathWorker.js | 39 +++++++++++--- src/plugins/comps/CompsMetadataProvider.js | 1 + src/plugins/comps/CompsTelemetryProvider.js | 7 +-- src/plugins/comps/components/CompsView.vue | 42 ++++++++++++++++ src/plugins/plot/configuration/PlotSeries.js | 8 ++- 7 files changed, 121 insertions(+), 48 deletions(-) diff --git a/src/api/telemetry/TelemetryCollection.js b/src/api/telemetry/TelemetryCollection.js index addfa008f1..d3999753c8 100644 --- a/src/api/telemetry/TelemetryCollection.js +++ b/src/api/telemetry/TelemetryCollection.js @@ -93,9 +93,6 @@ export default class TelemetryCollection extends EventEmitter { if (this.options.end) { this.lastBounds.end = this.options.end; } - console.debug( - `🫙 Bounds for collection are start ${new Date(this.lastBounds.start).toISOString()} and end ${new Date(this.lastBounds.end).toISOString()}` - ); this._watchBounds(); this._watchTimeSystem(); this._watchTimeModeChange(); @@ -140,9 +137,6 @@ export default class TelemetryCollection extends EventEmitter { * @private */ async _requestHistoricalTelemetry() { - console.debug( - `🫙 Requesting historical telemetry with start ${new Date(this.lastBounds.start).toISOString()} and end ${new Date(this.lastBounds.end).toISOString()}}` - ); let options = this.openmct.telemetry.standardizeRequestOptions({ ...this.options }); const historicalProvider = this.openmct.telemetry.findRequestProvider( this.domainObject, @@ -243,19 +237,6 @@ export default class TelemetryCollection extends EventEmitter { beforeStartOfBounds = parsedValue < boundsToUse.start; afterEndOfBounds = parsedValue > boundsToUse.end; - if (beforeStartOfBounds) { - console.debug( - `🫙 Datum is BEFORE start of bounds: ${new Date(parsedValue).toISOString()} < ${new Date(this.lastBounds.start).toISOString()}`, - this.options - ); - } - if (afterEndOfBounds) { - console.debug( - `🫙 Datum is AFTER start of bounds: ${new Date(parsedValue).toISOString()} < ${new Date(this.lastBounds.start).toISOString()}`, - this.options - ); - } - if ( !afterEndOfBounds && (!beforeStartOfBounds || (this.isStrategyLatest && this.openmct.telemetry.greedyLAD())) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 6d912ef397..b23f8071cd 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -59,7 +59,8 @@ export default class CompsManager extends EventEmitter { name: `${this.#getNextAlphabeticalParameterName()}`, valueToUse, testValue: 0, - timeMetaData + timeMetaData, + accumulateValues: false }); this.emit('parameterAdded', this.#domainObject); } @@ -173,27 +174,45 @@ export default class CompsManager extends EventEmitter { } } - getFullDataFrame(newTelemetry) { - const dataFrame = {}; - // can assume on data item - const newTelemetryKey = Object.keys(newTelemetry)[0]; - const newTelemetryData = newTelemetry[newTelemetryKey]; - const otherTelemetryKeys = Object.keys(this.#telemetryCollections).filter( - (keyString) => keyString !== newTelemetryKey + #getParameterForKeyString(keyString) { + return this.#domainObject.configuration.comps.parameters.find( + (parameter) => parameter.keyString === keyString ); - // initialize the data frame with the new telemetry data - dataFrame[newTelemetryKey] = newTelemetryData; - // initialize the other telemetry data + } + + getTelemetryForComps(newTelemetry) { + const telemetryForComps = {}; + const newTelemetryKey = Object.keys(newTelemetry)[0]; + const newTelemetryParameter = this.#getParameterForKeyString(newTelemetryKey); + const newTelemetryData = newTelemetry[newTelemetryKey]; + const otherTelemetryKeys = Object.keys(this.#telemetryCollections).slice(0); + if (newTelemetryParameter.accumulateValues) { + telemetryForComps[newTelemetryKey] = this.#telemetryCollections[newTelemetryKey].getAll(); + } else { + telemetryForComps[newTelemetryKey] = newTelemetryData; + } otherTelemetryKeys.forEach((keyString) => { - dataFrame[keyString] = []; + telemetryForComps[keyString] = []; }); - // march through the new telemetry data and add data to the frame from the other telemetry objects - // using LOCF + const otherTelemetryKeysNotAccumulating = otherTelemetryKeys.filter( + (keyString) => !this.#getParameterForKeyString(keyString).accumulateValues + ); + const otherTelemetryKeysAccumulating = otherTelemetryKeys.filter( + (keyString) => this.#getParameterForKeyString(keyString).accumulateValues + ); + // if we're accumulating, just add all the data + otherTelemetryKeysAccumulating.forEach((keyString) => { + telemetryForComps[keyString] = this.#telemetryCollections[keyString].getAll(); + }); + + // for the others, march through the new telemetry data and add data to the frame from the other telemetry objects + // using LOCF newTelemetryData.forEach((newDatum) => { - otherTelemetryKeys.forEach((otherKeyString) => { + otherTelemetryKeysNotAccumulating.forEach((otherKeyString) => { const otherCollection = this.#telemetryCollections[otherKeyString]; + // otherwise we need to find the closest datum to the new datum let insertionPointForNewData = otherCollection._sortedIndex(newDatum); const otherCollectionData = otherCollection.getAll(); if (insertionPointForNewData && insertionPointForNewData >= otherCollectionData.length) { @@ -202,11 +221,11 @@ export default class CompsManager extends EventEmitter { // get the closest datum to the new datum const closestDatum = otherCollectionData[insertionPointForNewData]; if (closestDatum) { - dataFrame[otherKeyString].push(closestDatum); + telemetryForComps[otherKeyString].push(closestDatum); } }); }); - return dataFrame; + return telemetryForComps; } #removeTelemetryObject = (telemetryObjectIdentifier) => { diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index adec37f357..29c2ba4fe2 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -5,7 +5,8 @@ onconnect = function (e) { const port = e.ports[0]; port.onmessage = function (event) { - const { type, callbackID, telemetryForComps, expression, parameters } = event.data; + const { type, callbackID, telemetryForComps, expression, parameters, newTelemetry } = + event.data; let responseType = 'unknown'; let error = null; let result = []; @@ -15,7 +16,7 @@ onconnect = function (e) { result = calculateRequest(telemetryForComps, parameters, expression); } else if (type === 'calculateSubscription') { responseType = 'calculationSubscriptionResult'; - result = calculateSubscription(telemetryForComps, parameters, expression); + result = calculateSubscription(telemetryForComps, newTelemetry, parameters, expression); } else if (type === 'init') { port.postMessage({ type: 'ready' }); return; @@ -40,9 +41,16 @@ function getFullDataFrame(telemetryForComps, parameters) { return dataFrame; } -function calculateSubscription(telemetryForComps, parameters, expression) { +function calculateSubscription(telemetryForComps, newTelemetry, parameters, expression) { const dataFrame = getFullDataFrame(telemetryForComps, parameters); - return calculate(dataFrame, parameters, expression); + const calculation = calculate(dataFrame, parameters, expression); + const newTelemetryKey = Object.keys(newTelemetry)[0]; + const newTelemetrySize = newTelemetry[newTelemetryKey].length; + let trimmedCalculation = calculation; + if (calculation.length > newTelemetrySize) { + trimmedCalculation = calculation.slice(calculation.length - newTelemetrySize); + } + return trimmedCalculation; } function calculateRequest(telemetryForComps, parameters, expression) { @@ -56,14 +64,28 @@ function calculate(dataFrame, parameters, expression) { if (!expression) { return sumResults; } + // set up accumulated data structure + const accumulatedData = {}; + parameters.forEach((parameter) => { + if (parameter.accumulateValues) { + accumulatedData[parameter.name] = []; + } + }); + // take the first parameter keyString as the reference const referenceParameter = parameters[0]; const otherParameters = parameters.slice(1); // iterate over the reference telemetry data const referenceTelemetry = dataFrame[referenceParameter.keyString]; referenceTelemetry?.forEach((referenceTelemetryItem) => { + let referenceValue = referenceTelemetryItem[referenceParameter.valueToUse]; + if (referenceParameter.accumulateValues) { + accumulatedData[referenceParameter.name].push(referenceValue); + referenceValue = accumulatedData[referenceParameter.name]; + } + const scope = { - [referenceParameter.name]: referenceTelemetryItem[referenceParameter.valueToUse] + [referenceParameter.name]: referenceValue }; const referenceTime = referenceTelemetryItem[referenceParameter.timeKey]; // iterate over the other parameters to set the scope @@ -75,7 +97,12 @@ function calculate(dataFrame, parameters, expression) { missingData = true; return; } - scope[parameter.name] = otherTelemetry[parameter.valueToUse]; + let otherValue = otherTelemetry[parameter.valueToUse]; + if (parameter.accumulateValues) { + accumulatedData[parameter.name].push(referenceValue); + otherValue = accumulatedData[referenceParameter.name]; + } + scope[parameter.name] = otherValue; }); if (missingData) { return; diff --git a/src/plugins/comps/CompsMetadataProvider.js b/src/plugins/comps/CompsMetadataProvider.js index b12fc34ef2..690b2c999b 100644 --- a/src/plugins/comps/CompsMetadataProvider.js +++ b/src/plugins/comps/CompsMetadataProvider.js @@ -61,6 +61,7 @@ export default class CompsMetadataProvider { key: 'compsOutput', source: 'compsOutput', name: 'Output', + derived: true, formatString: specificCompsManager.getOutputFormat(), hints: { range: 1 diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index bf069fd36d..cb75afe847 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -95,7 +95,7 @@ export default class CompsTelemetryProvider { return; } const expression = specificCompsManager.getExpression(); - const telemetryForComps = specificCompsManager.getFullDataFrame(newTelemetry); + const telemetryForComps = specificCompsManager.getTelemetryForComps(newTelemetry); const parameters = JSON.parse(JSON.stringify(specificCompsManager.getParameters())); if (!expression || !parameters) { return; @@ -103,6 +103,7 @@ export default class CompsTelemetryProvider { const payload = { type: 'calculateSubscription', telemetryForComps, + newTelemetry, expression, parameters, callbackID @@ -134,10 +135,6 @@ export default class CompsTelemetryProvider { ); return () => { delete this.#subscriptionCallbacks[callbackID]; - console.debug( - `🛑 Stopping subscription for ${domainObject.name} with callback ID ${callbackID}. We now have ${Object.keys(this.#subscriptionCallbacks).length} subscribers`, - this.#subscriptionCallbacks - ); specificCompsManager.stopListeningToUnderlyingTelemetry(); specificCompsManager.off('underlyingTelemetryUpdated', boundComputeOnNewTelemetry); }; diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index ec8f1abeab..d75ee003e0 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -95,6 +95,25 @@
{{ parameter.valueToUse }}
+
+ +
Test value @@ -235,6 +254,15 @@ function updateParameters() { applyTestData(); } +function updateAccumulateValues(parameter) { + if (parameter.accumulateValues) { + parameter.testValue = ['']; + } else { + parameter.testValue = ''; + } + updateParameters(); +} + function toggleTestData() { testDataApplied.value = !testDataApplied.value; if (testDataApplied.value) { @@ -270,6 +298,20 @@ function applyTestData() { } return acc; }, {}); + + // see which parameters are misconfigured as non-arrays + const misconfiguredParameterNames = parameters.value + .filter((parameter) => { + return parameter.accumulateValues && !Array.isArray(scope[parameter.name]); + }) + .map((parameter) => parameter.name); + if (misconfiguredParameterNames.length) { + const misconfiguredParameterNamesString = misconfiguredParameterNames.join(', '); + currentTestOutput.value = null; + expressionOutput.value = `Reference "${misconfiguredParameterNamesString}" set to accumulating, but test values aren't arrays.`; + return; + } + try { const testOutput = evaluate(expression.value, scope); const formattedData = getValueFormatter().format(testOutput); diff --git a/src/plugins/plot/configuration/PlotSeries.js b/src/plugins/plot/configuration/PlotSeries.js index 9f4f8329ea..34a1dec1ab 100644 --- a/src/plugins/plot/configuration/PlotSeries.js +++ b/src/plugins/plot/configuration/PlotSeries.js @@ -225,7 +225,13 @@ export default class PlotSeries extends Model { try { const points = await this.openmct.telemetry.request(this.domainObject, options); - const data = this.getSeriesData(); + // if derived, we can't use the old data + let data = this.getSeriesData(); + + if (this.metadata.value(this.get('yKey')).derived) { + data = []; + } + // eslint-disable-next-line you-dont-need-lodash-underscore/concat const newPoints = _(data) .concat(points) From 3f92deb89634e703d94950e978fcfed5f3312c9b Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 10:24:08 +0200 Subject: [PATCH 098/139] add sample size --- src/plugins/comps/CompsManager.js | 3 ++- src/plugins/comps/CompsMathWorker.js | 8 ++++++++ src/plugins/comps/components/CompsView.vue | 14 +++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index b23f8071cd..f25edb8ffa 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -60,7 +60,8 @@ export default class CompsManager extends EventEmitter { valueToUse, testValue: 0, timeMetaData, - accumulateValues: false + accumulateValues: false, + sampleSize: null }); this.emit('parameterAdded', this.#domainObject); } diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 29c2ba4fe2..59efc929dc 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -83,6 +83,14 @@ function calculate(dataFrame, parameters, expression) { accumulatedData[referenceParameter.name].push(referenceValue); referenceValue = accumulatedData[referenceParameter.name]; } + if (referenceParameter.sampleSize) { + // enforce sample size by ensuring referenceValue has the latest n elements + // if we don't have at least the sample size, skip this iteration + if (referenceValue.length < referenceParameter.sampleSize) { + return; + } + referenceValue = referenceValue.slice(-referenceParameter.sampleSize); + } const scope = { [referenceParameter.name]: referenceValue diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index d75ee003e0..3f9ccf19b3 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -102,6 +102,7 @@ ]" >
- Accumulate Values + + Sample Size + From c6806944eb38114e33f2decf83b7fb8d3ed8d67d Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 10:24:57 +0200 Subject: [PATCH 099/139] check if sample size greater than zero --- src/plugins/comps/CompsMathWorker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 59efc929dc..bb7c2ffe6f 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -1,3 +1,4 @@ +import { sampleSize } from 'lodash'; import { evaluate } from 'mathjs'; // eslint-disable-next-line no-undef @@ -83,7 +84,7 @@ function calculate(dataFrame, parameters, expression) { accumulatedData[referenceParameter.name].push(referenceValue); referenceValue = accumulatedData[referenceParameter.name]; } - if (referenceParameter.sampleSize) { + if (referenceParameter.sampleSize && sampleSize > 0) { // enforce sample size by ensuring referenceValue has the latest n elements // if we don't have at least the sample size, skip this iteration if (referenceValue.length < referenceParameter.sampleSize) { From 8e7bfd080dd6def1be2712752a9dea1f6f2e4815 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 12:04:28 +0200 Subject: [PATCH 100/139] ensure number for sample size --- src/plugins/comps/CompsMathWorker.js | 3 +-- src/plugins/comps/components/CompsView.vue | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index bb7c2ffe6f..4831c606a6 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -1,4 +1,3 @@ -import { sampleSize } from 'lodash'; import { evaluate } from 'mathjs'; // eslint-disable-next-line no-undef @@ -84,7 +83,7 @@ function calculate(dataFrame, parameters, expression) { accumulatedData[referenceParameter.name].push(referenceValue); referenceValue = accumulatedData[referenceParameter.name]; } - if (referenceParameter.sampleSize && sampleSize > 0) { + if (referenceParameter.sampleSize && referenceParameter.sampleSize > 0) { // enforce sample size by ensuring referenceValue has the latest n elements // if we don't have at least the sample size, skip this iteration if (referenceValue.length < referenceParameter.sampleSize) { diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 3f9ccf19b3..3acf6a4269 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -121,7 +121,7 @@ v-if="isEditing && parameter.accumulateValues" v-model="parameter.sampleSize" :aria-label="`Sample Size for ${parameter.name}`" - type="text" + type="number" class="c-input--md" @change="updateParameters" /> From 2de628adacf113f78474ad2f525ca902ea09fc0d Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 12:16:02 +0200 Subject: [PATCH 101/139] ensure we have a reference value before we slice --- src/plugins/comps/CompsMathWorker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 4831c606a6..00de8bdd1e 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -13,6 +13,7 @@ onconnect = function (e) { try { if (type === 'calculateRequest') { responseType = 'calculationRequestResult'; + console.debug(`📫 Received new calculation request with callback ID ${callbackID}`); result = calculateRequest(telemetryForComps, parameters, expression); } else if (type === 'calculateSubscription') { responseType = 'calculationSubscriptionResult'; @@ -86,7 +87,7 @@ function calculate(dataFrame, parameters, expression) { if (referenceParameter.sampleSize && referenceParameter.sampleSize > 0) { // enforce sample size by ensuring referenceValue has the latest n elements // if we don't have at least the sample size, skip this iteration - if (referenceValue.length < referenceParameter.sampleSize) { + if (!referenceValue.length || referenceValue.length < referenceParameter.sampleSize) { return; } referenceValue = referenceValue.slice(-referenceParameter.sampleSize); From ba7f2919c002558dc9c281d6a8b1034ebb4b3e88 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 12:36:20 +0200 Subject: [PATCH 102/139] can do derived derived accumulated comps now --- src/plugins/comps/CompsManager.js | 60 +++++++++++++++++++++++----- src/plugins/comps/CompsMathWorker.js | 6 ++- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index f25edb8ffa..0d25a4196c 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -1,5 +1,4 @@ import { EventEmitter } from 'eventemitter3'; -import _ from 'lodash'; export default class CompsManager extends EventEmitter { #openmct; @@ -12,6 +11,8 @@ export default class CompsManager extends EventEmitter { #loaded = false; #compositionLoaded = false; #telemetryProcessors = {}; + #loadVersion = 0; + #currentLoadPromise = null; constructor(openmct, domainObject) { super(); @@ -109,24 +110,61 @@ export default class CompsManager extends EventEmitter { return this.#loaded; } + #haveTelemetryOptionsChanged(telemetryOptions) { + return ( + telemetryOptions.strategy !== this.#telemetryOptions.strategy || + telemetryOptions.size !== this.#telemetryOptions.size || + telemetryOptions.end !== this.#telemetryOptions.end || + telemetryOptions.start !== this.#telemetryOptions.start || + telemetryOptions.duration !== this.#telemetryOptions.duration || + telemetryOptions.filters !== this.#telemetryOptions.filters || + telemetryOptions.domain !== this.#telemetryOptions.domain + ); + } + async load(telemetryOptions) { - if (!_.isEqual(telemetryOptions, this.#telemetryOptions)) { + // Increment the load version to mark a new load operation + const loadVersion = ++this.#loadVersion; + + if (this.#haveTelemetryOptionsChanged(telemetryOptions)) { console.debug( `😩 Reloading comps manager ${this.#domainObject.name} due to telemetry options change.`, telemetryOptions ); this.#destroy(); } + this.#telemetryOptions = telemetryOptions; - if (!this.#compositionLoaded) { - await this.#loadComposition(); - this.#compositionLoaded = true; - } - if (!this.#loaded) { - await this.#startListeningToUnderlyingTelemetry(); - this.#telemetryLoadedPromises = []; - this.#loaded = true; - } + + // Start the load process and store the promise + this.#currentLoadPromise = (async () => { + // Load composition if not already loaded + if (!this.#compositionLoaded) { + await this.#loadComposition(); + // Check if a newer load has been initiated + if (loadVersion !== this.#loadVersion) { + return; + } + this.#compositionLoaded = true; + } + + // Start listening to telemetry if not already done + if (!this.#loaded) { + await this.#startListeningToUnderlyingTelemetry(); + // Check again for newer load + if (loadVersion !== this.#loadVersion) { + return; + } + this.#loaded = true; + console.debug( + `✅ Comps manager ${this.#domainObject.name} is ready.`, + this.#telemetryCollections + ); + } + })(); + + // Await the load process + await this.#currentLoadPromise; } async #startListeningToUnderlyingTelemetry() { diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 00de8bdd1e..8dc8037bb2 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -84,7 +84,11 @@ function calculate(dataFrame, parameters, expression) { accumulatedData[referenceParameter.name].push(referenceValue); referenceValue = accumulatedData[referenceParameter.name]; } - if (referenceParameter.sampleSize && referenceParameter.sampleSize > 0) { + if ( + referenceParameter.accumulateValues && + referenceParameter.sampleSize && + referenceParameter.sampleSize > 0 + ) { // enforce sample size by ensuring referenceValue has the latest n elements // if we don't have at least the sample size, skip this iteration if (!referenceValue.length || referenceValue.length < referenceParameter.sampleSize) { From 7c01a5e0d7da3b94f2112b43646ec185078246a2 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 12:47:03 +0200 Subject: [PATCH 103/139] ensure we are checking for not equal --- src/plugins/comps/CompsManager.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 0d25a4196c..f53c1d4987 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -110,23 +110,11 @@ export default class CompsManager extends EventEmitter { return this.#loaded; } - #haveTelemetryOptionsChanged(telemetryOptions) { - return ( - telemetryOptions.strategy !== this.#telemetryOptions.strategy || - telemetryOptions.size !== this.#telemetryOptions.size || - telemetryOptions.end !== this.#telemetryOptions.end || - telemetryOptions.start !== this.#telemetryOptions.start || - telemetryOptions.duration !== this.#telemetryOptions.duration || - telemetryOptions.filters !== this.#telemetryOptions.filters || - telemetryOptions.domain !== this.#telemetryOptions.domain - ); - } - async load(telemetryOptions) { // Increment the load version to mark a new load operation const loadVersion = ++this.#loadVersion; - if (this.#haveTelemetryOptionsChanged(telemetryOptions)) { + if (!_.isEqual(this.#telemetryOptions, telemetryOptions)) { console.debug( `😩 Reloading comps manager ${this.#domainObject.name} due to telemetry options change.`, telemetryOptions From bf9d5ef4a79c9d86e573e58ab6662f45e1392f22 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 13:20:11 +0200 Subject: [PATCH 104/139] add a few more awaits --- src/plugins/comps/CompsManager.js | 10 +++++++++- src/plugins/comps/CompsMathWorker.js | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index f53c1d4987..68aafca4b0 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -131,6 +131,10 @@ export default class CompsManager extends EventEmitter { await this.#loadComposition(); // Check if a newer load has been initiated if (loadVersion !== this.#loadVersion) { + console.debug( + `🔄 Reloading comps manager in composition wait ${this.#domainObject.name} due to newer load.` + ); + await this.#currentLoadPromise; return; } this.#compositionLoaded = true; @@ -141,13 +145,17 @@ export default class CompsManager extends EventEmitter { await this.#startListeningToUnderlyingTelemetry(); // Check again for newer load if (loadVersion !== this.#loadVersion) { + console.debug( + `🔄 Reloading comps manager in telemetry wait ${this.#domainObject.name} due to newer load.` + ); + await this.#currentLoadPromise; return; } - this.#loaded = true; console.debug( `✅ Comps manager ${this.#domainObject.name} is ready.`, this.#telemetryCollections ); + this.#loaded = true; } })(); diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 8dc8037bb2..606c3b5a3e 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -27,6 +27,7 @@ onconnect = function (e) { } catch (errorInCalculation) { error = errorInCalculation; } + console.debug(`📭 Sending response for callback ID ${callbackID}`, result); port.postMessage({ type: responseType, callbackID, result, error }); }; }; From d6f50567bc16dd0a4935652bcced2df6a16646a3 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 13:32:56 +0200 Subject: [PATCH 105/139] allow blank test values for arrays --- src/plugins/comps/components/CompsView.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 3acf6a4269..093a2d474d 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -135,7 +135,7 @@ :aria-label="`Reference Test Value for ${parameter.name}`" type="text" class="c-input--md" - @change="updateParameters" + @change="updateTestValue(parameter)" /> @@ -275,6 +275,13 @@ function updateAccumulateValues(parameter) { updateParameters(); } +function updateTestValue(parameter) { + if (parameter.accumulateValues && !Array.isArray(parameter.testValue)) { + parameter.testValue = [parameter.testValue]; + } + updateParameters(); +} + function toggleTestData() { testDataApplied.value = !testDataApplied.value; if (testDataApplied.value) { From 85a77699e6239c29ce013dc4f2a4ffbe29e3cf19 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 13:35:46 +0200 Subject: [PATCH 106/139] check for blank test values --- src/plugins/comps/components/CompsView.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 093a2d474d..109733e4c6 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -276,8 +276,8 @@ function updateAccumulateValues(parameter) { } function updateTestValue(parameter) { - if (parameter.accumulateValues && !Array.isArray(parameter.testValue)) { - parameter.testValue = [parameter.testValue]; + if (parameter.accumulateValues && parameter.testValue === '') { + parameter.testValue = []; } updateParameters(); } From 3b06c7749e3e3903b1299cab799d25bcc2361785 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 17:56:02 +0200 Subject: [PATCH 107/139] change to just value --- src/plugins/comps/CompsMathWorker.js | 4 ++-- src/plugins/comps/CompsMetadataProvider.js | 5 ++--- src/plugins/comps/components/CompsView.vue | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 606c3b5a3e..2da09178fe 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -121,8 +121,8 @@ function calculate(dataFrame, parameters, expression) { if (missingData) { return; } - const compsOutput = evaluate(expression, scope); - sumResults.push({ [referenceParameter.timeKey]: referenceTime, compsOutput }); + const value = evaluate(expression, scope); + sumResults.push({ [referenceParameter.timeKey]: referenceTime, value }); }); return sumResults; } diff --git a/src/plugins/comps/CompsMetadataProvider.js b/src/plugins/comps/CompsMetadataProvider.js index 690b2c999b..1b4a489277 100644 --- a/src/plugins/comps/CompsMetadataProvider.js +++ b/src/plugins/comps/CompsMetadataProvider.js @@ -58,9 +58,8 @@ export default class CompsMetadataProvider { const metaDataToReturn = { values: [ { - key: 'compsOutput', - source: 'compsOutput', - name: 'Output', + key: 'value', + name: 'Value', derived: true, formatString: specificCompsManager.getOutputFormat(), hints: { diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 109733e4c6..606bd13613 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -299,7 +299,7 @@ function updateExpression() { function getValueFormatter() { const metaData = openmct.telemetry.getMetadata(domainObject); - const outputMetaDatum = metaData.values().find((metaDatum) => metaDatum.key === 'compsOutput'); + const outputMetaDatum = metaData.values().find((metaDatum) => metaDatum.key === 'value'); return openmct.telemetry.getValueFormatter(outputMetaDatum); } @@ -347,7 +347,7 @@ function telemetryProcessor(data) { return; } // new data will come in as array, so just take the last element - const currentOutput = data[data.length - 1]?.compsOutput; + const currentOutput = data[data.length - 1]?.value; const formattedOutput = getValueFormatter().format(currentOutput); currentCompOutput.value = formattedOutput; } From a83f8a3f56710de6b3716b8779ab7f3e961c276b Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 22:15:26 +0200 Subject: [PATCH 108/139] impute requested data properly --- src/plugins/comps/CompsManager.js | 72 +++++++++++++++++---- src/plugins/comps/CompsMathWorker.js | 1 + src/plugins/comps/CompsTelemetryProvider.js | 4 +- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 68aafca4b0..45695bb17d 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -215,7 +215,62 @@ export default class CompsManager extends EventEmitter { ); } - getTelemetryForComps(newTelemetry) { + #getImputedDataUsingLOCF(datum, telemetryCollection) { + const telemetryCollectionData = telemetryCollection.getAll(); + let insertionPointForNewData = telemetryCollection._sortedIndex(datum); + if (insertionPointForNewData && insertionPointForNewData >= telemetryCollectionData.length) { + insertionPointForNewData = telemetryCollectionData.length - 1; + } + // get the closest datum to the new datum + const closestDatum = telemetryCollectionData[insertionPointForNewData]; + // clone the closest datum and replace the time key with the new time + const imputedData = { + ...closestDatum, + [telemetryCollection.timeKey]: datum[telemetryCollection.timeKey] + }; + return imputedData; + } + + getDataFrameForRequest() { + // Step 1: Collect all unique timestamps from all telemetry collections + const allTimestampsSet = new Set(); + + Object.values(this.#telemetryCollections).forEach((collection) => { + collection.getAll().forEach((dataPoint) => { + allTimestampsSet.add(dataPoint.timestamp); + }); + }); + + // Convert the set to a sorted array + const allTimestamps = Array.from(allTimestampsSet).sort((a, b) => a - b); + + // Step 2: Initialize the result object + const telemetryForComps = {}; + + // Step 3: Iterate through each telemetry collection to align data + Object.keys(this.#telemetryCollections).forEach((keyString) => { + const telemetryCollection = this.#telemetryCollections[keyString]; + const alignedValues = []; + + // Iterate through each common timestamp + allTimestamps.forEach((timestamp) => { + const timeKey = telemetryCollection.timeKey; + const fakeData = { [timeKey]: timestamp }; + const imputedDatum = this.#getImputedDataUsingLOCF(fakeData, telemetryCollection); + if (imputedDatum) { + alignedValues.push(imputedDatum); + } else { + console.debug(`🚨 Missing data for ${keyString} at ${timestamp}`); + } + }); + + telemetryForComps[keyString] = alignedValues; + }); + + return telemetryForComps; + } + + getDataFrameForSubscription(newTelemetry) { const telemetryForComps = {}; const newTelemetryKey = Object.keys(newTelemetry)[0]; const newTelemetryParameter = this.#getParameterForKeyString(newTelemetryKey); @@ -247,16 +302,9 @@ export default class CompsManager extends EventEmitter { newTelemetryData.forEach((newDatum) => { otherTelemetryKeysNotAccumulating.forEach((otherKeyString) => { const otherCollection = this.#telemetryCollections[otherKeyString]; - // otherwise we need to find the closest datum to the new datum - let insertionPointForNewData = otherCollection._sortedIndex(newDatum); - const otherCollectionData = otherCollection.getAll(); - if (insertionPointForNewData && insertionPointForNewData >= otherCollectionData.length) { - insertionPointForNewData = otherCollectionData.length - 1; - } - // get the closest datum to the new datum - const closestDatum = otherCollectionData[insertionPointForNewData]; - if (closestDatum) { - telemetryForComps[otherKeyString].push(closestDatum); + const imputedDatum = this.#getImputedDataUsingLOCF(newDatum, otherCollection); + if (imputedDatum) { + telemetryForComps[otherKeyString].push(imputedDatum); } }); }); @@ -272,7 +320,7 @@ export default class CompsManager extends EventEmitter { this.deleteParameter(keyString); }; - requestUnderlyingTelemetry() { + #requestUnderlyingTelemetry() { const underlyingTelemetry = {}; Object.keys(this.#telemetryCollections).forEach((collectionKey) => { const collection = this.#telemetryCollections[collectionKey]; diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 2da09178fe..52628fa8d8 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -119,6 +119,7 @@ function calculate(dataFrame, parameters, expression) { scope[parameter.name] = otherValue; }); if (missingData) { + console.debug('🤦‍♂️ Missing data for some parameters, skipping calculation'); return; } const value = evaluate(expression, scope); diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index cb75afe847..4c4f710b85 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -64,7 +64,7 @@ export default class CompsTelemetryProvider { specificCompsManager.load(options).then(() => { const callbackID = this.#getCallbackID(); const telemetryForComps = JSON.parse( - JSON.stringify(specificCompsManager.requestUnderlyingTelemetry()) + JSON.stringify(specificCompsManager.getDataFrameForRequest()) ); const expression = specificCompsManager.getExpression(); const parameters = JSON.parse(JSON.stringify(specificCompsManager.getParameters())); @@ -95,7 +95,7 @@ export default class CompsTelemetryProvider { return; } const expression = specificCompsManager.getExpression(); - const telemetryForComps = specificCompsManager.getTelemetryForComps(newTelemetry); + const telemetryForComps = specificCompsManager.getDataFrameForSubscription(newTelemetry); const parameters = JSON.parse(JSON.stringify(specificCompsManager.getParameters())); if (!expression || !parameters) { return; From 4de03542f871d0ca2965ab6f6b8c118105779cb5 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 9 Oct 2024 22:15:26 +0200 Subject: [PATCH 109/139] impute requested data properly --- src/plugins/comps/CompsManager.js | 72 +++++++++++++++++---- src/plugins/comps/CompsMathWorker.js | 1 + src/plugins/comps/CompsTelemetryProvider.js | 4 +- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 68aafca4b0..45695bb17d 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -215,7 +215,62 @@ export default class CompsManager extends EventEmitter { ); } - getTelemetryForComps(newTelemetry) { + #getImputedDataUsingLOCF(datum, telemetryCollection) { + const telemetryCollectionData = telemetryCollection.getAll(); + let insertionPointForNewData = telemetryCollection._sortedIndex(datum); + if (insertionPointForNewData && insertionPointForNewData >= telemetryCollectionData.length) { + insertionPointForNewData = telemetryCollectionData.length - 1; + } + // get the closest datum to the new datum + const closestDatum = telemetryCollectionData[insertionPointForNewData]; + // clone the closest datum and replace the time key with the new time + const imputedData = { + ...closestDatum, + [telemetryCollection.timeKey]: datum[telemetryCollection.timeKey] + }; + return imputedData; + } + + getDataFrameForRequest() { + // Step 1: Collect all unique timestamps from all telemetry collections + const allTimestampsSet = new Set(); + + Object.values(this.#telemetryCollections).forEach((collection) => { + collection.getAll().forEach((dataPoint) => { + allTimestampsSet.add(dataPoint.timestamp); + }); + }); + + // Convert the set to a sorted array + const allTimestamps = Array.from(allTimestampsSet).sort((a, b) => a - b); + + // Step 2: Initialize the result object + const telemetryForComps = {}; + + // Step 3: Iterate through each telemetry collection to align data + Object.keys(this.#telemetryCollections).forEach((keyString) => { + const telemetryCollection = this.#telemetryCollections[keyString]; + const alignedValues = []; + + // Iterate through each common timestamp + allTimestamps.forEach((timestamp) => { + const timeKey = telemetryCollection.timeKey; + const fakeData = { [timeKey]: timestamp }; + const imputedDatum = this.#getImputedDataUsingLOCF(fakeData, telemetryCollection); + if (imputedDatum) { + alignedValues.push(imputedDatum); + } else { + console.debug(`🚨 Missing data for ${keyString} at ${timestamp}`); + } + }); + + telemetryForComps[keyString] = alignedValues; + }); + + return telemetryForComps; + } + + getDataFrameForSubscription(newTelemetry) { const telemetryForComps = {}; const newTelemetryKey = Object.keys(newTelemetry)[0]; const newTelemetryParameter = this.#getParameterForKeyString(newTelemetryKey); @@ -247,16 +302,9 @@ export default class CompsManager extends EventEmitter { newTelemetryData.forEach((newDatum) => { otherTelemetryKeysNotAccumulating.forEach((otherKeyString) => { const otherCollection = this.#telemetryCollections[otherKeyString]; - // otherwise we need to find the closest datum to the new datum - let insertionPointForNewData = otherCollection._sortedIndex(newDatum); - const otherCollectionData = otherCollection.getAll(); - if (insertionPointForNewData && insertionPointForNewData >= otherCollectionData.length) { - insertionPointForNewData = otherCollectionData.length - 1; - } - // get the closest datum to the new datum - const closestDatum = otherCollectionData[insertionPointForNewData]; - if (closestDatum) { - telemetryForComps[otherKeyString].push(closestDatum); + const imputedDatum = this.#getImputedDataUsingLOCF(newDatum, otherCollection); + if (imputedDatum) { + telemetryForComps[otherKeyString].push(imputedDatum); } }); }); @@ -272,7 +320,7 @@ export default class CompsManager extends EventEmitter { this.deleteParameter(keyString); }; - requestUnderlyingTelemetry() { + #requestUnderlyingTelemetry() { const underlyingTelemetry = {}; Object.keys(this.#telemetryCollections).forEach((collectionKey) => { const collection = this.#telemetryCollections[collectionKey]; diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 2da09178fe..52628fa8d8 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -119,6 +119,7 @@ function calculate(dataFrame, parameters, expression) { scope[parameter.name] = otherValue; }); if (missingData) { + console.debug('🤦‍♂️ Missing data for some parameters, skipping calculation'); return; } const value = evaluate(expression, scope); diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index cb75afe847..4c4f710b85 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -64,7 +64,7 @@ export default class CompsTelemetryProvider { specificCompsManager.load(options).then(() => { const callbackID = this.#getCallbackID(); const telemetryForComps = JSON.parse( - JSON.stringify(specificCompsManager.requestUnderlyingTelemetry()) + JSON.stringify(specificCompsManager.getDataFrameForRequest()) ); const expression = specificCompsManager.getExpression(); const parameters = JSON.parse(JSON.stringify(specificCompsManager.getParameters())); @@ -95,7 +95,7 @@ export default class CompsTelemetryProvider { return; } const expression = specificCompsManager.getExpression(); - const telemetryForComps = specificCompsManager.getTelemetryForComps(newTelemetry); + const telemetryForComps = specificCompsManager.getDataFrameForSubscription(newTelemetry); const parameters = JSON.parse(JSON.stringify(specificCompsManager.getParameters())); if (!expression || !parameters) { return; From 3b78d4d2bfea6b564ec1911fdd3dba52576cc4a4 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 10 Oct 2024 09:38:34 +0200 Subject: [PATCH 110/139] fix output and add accumulation label --- src/plugins/comps/CompsManager.js | 2 +- src/plugins/comps/components/CompsView.vue | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 45695bb17d..ecac724933 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -62,7 +62,7 @@ export default class CompsManager extends EventEmitter { testValue: 0, timeMetaData, accumulateValues: false, - sampleSize: null + sampleSize: 10 }); this.emit('parameterAdded', this.#domainObject); } diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 606bd13613..f34648a5dd 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -113,6 +113,9 @@ aria-label="Toggle Parameter Accumulation" > +
+ - accumulating values with sample size {{ parameter.sampleSize }} +
Sample Size { const telemetryOptions = { - size: 1, - strategy: 'latest' + strategy: 'minmax' }; outputTelemetryCollection = openmct.telemetry.requestCollection(domainObject, telemetryOptions); outputTelemetryCollection.on('add', telemetryProcessor); From d5ee430f8b2aa3775d3f54c1c9d643c124f52926 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 10 Oct 2024 10:31:16 +0200 Subject: [PATCH 111/139] update output when comp changes --- src/plugins/comps/CompsManager.js | 9 ++++++++- src/plugins/comps/components/CompsView.vue | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index ecac724933..f0b649a2c4 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -345,9 +345,16 @@ export default class CompsManager extends EventEmitter { this.emit('underlyingTelemetryUpdated', { [keyString]: newTelemetry }); }; + reload() { + this.#destroy(); + return this.load(this.#telemetryOptions); + } + clearData(telemetryLoadedPromise) { this.#loaded = false; - this.#telemetryLoadedPromises.push(telemetryLoadedPromise); + if (telemetryLoadedPromise) { + this.#telemetryLoadedPromises.push(telemetryLoadedPromise); + } } setOutputFormat(outputFormat) { diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index f34648a5dd..394cf212be 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -266,6 +266,7 @@ function updateParameters() { openmct.objects.mutate(domainObject, `configuration.comps.parameters`, parameters.value); compsManager.setDomainObject(domainObject); applyTestData(); + reload(); } function updateAccumulateValues(parameter) { @@ -297,6 +298,7 @@ function updateExpression() { openmct.objects.mutate(domainObject, `configuration.comps.expression`, expression.value); compsManager.setDomainObject(domainObject); applyTestData(); + reload(); } function getValueFormatter() { @@ -354,6 +356,11 @@ function telemetryProcessor(data) { currentCompOutput.value = formattedOutput; } +function reload() { + clearData(); + outputTelemetryCollection._requestHistoricalTelemetry(); +} + function clearData() { currentCompOutput.value = null; } From 6710ad0d4cd1c4efc9fef4bdb010f008c1cb9098 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 10 Oct 2024 10:34:17 +0200 Subject: [PATCH 112/139] remove unused function --- src/plugins/comps/CompsManager.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index f0b649a2c4..50b0d0f354 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -345,11 +345,6 @@ export default class CompsManager extends EventEmitter { this.emit('underlyingTelemetryUpdated', { [keyString]: newTelemetry }); }; - reload() { - this.#destroy(); - return this.load(this.#telemetryOptions); - } - clearData(telemetryLoadedPromise) { this.#loaded = false; if (telemetryLoadedPromise) { From 7d46afbceda6ff48dfd1e0198167a4916e4c6d83 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 10 Oct 2024 11:15:04 +0200 Subject: [PATCH 113/139] add placeholder --- src/plugins/comps/components/CompsInspectorView.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/comps/components/CompsInspectorView.vue b/src/plugins/comps/components/CompsInspectorView.vue index 9ace9cc005..ff02eb94e7 100644 --- a/src/plugins/comps/components/CompsInspectorView.vue +++ b/src/plugins/comps/components/CompsInspectorView.vue @@ -33,6 +33,7 @@ v-model="inputFormatValue" type="text" class="c-input--flex" + placeholder="e.g. %0.2f" @change="changeInputFormat()" /> From f4c2b79fdb20d2610aded401f2d890f09b85a7bb Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Thu, 10 Oct 2024 20:12:52 -0500 Subject: [PATCH 114/139] Update condition set metadata --- .../condition/ConditionSetMetadataProvider.js | 15 ++++++----- .../condition/components/ConditionItem.vue | 27 ++++++++++++++++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/plugins/condition/ConditionSetMetadataProvider.js b/src/plugins/condition/ConditionSetMetadataProvider.js index 52d6d3ceb7..21e5c1bb02 100644 --- a/src/plugins/condition/ConditionSetMetadataProvider.js +++ b/src/plugins/condition/ConditionSetMetadataProvider.js @@ -43,11 +43,13 @@ export default class ConditionSetMetadataProvider { } getMetadata(domainObject) { - const enumerations = domainObject.configuration.conditionCollection.map((condition, index) => { - return { - string: condition.configuration.output, - value: index - }; + const format = { formatString: '%0.2f' }; + domainObject.configuration.conditionCollection.forEach((condition, index) => { + if (condition?.configuration?.valueMetadata?.enumerations) { + delete format.formatString; + format.format = 'enum'; + format.enumerations = condition?.configuration?.valueMetadata?.enumerations; + } }); const resultEnum = [ @@ -67,8 +69,7 @@ export default class ConditionSetMetadataProvider { key: 'value', source: 'output', name: 'Value', - format: 'enum', - enumerations: enumerations, + ...format, hints: { range: 1 } diff --git a/src/plugins/condition/components/ConditionItem.vue b/src/plugins/condition/components/ConditionItem.vue index c47969b3c4..9df75b7976 100644 --- a/src/plugins/condition/components/ConditionItem.vue +++ b/src/plugins/condition/components/ConditionItem.vue @@ -294,7 +294,8 @@ export default { criterionIndex: 0, draggingOver: false, isDefault: this.condition.isDefault, - telemetryMetadataOptions: {} + telemetryMetadataOptions: {}, + telemetryFormats: new Map() }; }, computed: { @@ -331,9 +332,10 @@ export default { watch: { condition: { handler() { - if (this.condition.configuration.output !== TELEMETRY_VALUE) { - this.condition.configuration.outputTelemetry = null; - this.condition.configuration.outputMetadata = null; + const config = this.condition?.configuration; + if (config?.output !== TELEMETRY_VALUE) { + config.outputTelemetry = null; + config.outputMetadata = null; } }, deep: true @@ -374,6 +376,16 @@ export default { this.persist(); }, + getOutputMetadata() { + const config = this.condition.configuration; + let valueMetadata; + if (config?.outputTelemetry && config?.outputMetadata) { + valueMetadata = this.telemetryFormats.get( + `${config?.outputTelemetry}_${config?.outputMetadata}` + ); + } + return valueMetadata; + }, addCriteria() { const criteriaObject = { id: uuid(), @@ -456,6 +468,10 @@ export default { this.persist(); }, persist() { + const valueMetadata = this.getOutputMetadata(); + if (valueMetadata) { + this.condition.configuration.valueMetadata = valueMetadata; + } this.$emit('update-condition', { condition: this.condition }); @@ -469,6 +485,9 @@ export default { let telemetryMetadata = this.openmct.telemetry.getMetadata(telemetryObject); if (telemetryMetadata) { this.telemetryMetadataOptions[id] = telemetryMetadata.values().slice(); + telemetryMetadata.values().forEach((telemetryValue) => { + this.telemetryFormats.set(`${id}_${telemetryValue.key}`, telemetryValue); + }); } else { this.telemetryMetadataOptions[id] = []; } From bd3f00c2c6fa7d1afaded9dc5ea32ada7c0b7a37 Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Thu, 10 Oct 2024 20:35:22 -0500 Subject: [PATCH 115/139] Fix zero issue --- .../condition/HistoricalTelemetryProvider.js | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index fb375975d7..1b9d4b46c0 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -41,7 +41,7 @@ export default class HistoricalTelemetryProvider { const outputTelemetryID = this.openmct.objects.makeKeyString(outputTelemetry); const outputTelemetryData = telemetryData.get(outputTelemetryID); output.telemetry = outputTelemetryData; - output.value = outputTelemetryData?.[outputMetadata] || undefined; + output.value = outputTelemetryData?.[outputMetadata]; output.condition = condition; } else if (conditionConfiguration?.output) { output.telemetry = null; @@ -58,17 +58,8 @@ export default class HistoricalTelemetryProvider { const historicalTelemetryPoolPromises = []; conditionCollection.forEach((condition, index) => { - console.log('-------------------------'); - console.log(condition); - const { id } = condition; - const { criteria, output, outputTelemetry, outputMetadata } = condition.configuration; + const { criteria, outputTelemetry } = condition.configuration; const inputTelemetry = criteria?.[0]?.telemetry; - console.log(id); - console.log(criteria); - console.log(output); - console.log(outputMetadata); - console.log('inputTelemetry', inputTelemetry); - console.log('outputTelemetry', outputTelemetry); conditionCollectionMap.set(condition?.id, condition); if (inputTelemetry) { const inputTelemetryId = this.openmct.objects.makeKeyString(inputTelemetry); @@ -241,12 +232,12 @@ export default class HistoricalTelemetryProvider { ); console.log('*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣'); - console.log(historicalTelemetriesPool); - console.log(this.historicalTelemetryPoolMap); - console.log(inputTelemetries); - console.log(outputTelemetries); - console.log(historicalTelemetryDateMap); - console.log(outputTelemetryDateMap); + console.log('historicalTelemetriesPool', historicalTelemetriesPool); + console.log('historicalTelemetryPoolMap', this.historicalTelemetryPoolMap); + console.log('inputTelemetries', inputTelemetries); + console.log('outputTelemetries', outputTelemetries); + console.log('historicalTelemetryDateMap', historicalTelemetryDateMap); + console.log('outputTelemetryDateMap', outputTelemetryDateMap); return outputTelemetryDateMap; } @@ -258,7 +249,7 @@ export default class HistoricalTelemetryProvider { } async getHistoricalData() { - console.log('getHistoricalData'); + console.log('🌟🌟🌟🌟🌟🌟🌟🌟🌟 getHistoricalData 🌟🌟🌟🌟🌟🌟🌟🌟🌟'); this.setTimeBounds(this.openmct.time.getBounds()); const outputTelemetryMap = await this.getHistoricalInputsByDate(); const formattedOutputTelemetry = this.formatOutputData(outputTelemetryMap); From cba2056f72a3bb8618da3252802a5af15f3017c0 Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Fri, 11 Oct 2024 00:57:54 -0500 Subject: [PATCH 116/139] Try removing the default format for better data inspection --- src/plugins/condition/ConditionSetMetadataProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/condition/ConditionSetMetadataProvider.js b/src/plugins/condition/ConditionSetMetadataProvider.js index 21e5c1bb02..dbaadfff12 100644 --- a/src/plugins/condition/ConditionSetMetadataProvider.js +++ b/src/plugins/condition/ConditionSetMetadataProvider.js @@ -43,7 +43,7 @@ export default class ConditionSetMetadataProvider { } getMetadata(domainObject) { - const format = { formatString: '%0.2f' }; + const format = {}; domainObject.configuration.conditionCollection.forEach((condition, index) => { if (condition?.configuration?.valueMetadata?.enumerations) { delete format.formatString; From d6036a7e104f0e76a8b77c51df37db7ac59f765c Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 11 Oct 2024 17:09:24 +0200 Subject: [PATCH 117/139] updating with historical data --- src/plugins/condition/ConditionManager.js | 4 +- .../condition/ConditionSetMetadataProvider.js | 2 + .../condition/HistoricalTelemetryProvider.js | 474 +++++++++--------- 3 files changed, 228 insertions(+), 252 deletions(-) diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 9b9a1a27a1..7d9f404ac2 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -328,15 +328,13 @@ export default class ConditionManager extends EventEmitter { if (!this.conditionSetDomainObject.configuration.shouldFetchHistorical) { return []; } - let historicalTelemetry = new HistoricalTelemetryProvider( + const historicalTelemetry = new HistoricalTelemetryProvider( this.openmct, - this.telemetryObjects, this.conditions, this.conditionSetDomainObject, options ); const historicalData = historicalTelemetry.getHistoricalData(); - historicalTelemetry = null; return historicalData; } diff --git a/src/plugins/condition/ConditionSetMetadataProvider.js b/src/plugins/condition/ConditionSetMetadataProvider.js index dbaadfff12..25c017b39e 100644 --- a/src/plugins/condition/ConditionSetMetadataProvider.js +++ b/src/plugins/condition/ConditionSetMetadataProvider.js @@ -69,6 +69,7 @@ export default class ConditionSetMetadataProvider { key: 'value', source: 'output', name: 'Value', + derived: true, ...format, hints: { range: 1 @@ -77,6 +78,7 @@ export default class ConditionSetMetadataProvider { { key: 'result', source: 'result', + derived: true, name: 'Result', format: 'enum', enumerations: resultEnum, diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index 1b9d4b46c0..7b6bbe1bd3 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -1,276 +1,252 @@ export default class HistoricalTelemetryProvider { - constructor(openmct, telemetryObjects, conditions, conditionSetDomainObject, options) { - this.openmct = openmct; - this.telemetryObjects = telemetryObjects; - this.bounds = { start: null, end: null }; - this.telemetryList = []; - this.conditions = conditions; - this.conditionSetDomainObject = conditionSetDomainObject; - this.historicalTelemetryPoolMap = new Map(); - this.historicalTelemetryDateMap = new Map(); - this.index = 0; - this.options = options; + #telemetryOptions; + #telemetryObjects = {}; + #conditions; + #conditionSetDomainObject; + #openmct; + #telemetryCollections = {}; + #composition; + #outputTelemetryDetails = {}; + + constructor(openmct, conditions, conditionSetDomainObject, telemetryOptions) { + this.#openmct = openmct; + this.#conditions = conditions; + this.#conditionSetDomainObject = conditionSetDomainObject; + this.#telemetryOptions = telemetryOptions; + this.addTelemetryObject = this.addTelemetryObject.bind(this); + this.removeTelemetryObject = this.removeTelemetryObject.bind(this); } - setTimeBounds(bounds) { - this.bounds = bounds; + #evaluateTrueCondition() { + return null; } - async refreshHistoricalTelemetry(domainObject, identifier) { - console.log('refreshHistoricalTelemetry'); - if (!domainObject && identifier) { - domainObject = await this.openmct.objects.get(identifier); + #getInputTelemetry(conditionCriteria, dataFrame, timestamp) { + if (conditionCriteria?.telemetry === 'all') { + // if the criteria is 'all', return all telemetry data + const allTelemetry = []; + Object.keys(dataFrame).forEach((key) => { + const telemetryData = dataFrame[key][timestamp]; + telemetryData.id = key; + if (telemetryData) { + allTelemetry.push(telemetryData); + } + }); + return allTelemetry; } - const id = this.openmct.objects.makeKeyString(domainObject.identifier); - const telemetryOptions = { ...this.bounds, ...this.options }; - const historicalTelemetry = await this.openmct.telemetry.request( - domainObject, - telemetryOptions + if (!conditionCriteria?.telemetry) { + console.debug('🚨 Missing telemetry key in condition criteria - are we the default?'); + return null; + } + const conditionInputTelemetryKeyString = this.#openmct.objects.makeKeyString( + conditionCriteria?.telemetry ); - this.historicalTelemetryPoolMap.set(id, { domainObject, historicalTelemetry }); - return { domainObject, historicalTelemetry }; - } - evaluateTrueCondition(historicalDateMap, timestamp, condition, conditionCollectionMap) { - const telemetryData = historicalDateMap.get(timestamp); - const conditionConfiguration = conditionCollectionMap.get(condition.id)?.configuration; - const { outputTelemetry, outputMetadata } = conditionConfiguration; - let output = {}; - output.result = true; - if (outputTelemetry) { - const outputTelemetryID = this.openmct.objects.makeKeyString(outputTelemetry); - const outputTelemetryData = telemetryData.get(outputTelemetryID); - output.telemetry = outputTelemetryData; - output.value = outputTelemetryData?.[outputMetadata]; - output.condition = condition; - } else if (conditionConfiguration?.output) { - output.telemetry = null; - output.value = conditionConfiguration?.output; - output.condition = condition; + const inputTelemetryByDate = dataFrame[conditionInputTelemetryKeyString]; + if (!inputTelemetryByDate) { + console.debug(`🚨 Missing ALL data for ${conditionInputTelemetryKeyString}`); + return null; } - return output; + const specificDatum = inputTelemetryByDate[timestamp]; + + if (!specificDatum) { + console.debug(`🚨 Missing data for ${conditionInputTelemetryKeyString} at ${timestamp}`); + return null; + } + specificDatum.id = conditionInputTelemetryKeyString; + return specificDatum; } - async getAllTelemetries(conditionCollection) { - const conditionCollectionMap = new Map(); - const inputTelemetries = []; - const outputTelemetries = []; - const historicalTelemetryPoolPromises = []; - - conditionCollection.forEach((condition, index) => { - const { criteria, outputTelemetry } = condition.configuration; - const inputTelemetry = criteria?.[0]?.telemetry; - conditionCollectionMap.set(condition?.id, condition); - if (inputTelemetry) { - const inputTelemetryId = this.openmct.objects.makeKeyString(inputTelemetry); - if (![...inputTelemetries, ...outputTelemetries].includes(inputTelemetryId)) { - historicalTelemetryPoolPromises.push( - this.refreshHistoricalTelemetry(null, inputTelemetry) - ); - } - inputTelemetries.push(inputTelemetryId); - } else { - inputTelemetries.push(null); - } - if (outputTelemetry) { - if (![...inputTelemetries, ...outputTelemetries].includes(outputTelemetry)) { - historicalTelemetryPoolPromises.push( - this.refreshHistoricalTelemetry(null, outputTelemetry) - ); - } - outputTelemetries.push(outputTelemetry); - } else { - outputTelemetries.push(null); - } - }); - - const historicalTelemetriesPool = await Promise.all(historicalTelemetryPoolPromises); - return { - historicalTelemetriesPool, - inputTelemetries, - outputTelemetries, - conditionCollectionMap + #formatDatumForOutput(datum, metadata) { + const formattedDatum = { + ...datum }; + formattedDatum.output = datum[metadata]; + return formattedDatum; } - sortTelemetriesByDate(historicalTelemetriesPool) { - const historicalTelemetryDateMap = new Map(); - historicalTelemetriesPool.forEach((historicalTelemetryList) => { - const { historicalTelemetry, domainObject } = historicalTelemetryList; - const { identifier } = domainObject; - const telemetryIdentifier = this.openmct.objects.makeKeyString(identifier); - historicalTelemetry.forEach((historicalTelemetryItem) => { - if (!historicalTelemetryDateMap.get(historicalTelemetryItem.utc)) { - const telemetryMap = new Map(); - telemetryMap.set(telemetryIdentifier, historicalTelemetryItem); - historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap); - } else { - const telemetryMap = historicalTelemetryDateMap.get(historicalTelemetryItem.utc); - telemetryMap.set(telemetryIdentifier, historicalTelemetryItem); - historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap); + #computeHistoricalDatum(timestamp, dataFrame) { + for (let conditionIndex = 0; conditionIndex < this.#conditions.length; conditionIndex++) { + const condition = this.#conditions[conditionIndex]; + const { id } = condition; + const conditionCriteria = condition.criteria?.[0]; + let result = false; + if (conditionCriteria) { + const inputTelemetry = this.#getInputTelemetry(conditionCriteria, dataFrame, timestamp); + result = conditionCriteria.computeResult({ id, ...inputTelemetry }); + } else { + // default criteria is 'all' + result = true; + } + if (result) { + // generate the output telemetry object if available + const outputTelmetryDetail = this.#outputTelemetryDetails[id]; + if (outputTelmetryDetail) { + const outputTelmetryDatum = + dataFrame[outputTelmetryDetail.outputTelemetryKeyString][timestamp]; + const formattedDatum = this.#formatDatumForOutput( + outputTelmetryDatum, + outputTelmetryDetail.outputMetadata + ); + return formattedDatum; } - }); - }); - return historicalTelemetryDateMap; - } - - async sortTelemetriesInWorker(historicalTelemetriesPool) { - const sortedTelemetries = await this.startWorker('sortTelemetries', { - historicalTelemetriesPool - }); - return sortedTelemetries; - } - - async startWorker(type, data) { - // eslint-disable-next-line no-undef - const workerUrl = `${this.openmct.getAssetPath()}${__OPENMCT_ROOT_RELATIVE__}historicalTelemetryWorker.js`; - const worker = new Worker(workerUrl); - - try { - const result = await this.getDataFromWorker(worker, type, data); - return result; - } catch (error) { - console.error('Error in condition manager getHistoricalData:', error); - throw error; - } finally { - worker.terminate(); + } } } - getDataFromWorker(worker, type, data) { - return new Promise((resolve, reject) => { - worker.onmessage = (e) => { - if (e.data.type === 'result') { - resolve(e.data.data); - } else if (e.data.type === 'error') { - reject(new Error(e.data.error)); - } - }; - - worker.onerror = (error) => { - reject(error); - }; - - worker.postMessage({ - type, - data - }); - }); - } - - evaluateConditionsByDate(historicalTelemetryDateMap, conditionCollectionMap) { - const outputTelemetryDateMap = new Map(); - historicalTelemetryDateMap.forEach((historicalTelemetryMap, timestamp) => { - let isConditionValid = false; - const evaluatedConditions = []; - this.conditions.forEach((condition) => { - if (isConditionValid) { - return; - } - const { id } = condition; - const conditionMetadata = { condition }; - const conditionCriteria = condition.criteria[0]; - let result; - if (conditionCriteria?.telemetry) { - const conditionInputTelemetryId = this.openmct.objects.makeKeyString( - conditionCriteria.telemetry - ); - const inputTelemetry = historicalTelemetryMap.get(conditionInputTelemetryId); - conditionMetadata.inputTelemetry = inputTelemetry; - result = conditionCriteria.computeResult({ - id, - ...inputTelemetry - }); - } else if (!conditionCriteria) { - const conditionDetails = conditionCollectionMap.get(id); - const { isDefault } = conditionDetails; - const conditionConfiguration = conditionDetails?.configuration; - const { output } = conditionConfiguration; - if (isDefault) { - const conditionOutput = { - condition, - telemetry: null, - value: output, - result: false, - isDefault: true - }; - outputTelemetryDateMap.set(timestamp, conditionOutput); - } - } - conditionMetadata.result = result; - evaluatedConditions.push(conditionMetadata); - if (result === true) { - isConditionValid = true; - const conditionOutput = this.evaluateTrueCondition( - historicalTelemetryDateMap, - timestamp, - condition, - conditionCollectionMap - ); - outputTelemetryDateMap.set(timestamp, conditionOutput); - } - }); - }); - return outputTelemetryDateMap; - } - - async getHistoricalInputsByDate() { - const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection; - - const { - historicalTelemetriesPool, - inputTelemetries, - outputTelemetries, - conditionCollectionMap - } = await this.getAllTelemetries(conditionCollection); - - const historicalTelemetryDateMap = - await this.sortTelemetriesInWorker(historicalTelemetriesPool); - const outputTelemetryDateMap = this.evaluateConditionsByDate( - historicalTelemetryDateMap, - conditionCollectionMap + async #loadTelemetryCollections() { + await Promise.all( + Object.entries(this.#telemetryObjects).map(async ([keystring, telemetryObject]) => { + const telemetryCollection = this.#openmct.telemetry.requestCollection( + telemetryObject, + this.#telemetryOptions + ); + await telemetryCollection.load(); + this.#telemetryCollections[keystring] = telemetryCollection; + }) ); - - console.log('*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣'); - console.log('historicalTelemetriesPool', historicalTelemetriesPool); - console.log('historicalTelemetryPoolMap', this.historicalTelemetryPoolMap); - console.log('inputTelemetries', inputTelemetries); - console.log('outputTelemetries', outputTelemetries); - console.log('historicalTelemetryDateMap', historicalTelemetryDateMap); - console.log('outputTelemetryDateMap', outputTelemetryDateMap); - - return outputTelemetryDateMap; } - addItemToHistoricalTelemetryMap(telemetryMap, item, type, index) { - if (type === 'input') { - telemetryMap.set(); + #computeHistoricalData(dataFrame) { + const historicalData = []; + if (Object.keys(dataFrame).length === 0) { + // if we have no telemetry data, return an empty object + return historicalData; } + + // use the first telemetry collection as the reference for the frame + const referenceTelemetryKeyString = Object.keys(dataFrame)[0]; + const referenceTelemetryCollection = this.#telemetryCollections[referenceTelemetryKeyString]; + const referenceTelemetryData = referenceTelemetryCollection.getAll(); + referenceTelemetryData.forEach((datum) => { + const timestamp = datum[referenceTelemetryCollection.timeKey]; + const historicalDatum = this.#computeHistoricalDatum(timestamp, dataFrame); + historicalData.push(historicalDatum); + }); + return historicalData; + } + + #getImputedDataUsingLOCF(datum, telemetryCollection) { + const telemetryCollectionData = telemetryCollection.getAll(); + let insertionPointForNewData = telemetryCollection._sortedIndex(datum); + if (insertionPointForNewData && insertionPointForNewData >= telemetryCollectionData.length) { + insertionPointForNewData = telemetryCollectionData.length - 1; + } + // get the closest datum to the new datum + const closestDatum = telemetryCollectionData[insertionPointForNewData]; + // clone the closest datum and replace the time key with the new time + const imputedData = { + ...closestDatum, + [telemetryCollection.timeKey]: datum[telemetryCollection.timeKey] + }; + return imputedData; + } + + #createDataFrame() { + // Step 1: Collect all unique timestamps from all telemetry collections + const allTimestampsSet = new Set(); + + Object.values(this.#telemetryCollections).forEach((collection) => { + collection.getAll().forEach((dataPoint) => { + const timeKey = collection.timeKey; + allTimestampsSet.add(dataPoint[timeKey]); + }); + }); + + // Convert the set to a sorted array + const allTimestamps = Array.from(allTimestampsSet).sort((a, b) => a - b); + + // Step 2: Initialize the result object + const dataFrame = {}; + + // Step 3: Iterate through each telemetry collection to align data + Object.keys(this.#telemetryCollections)?.forEach((keyString) => { + const telemetryCollection = this.#telemetryCollections[keyString]; + const alignedValues = {}; + + // Iterate through each common timestamp + allTimestamps.forEach((timestamp) => { + const timeKey = telemetryCollection.timeKey; + const fakeData = { [timeKey]: timestamp }; + const imputedDatum = this.#getImputedDataUsingLOCF(fakeData, telemetryCollection); + if (imputedDatum) { + alignedValues[timestamp] = imputedDatum; + } else { + console.debug(`🚨 Missing data for ${keyString} at ${timestamp}`); + } + }); + + dataFrame[keyString] = alignedValues; + }); + return dataFrame; + } + + addTelemetryObject(telemetryObjectToAdd) { + const keyString = this.#openmct.objects.makeKeyString(telemetryObjectToAdd.identifier); + this.#telemetryObjects[keyString] = telemetryObjectToAdd; + } + + removeTelemetryObject(telemetryObjectToRemove) { + const keyStringToRemove = this.#openmct.objects.makeKeyString( + telemetryObjectToRemove.identifier + ); + this.#telemetryObjects = this.#telemetryObjects.filter((existingTelemetryObject) => { + const existingKeyString = this.#openmct.objects.makeKeyString(existingTelemetryObject); + return keyStringToRemove !== existingKeyString; + }); + } + + destroy() { + this.#composition.off('add', this.addTelemetryObject); + this.#composition.off('remove', this.removeTelemetryObject); + Object.keys(this.#telemetryCollections).forEach((key) => { + this.#telemetryCollections[key]?.destroy(); + }); + } + + async #loadComposition() { + // load the composition of the condition set + this.#composition = this.#openmct.composition.get(this.#conditionSetDomainObject); + if (this.#composition) { + this.#composition.on('add', this.addTelemetryObject); + this.#composition.on('remove', this.removeTelemetryObject); + await this.#composition.load(); + } + } + + #processConditionSet() { + const conditionCollection = this.#conditionSetDomainObject.configuration.conditionCollection; + conditionCollection.forEach((condition, index) => { + const { outputTelemetry, outputMetadata } = condition.configuration; + if (outputTelemetry && outputMetadata) { + this.#outputTelemetryDetails[condition.id] = { + outputTelemetryKeyString: outputTelemetry, + outputMetadata + }; + } + }); } async getHistoricalData() { - console.log('🌟🌟🌟🌟🌟🌟🌟🌟🌟 getHistoricalData 🌟🌟🌟🌟🌟🌟🌟🌟🌟'); - this.setTimeBounds(this.openmct.time.getBounds()); - const outputTelemetryMap = await this.getHistoricalInputsByDate(); - const formattedOutputTelemetry = this.formatOutputData(outputTelemetryMap); - console.log(formattedOutputTelemetry); - return formattedOutputTelemetry; - } - - formatOutputData(outputTelemetryMap) { - const outputTelemetryList = []; - const domainObject = this.conditionSetDomainObject; - outputTelemetryMap.forEach((outputMetadata, timestamp) => { - const { condition, value, result, isDefault } = outputMetadata; - outputTelemetryList.push({ - conditionId: condition.id, - id: domainObject.identifier, - output: value, - utc: timestamp, - result, - isDefault - }); - }); - return outputTelemetryList; + console.debug('🍯 Getting historical data'); + // get the telemetry objects from the condition set + await this.#loadComposition(); + console.debug('🍯 Loaded telemetry objects', this.#telemetryObjects); + if (!this.#telemetryObjects) { + console.debug('🚨 No telemetry objects found in condition set'); + return []; + } + console.debug('🍯 Processed Condition Set'); + this.#processConditionSet(); + // load telemetry collections for each telemetry object + await this.#loadTelemetryCollections(); + console.debug('🍯 Loaded Telemetry Collections', this.#telemetryCollections); + // create data frame from telemetry collections + const dataFrame = this.#createDataFrame(); + console.debug('🍯 Created data frame', dataFrame); + // compute historical data from data frame + const computedHistoricalData = this.#computeHistoricalData(dataFrame); + console.debug('🍯 Computed historical data', computedHistoricalData); + return computedHistoricalData; } } From f3f8e3a5777b987951be2fd34dfba6fd9abf2de6 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 11 Oct 2024 18:12:59 +0200 Subject: [PATCH 118/139] not plotting --- .../condition/ConditionSetMetadataProvider.js | 4 --- .../condition/HistoricalTelemetryProvider.js | 34 +++++++++++++++---- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/plugins/condition/ConditionSetMetadataProvider.js b/src/plugins/condition/ConditionSetMetadataProvider.js index 25c017b39e..08ca67d447 100644 --- a/src/plugins/condition/ConditionSetMetadataProvider.js +++ b/src/plugins/condition/ConditionSetMetadataProvider.js @@ -67,10 +67,7 @@ export default class ConditionSetMetadataProvider { values: this.getDomains().concat([ { key: 'value', - source: 'output', name: 'Value', - derived: true, - ...format, hints: { range: 1 } @@ -78,7 +75,6 @@ export default class ConditionSetMetadataProvider { { key: 'result', source: 'result', - derived: true, name: 'Result', format: 'enum', enumerations: resultEnum, diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index 7b6bbe1bd3..bdb26a8721 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -61,11 +61,11 @@ export default class HistoricalTelemetryProvider { const formattedDatum = { ...datum }; - formattedDatum.output = datum[metadata]; + formattedDatum.value = datum[metadata]; return formattedDatum; } - #computeHistoricalDatum(timestamp, dataFrame) { + #computeHistoricalDatum(timestamp, dataFrame, timekey) { for (let conditionIndex = 0; conditionIndex < this.#conditions.length; conditionIndex++) { const condition = this.#conditions[conditionIndex]; const { id } = condition; @@ -81,7 +81,10 @@ export default class HistoricalTelemetryProvider { if (result) { // generate the output telemetry object if available const outputTelmetryDetail = this.#outputTelemetryDetails[id]; - if (outputTelmetryDetail) { + if ( + outputTelmetryDetail?.outputTelemetryKeyString && + outputTelmetryDetail?.outputMetadata + ) { const outputTelmetryDatum = dataFrame[outputTelmetryDetail.outputTelemetryKeyString][timestamp]; const formattedDatum = this.#formatDatumForOutput( @@ -89,6 +92,13 @@ export default class HistoricalTelemetryProvider { outputTelmetryDetail.outputMetadata ); return formattedDatum; + } else if (outputTelmetryDetail?.staticOutputValue) { + const staticOutput = { + output: outputTelmetryDetail?.staticOutputValue, + [timekey]: timestamp, + result: false + }; + return staticOutput; } } } @@ -120,8 +130,14 @@ export default class HistoricalTelemetryProvider { const referenceTelemetryData = referenceTelemetryCollection.getAll(); referenceTelemetryData.forEach((datum) => { const timestamp = datum[referenceTelemetryCollection.timeKey]; - const historicalDatum = this.#computeHistoricalDatum(timestamp, dataFrame); - historicalData.push(historicalDatum); + const historicalDatum = this.#computeHistoricalDatum( + timestamp, + dataFrame, + referenceTelemetryCollection.timeKey + ); + if (historicalDatum) { + historicalData.push(historicalDatum); + } }); return historicalData; } @@ -217,12 +233,16 @@ export default class HistoricalTelemetryProvider { #processConditionSet() { const conditionCollection = this.#conditionSetDomainObject.configuration.conditionCollection; conditionCollection.forEach((condition, index) => { - const { outputTelemetry, outputMetadata } = condition.configuration; + const { outputTelemetry, outputMetadata, output } = condition.configuration; if (outputTelemetry && outputMetadata) { this.#outputTelemetryDetails[condition.id] = { outputTelemetryKeyString: outputTelemetry, outputMetadata }; + } else if (output) { + this.#outputTelemetryDetails[condition.id] = { + staticOutputValue: output + }; } }); } @@ -236,7 +256,7 @@ export default class HistoricalTelemetryProvider { console.debug('🚨 No telemetry objects found in condition set'); return []; } - console.debug('🍯 Processed Condition Set'); + console.debug('🍯 Processed Condition Set', this.#outputTelemetryDetails); this.#processConditionSet(); // load telemetry collections for each telemetry object await this.#loadTelemetryCollections(); From cf4f3aa618c6032c67bd6559d8b4740318054188 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 11 Oct 2024 19:55:12 +0200 Subject: [PATCH 119/139] persist metadata --- .../condition/ConditionSetMetadataProvider.js | 21 +++++++++++++++---- .../condition/HistoricalTelemetryProvider.js | 10 +++++---- .../condition/components/ConditionItem.vue | 19 +++++++++++++++++ 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/plugins/condition/ConditionSetMetadataProvider.js b/src/plugins/condition/ConditionSetMetadataProvider.js index 08ca67d447..60bc434e1c 100644 --- a/src/plugins/condition/ConditionSetMetadataProvider.js +++ b/src/plugins/condition/ConditionSetMetadataProvider.js @@ -29,7 +29,7 @@ export default class ConditionSetMetadataProvider { return domainObject.type === 'conditionSet'; } - getDomains(domainObject) { + getDefaultDomains(domainObject) { return this.openmct.time.getAllTimeSystems().map(function (ts, i) { return { key: ts.key, @@ -63,8 +63,8 @@ export default class ConditionSetMetadataProvider { } ]; - return { - values: this.getDomains().concat([ + const metaDataToReturn = { + values: [ { key: 'value', name: 'Value', @@ -82,7 +82,20 @@ export default class ConditionSetMetadataProvider { range: 2 } } - ]) + ] }; + + // if there are any parameters, grab the first one's timeMetaData + const timeMetaData = + domainObject?.configuration?.conditionCollection[0]?.configuration.timeMetadata; + + if (timeMetaData) { + metaDataToReturn.values.push(timeMetaData); + } else { + const defaultDomains = this.getDefaultDomains(domainObject); + metaDataToReturn.values.push(...defaultDomains); + } + + return metaDataToReturn; } } diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index bdb26a8721..2ab11bfb14 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -57,11 +57,12 @@ export default class HistoricalTelemetryProvider { return specificDatum; } - #formatDatumForOutput(datum, metadata) { + #formatDatumForOutput(datum, metadata, result) { const formattedDatum = { - ...datum + ...datum, + value: datum[metadata], + result }; - formattedDatum.value = datum[metadata]; return formattedDatum; } @@ -89,7 +90,8 @@ export default class HistoricalTelemetryProvider { dataFrame[outputTelmetryDetail.outputTelemetryKeyString][timestamp]; const formattedDatum = this.#formatDatumForOutput( outputTelmetryDatum, - outputTelmetryDetail.outputMetadata + outputTelmetryDetail.outputMetadata, + result ); return formattedDatum; } else if (outputTelmetryDetail?.staticOutputValue) { diff --git a/src/plugins/condition/components/ConditionItem.vue b/src/plugins/condition/components/ConditionItem.vue index 9df75b7976..d73407e01d 100644 --- a/src/plugins/condition/components/ConditionItem.vue +++ b/src/plugins/condition/components/ConditionItem.vue @@ -336,6 +336,7 @@ export default { if (config?.output !== TELEMETRY_VALUE) { config.outputTelemetry = null; config.outputMetadata = null; + config.timeMetadata = null; } }, deep: true @@ -467,10 +468,28 @@ export default { this.condition.configuration.criteria.splice(index + 1, 0, clonedCriterion); this.persist(); }, + persistTimeMetadata() { + if (!this.condition.configuration.outputTelemetry) { + return; + } + const outputTelemetryObject = this.telemetry.find( + (telemetryItem) => + this.openmct.objects.makeKeyString(telemetryItem.identifier) === + this.condition.configuration.outputTelemetry + ); + const timeSystem = this.openmct.time.getTimeSystem(); + const telemetryMetadata = this.openmct.telemetry.getMetadata(outputTelemetryObject); + const domains = telemetryMetadata?.valuesForHints(['domain']); + const timeMetaData = domains.find((d) => d.key === timeSystem.key); + if (telemetryMetadata) { + this.condition.configuration.timeMetadata = timeMetaData; + } + }, persist() { const valueMetadata = this.getOutputMetadata(); if (valueMetadata) { this.condition.configuration.valueMetadata = valueMetadata; + this.persistTimeMetadata(); } this.$emit('update-condition', { condition: this.condition From 597f8b5c6fae56f2f9232788c7bb4692a0457609 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 11 Oct 2024 20:10:46 +0200 Subject: [PATCH 120/139] switch to all value --- src/plugins/condition/ConditionManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 7d9f404ac2..6ff201a046 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -412,7 +412,7 @@ export default class ConditionManager extends EventEmitter { } const currentOutput = { - output: output, + value: output, id: this.conditionSetDomainObject.identifier, conditionId: currentCondition.id, ...latestTimestamp @@ -471,7 +471,7 @@ export default class ConditionManager extends EventEmitter { { id: this.conditionSetDomainObject.identifier, conditionId: currentCondition.id, - output: outputValue, + value: outputValue, result }, timestamp From d4736ead4589e12dbcff5d40e4087bc0e3e18f59 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 14 Oct 2024 13:53:20 +0200 Subject: [PATCH 121/139] get telemetry tables working and ensure we are properly outputting data --- .webpack/webpack.common.mjs | 3 +- src/plugins/condition/ConditionManager.js | 188 +++++------------- .../ConditionSetTelemetryProvider.js | 3 +- .../condition/components/ConditionSet.vue | 2 +- .../condition/historicalTelemetryWorker.js | 37 ---- .../components/ConditionWidget.vue | 2 +- 6 files changed, 51 insertions(+), 184 deletions(-) delete mode 100644 src/plugins/condition/historicalTelemetryWorker.js diff --git a/.webpack/webpack.common.mjs b/.webpack/webpack.common.mjs index 17bf26f517..8a745cb464 100644 --- a/.webpack/webpack.common.mjs +++ b/.webpack/webpack.common.mjs @@ -51,8 +51,7 @@ const config = { compsMathWorker: './src/plugins/comps/CompsMathWorker.js', espressoTheme: './src/plugins/themes/espresso-theme.scss', snowTheme: './src/plugins/themes/snow-theme.scss', - darkmatterTheme: './src/plugins/themes/darkmatter-theme.scss', - historicalTelemetryWorker: './src/plugins/condition/historicalTelemetryWorker.js', + darkmatterTheme: './src/plugins/themes/darkmatter-theme.scss' }, output: { globalObject: 'this', diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 6ff201a046..17ffcff4ed 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -25,7 +25,6 @@ import { v4 as uuid } from 'uuid'; import Condition from './Condition.js'; import HistoricalTelemetryProvider from './HistoricalTelemetryProvider.js'; -import { TELEMETRY_VALUE } from './utils/constants.js'; import { getLatestTimestamp } from './utils/time.js'; export default class ConditionManager extends EventEmitter { @@ -338,89 +337,6 @@ export default class ConditionManager extends EventEmitter { return historicalData; } - getCurrentConditionLAD(conditionResults) { - const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection; - let currentCondition = conditionCollection[conditionCollection.length - 1]; - - for (let i = 0; i < conditionCollection.length - 1; i++) { - if (conditionResults[conditionCollection[i].id]) { - //first condition to be true wins - currentCondition = conditionCollection[i]; - break; - } - } - - return currentCondition; - } - - async requestLADConditionSetOutput(options) { - if (!this.conditions.length) { - return []; - } - - await this.compositionLoad; - - let latestTimestamp; - let conditionResults = {}; - let nextLegOptions = { ...options }; - delete nextLegOptions.onPartialResponse; - - const results = await Promise.all( - this.conditions.map((condition) => condition.requestLADConditionResult(nextLegOptions)) - ); - - results.forEach((resultObj) => { - const { - id, - data, - data: { result } - } = resultObj; - - if (this.findConditionById(id)) { - conditionResults[id] = Boolean(result); - } - - latestTimestamp = getLatestTimestamp( - latestTimestamp, - data, - this.timeSystems, - this.openmct.time.getTimeSystem() - ); - }); - - if (!Object.values(latestTimestamp).some((timeSystem) => timeSystem)) { - return []; - } - - const currentCondition = this.getCurrentConditionLAD(conditionResults); - let output = currentCondition?.configuration?.output; - if (output === TELEMETRY_VALUE) { - const { outputTelemetry, outputMetadata } = currentCondition.configuration; - const outputTelemetryObject = await this.openmct.objects.get(outputTelemetry); - const telemetryOptions = { - size: 1, - strategy: 'latest', - timeContext: this.openmct.time.getContextForView([]) - }; - const latestData = await this.openmct.telemetry.request( - outputTelemetryObject, - telemetryOptions - ); - if (latestData?.[0]?.[outputMetadata]) { - output = latestData?.[0]?.[outputMetadata]; - } - } - - const currentOutput = { - value: output, - id: this.conditionSetDomainObject.identifier, - conditionId: currentCondition.id, - ...latestTimestamp - }; - - return [currentOutput]; - } - isTelemetryUsed(endpoint) { const id = this.openmct.objects.makeKeyString(endpoint.identifier); @@ -445,13 +361,16 @@ export default class ConditionManager extends EventEmitter { const datum = data[0]; const normalizedDatum = this.createNormalizedDatum(datum, endpoint); - const timeSystemKey = this.openmct.time.getTimeSystem().key; - let timestamp = {}; - const currentTimestamp = normalizedDatum[timeSystemKey]; - timestamp[timeSystemKey] = currentTimestamp; - if (this.shouldEvaluateNewTelemetry(currentTimestamp)) { + const keyString = this.openmct.objects.makeKeyString(endpoint.identifier); + const associatedTelemetryCollection = this.telemetryCollections[keyString]; + const timeKey = associatedTelemetryCollection.timeKey; + const formattedTimeStamp = associatedTelemetryCollection.parseTime(datum); + const rawTimestamp = { + [timeKey]: datum[timeKey] + }; + if (this.shouldEvaluateNewTelemetry(formattedTimeStamp)) { this.updateConditionResults(normalizedDatum); - this.updateCurrentCondition(timestamp, endpoint, datum); + this.updateCurrentCondition(rawTimestamp, endpoint, datum); } } @@ -465,18 +384,14 @@ export default class ConditionManager extends EventEmitter { } emitConditionSetResult(currentCondition, timestamp, outputValue, result) { - this.emit( - 'conditionSetResultUpdated', - Object.assign( - { - id: this.conditionSetDomainObject.identifier, - conditionId: currentCondition.id, - value: outputValue, - result - }, - timestamp - ) - ); + const conditionSetResult = { + id: this.conditionSetDomainObject.identifier, + conditionId: currentCondition.id, + value: outputValue, + result, + ...timestamp + }; + this.emit('conditionSetResultUpdated', conditionSetResult); } updateCurrentCondition(timestamp, telemetryObject, telemetryData) { @@ -498,7 +413,29 @@ export default class ConditionManager extends EventEmitter { this.isProcessing = false; } - async processCondition(timestamp, telemetryObject, telemetryData) { + fetchUnderlyingTelemetry(currentCondition, telemetryObject, telemetryData, timestamp) { + let telemetryValue; + const selectedOutputIdentifier = currentCondition?.configuration?.outputTelemetry; + const outputMetadata = currentCondition?.configuration?.outputMetadata; + const telemetryKeystring = this.openmct.objects.makeKeyString(telemetryObject.identifier); + + if (selectedOutputIdentifier === telemetryKeystring) { + telemetryValue = telemetryData[outputMetadata]; + } else { + // grab it from the associated telemetry collection + const outputTelemetryCollection = this.telemetryCollections[selectedOutputIdentifier]; + const latestTelemetryData = outputTelemetryCollection.getAll(); + const lastValue = latestTelemetryData[latestTelemetryData.length - 1]; + if (lastValue && lastValue?.[outputMetadata]) { + telemetryValue = lastValue?.[outputMetadata]; + } else { + telemetryValue = null; + } + } + return telemetryValue; + } + + processCondition(timestamp, telemetryObject, telemetryData) { const currentCondition = this.getCurrentCondition(); const conditionDetails = this.conditions.filter( (condition) => condition.id === currentCondition.id @@ -506,32 +443,12 @@ export default class ConditionManager extends EventEmitter { const conditionResult = currentCondition?.isDefault ? false : conditionDetails?.result; let telemetryValue = currentCondition.configuration.output; if (currentCondition?.configuration?.outputTelemetry) { - const selectedOutputIdentifier = currentCondition?.configuration?.outputTelemetry; - const outputMetadata = currentCondition?.configuration?.outputMetadata; - const telemetryKeystring = this.openmct.objects.makeKeyString(telemetryObject.identifier); - - if (selectedOutputIdentifier === telemetryKeystring) { - telemetryValue = telemetryData[outputMetadata]; - } else { - const outputTelemetryObject = await this.openmct.objects.get(selectedOutputIdentifier); - const telemetryOptions = { - size: 1, - strategy: 'latest', - start: timestamp?.utc - 1000, - end: timestamp?.utc + 1000 - }; - const outputTelemetryData = await this.openmct.telemetry.request( - outputTelemetryObject, - telemetryOptions - ); - const outputTelemetryValue = - outputTelemetryData?.length > 0 ? outputTelemetryData.slice(-1)[0] : null; - if (outputTelemetryData.length && outputTelemetryValue?.[outputMetadata]) { - telemetryValue = outputTelemetryValue?.[outputMetadata]; - } else { - telemetryValue = undefined; - } - } + telemetryValue = this.fetchUnderlyingTelemetry( + currentCondition, + telemetryObject, + telemetryData, + timestamp + ); } this.emitConditionSetResult(currentCondition, timestamp, telemetryValue, conditionResult); @@ -553,18 +470,7 @@ export default class ConditionManager extends EventEmitter { createNormalizedDatum(telemetryDatum, endpoint) { const id = this.openmct.objects.makeKeyString(endpoint.identifier); - const metadata = this.openmct.telemetry.getMetadata(endpoint).valueMetadatas; - - const normalizedDatum = Object.values(metadata).reduce((datum, metadatum) => { - const testValue = this.getTestData(metadatum); - const formatter = this.openmct.telemetry.getValueFormatter(metadatum); - datum[metadatum.key] = - testValue !== undefined - ? formatter.parse(testValue) - : formatter.parse(telemetryDatum[metadatum.source]); - - return datum; - }, {}); + const normalizedDatum = { ...telemetryDatum }; normalizedDatum.id = id; diff --git a/src/plugins/condition/ConditionSetTelemetryProvider.js b/src/plugins/condition/ConditionSetTelemetryProvider.js index dc3e3a7240..9abf3d2e99 100644 --- a/src/plugins/condition/ConditionSetTelemetryProvider.js +++ b/src/plugins/condition/ConditionSetTelemetryProvider.js @@ -43,8 +43,7 @@ export default class ConditionSetTelemetryProvider { async request(domainObject, options) { let conditionManager = this.getConditionManager(domainObject); const formattedHistoricalData = await conditionManager.getHistoricalData(options); - let latestOutput = await conditionManager.requestLADConditionSetOutput(options); - return [...formattedHistoricalData, ...latestOutput]; + return formattedHistoricalData; } subscribe(domainObject, callback) { diff --git a/src/plugins/condition/components/ConditionSet.vue b/src/plugins/condition/components/ConditionSet.vue index cb473c10b9..bb1a03b454 100644 --- a/src/plugins/condition/components/ConditionSet.vue +++ b/src/plugins/condition/components/ConditionSet.vue @@ -86,7 +86,7 @@ export default { }, methods: { updateCurrentOutput(currentConditionResult) { - this.currentConditionOutput = currentConditionResult.output; + this.currentConditionOutput = currentConditionResult.value; }, updateDefaultOutput(output) { this.currentConditionOutput = output; diff --git a/src/plugins/condition/historicalTelemetryWorker.js b/src/plugins/condition/historicalTelemetryWorker.js deleted file mode 100644 index fae6a5b913..0000000000 --- a/src/plugins/condition/historicalTelemetryWorker.js +++ /dev/null @@ -1,37 +0,0 @@ -import { makeKeyString } from '../../api/objects/object-utils.js'; - -function sortTelemetriesByDate(historicalTelemetriesPool) { - const historicalTelemetryDateMap = new Map(); - historicalTelemetriesPool.forEach((historicalTelemetryList) => { - const { historicalTelemetry, domainObject } = historicalTelemetryList; - const { identifier } = domainObject; - const telemetryIdentifier = makeKeyString(identifier); - historicalTelemetry.forEach((historicalTelemetryItem) => { - let telemetryTimestamp = historicalTelemetryItem.utc; - if (historicalTelemetryItem.timestamp) { - telemetryTimestamp = new Date(historicalTelemetryItem.timestamp)?.getTime(); - } - if (!historicalTelemetryDateMap.get(telemetryTimestamp)) { - const telemetryMap = new Map(); - telemetryMap.set(telemetryIdentifier, historicalTelemetryItem); - historicalTelemetryDateMap.set(telemetryTimestamp, telemetryMap); - } else { - const telemetryMap = historicalTelemetryDateMap.get(telemetryTimestamp); - telemetryMap.set(telemetryIdentifier, historicalTelemetryItem); - historicalTelemetryDateMap.set(telemetryTimestamp, telemetryMap); - } - }); - }); - return historicalTelemetryDateMap; -} - -self.onmessage = function (e) { - const { type, data } = e.data; - - if (type === 'sortTelemetries') { - const sortedTelemetries = sortTelemetriesByDate(data.historicalTelemetriesPool); - self.postMessage({ type: 'result', data: sortedTelemetries }); - } else { - self.postMessage({ type: 'error', error: 'Unknown message type' }); - } -}; diff --git a/src/plugins/conditionWidget/components/ConditionWidget.vue b/src/plugins/conditionWidget/components/ConditionWidget.vue index 1d07e629b8..d83e4da31e 100644 --- a/src/plugins/conditionWidget/components/ConditionWidget.vue +++ b/src/plugins/conditionWidget/components/ConditionWidget.vue @@ -123,7 +123,7 @@ export default { return; } - this.conditionalLabel = latestDatum.output || ''; + this.conditionalLabel = latestDatum.value || ''; }, async showToolTip() { const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS; From 958e5ce09a83d69534a3da565f904c20546c99a5 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 14 Oct 2024 14:02:45 +0200 Subject: [PATCH 122/139] should be waiting for historical data --- src/plugins/condition/ConditionManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 17ffcff4ed..10b7409eb6 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -323,7 +323,7 @@ export default class ConditionManager extends EventEmitter { return currentCondition; } - getHistoricalData(options) { + async getHistoricalData(options) { if (!this.conditionSetDomainObject.configuration.shouldFetchHistorical) { return []; } @@ -333,7 +333,7 @@ export default class ConditionManager extends EventEmitter { this.conditionSetDomainObject, options ); - const historicalData = historicalTelemetry.getHistoricalData(); + const historicalData = await historicalTelemetry.getHistoricalData(); return historicalData; } From 1516524f0b7036bb2339c2e301cd715efc918046 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 14 Oct 2024 15:28:19 +0200 Subject: [PATCH 123/139] support lambda values --- src/plugins/comps/CompsMathWorker.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/plugins/comps/CompsMathWorker.js b/src/plugins/comps/CompsMathWorker.js index 52628fa8d8..a0097c00ef 100644 --- a/src/plugins/comps/CompsMathWorker.js +++ b/src/plugins/comps/CompsMathWorker.js @@ -122,8 +122,18 @@ function calculate(dataFrame, parameters, expression) { console.debug('🤦‍♂️ Missing data for some parameters, skipping calculation'); return; } - const value = evaluate(expression, scope); - sumResults.push({ [referenceParameter.timeKey]: referenceTime, value }); + const rawComputedValue = evaluate(expression, scope); + let computedValue = rawComputedValue; + if (computedValue.entries) { + // if there aren't any entries, return with nothing + if (computedValue.entries.length === 0) { + return; + } + console.debug('📊 Computed value is an array of entries', computedValue.entries); + // make array of arrays of entries + computedValue = computedValue.entries?.[0]; + } + sumResults.push({ [referenceParameter.timeKey]: referenceTime, value: computedValue }); }); return sumResults; } From 3fc569beef9e1e0da523bcb5a941492fb7caa9a8 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 15 Oct 2024 20:12:57 +0200 Subject: [PATCH 124/139] can remove telemetry mostly --- .../condition/HistoricalTelemetryProvider.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index 2ab11bfb14..f8938955cb 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -72,14 +72,15 @@ export default class HistoricalTelemetryProvider { const { id } = condition; const conditionCriteria = condition.criteria?.[0]; let result = false; + let defaultHit = false; if (conditionCriteria) { const inputTelemetry = this.#getInputTelemetry(conditionCriteria, dataFrame, timestamp); result = conditionCriteria.computeResult({ id, ...inputTelemetry }); } else { // default criteria is 'all' - result = true; + defaultHit = true; } - if (result) { + if (result || defaultHit) { // generate the output telemetry object if available const outputTelmetryDetail = this.#outputTelemetryDetails[id]; if ( @@ -98,7 +99,7 @@ export default class HistoricalTelemetryProvider { const staticOutput = { output: outputTelmetryDetail?.staticOutputValue, [timekey]: timestamp, - result: false + result }; return staticOutput; } @@ -204,12 +205,12 @@ export default class HistoricalTelemetryProvider { this.#telemetryObjects[keyString] = telemetryObjectToAdd; } - removeTelemetryObject(telemetryObjectToRemove) { - const keyStringToRemove = this.#openmct.objects.makeKeyString( - telemetryObjectToRemove.identifier - ); + removeTelemetryObject(telemetryIdentifierToRemove) { + const keyStringToRemove = this.#openmct.objects.makeKeyString(telemetryIdentifierToRemove); this.#telemetryObjects = this.#telemetryObjects.filter((existingTelemetryObject) => { - const existingKeyString = this.#openmct.objects.makeKeyString(existingTelemetryObject); + const existingKeyString = this.#openmct.objects.makeKeyString( + existingTelemetryObject.identifier + ); return keyStringToRemove !== existingKeyString; }); } From 5d1f1d0a4a03e3f96bb8832cd871df18d586068a Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 15 Oct 2024 21:04:48 +0200 Subject: [PATCH 125/139] fix false output --- src/plugins/condition/ConditionManager.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 10b7409eb6..17eeecbf8f 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -391,7 +391,9 @@ export default class ConditionManager extends EventEmitter { result, ...timestamp }; - this.emit('conditionSetResultUpdated', conditionSetResult); + if (result) { + this.emit('conditionSetResultTrue', conditionSetResult); + } } updateCurrentCondition(timestamp, telemetryObject, telemetryData) { From 219303271d06353cb44bc5b883e6fe5a69d38f60 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 15 Oct 2024 21:53:01 +0200 Subject: [PATCH 126/139] only emit telemetry if we have a result --- src/plugins/condition/ConditionManager.js | 4 +--- src/plugins/condition/ConditionSetTelemetryProvider.js | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 17eeecbf8f..10b7409eb6 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -391,9 +391,7 @@ export default class ConditionManager extends EventEmitter { result, ...timestamp }; - if (result) { - this.emit('conditionSetResultTrue', conditionSetResult); - } + this.emit('conditionSetResultUpdated', conditionSetResult); } updateCurrentCondition(timestamp, telemetryObject, telemetryData) { diff --git a/src/plugins/condition/ConditionSetTelemetryProvider.js b/src/plugins/condition/ConditionSetTelemetryProvider.js index 9abf3d2e99..5272b03ae7 100644 --- a/src/plugins/condition/ConditionSetTelemetryProvider.js +++ b/src/plugins/condition/ConditionSetTelemetryProvider.js @@ -50,7 +50,9 @@ export default class ConditionSetTelemetryProvider { let conditionManager = this.getConditionManager(domainObject); conditionManager.on('conditionSetResultUpdated', (data) => { - callback(data); + if (data?.result){ + callback(data); + } }); return this.destroyConditionManager.bind( From 251b8bd0384d42674327790e72ed1046ba4df997 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 15 Oct 2024 21:53:01 +0200 Subject: [PATCH 127/139] only emit telemetry if we have a result --- src/plugins/condition/ConditionManager.js | 4 +--- src/plugins/condition/ConditionSetTelemetryProvider.js | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index 17eeecbf8f..10b7409eb6 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -391,9 +391,7 @@ export default class ConditionManager extends EventEmitter { result, ...timestamp }; - if (result) { - this.emit('conditionSetResultTrue', conditionSetResult); - } + this.emit('conditionSetResultUpdated', conditionSetResult); } updateCurrentCondition(timestamp, telemetryObject, telemetryData) { diff --git a/src/plugins/condition/ConditionSetTelemetryProvider.js b/src/plugins/condition/ConditionSetTelemetryProvider.js index 9abf3d2e99..5272b03ae7 100644 --- a/src/plugins/condition/ConditionSetTelemetryProvider.js +++ b/src/plugins/condition/ConditionSetTelemetryProvider.js @@ -50,7 +50,9 @@ export default class ConditionSetTelemetryProvider { let conditionManager = this.getConditionManager(domainObject); conditionManager.on('conditionSetResultUpdated', (data) => { - callback(data); + if (data?.result){ + callback(data); + } }); return this.destroyConditionManager.bind( From 397ba314b54287957924009fc2637868e20471e6 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 15 Oct 2024 21:54:37 +0200 Subject: [PATCH 128/139] lint --- src/plugins/condition/ConditionSetTelemetryProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/condition/ConditionSetTelemetryProvider.js b/src/plugins/condition/ConditionSetTelemetryProvider.js index 5272b03ae7..8a0d9e17e1 100644 --- a/src/plugins/condition/ConditionSetTelemetryProvider.js +++ b/src/plugins/condition/ConditionSetTelemetryProvider.js @@ -50,7 +50,7 @@ export default class ConditionSetTelemetryProvider { let conditionManager = this.getConditionManager(domainObject); conditionManager.on('conditionSetResultUpdated', (data) => { - if (data?.result){ + if (data?.result) { callback(data); } }); From 01694869998f11ea8665a5ed9b16ff1f663e0391 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 16 Oct 2024 07:58:11 +0200 Subject: [PATCH 129/139] delete size for underlying telemetry so we can get full bounds --- src/plugins/condition/HistoricalTelemetryProvider.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index f8938955cb..48507fb5e4 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -110,6 +110,8 @@ export default class HistoricalTelemetryProvider { async #loadTelemetryCollections() { await Promise.all( Object.entries(this.#telemetryObjects).map(async ([keystring, telemetryObject]) => { + // delete size + delete this.#telemetryOptions.size; const telemetryCollection = this.#openmct.telemetry.requestCollection( telemetryObject, this.#telemetryOptions From f834a47b9fbb94f853a427128350c831bed71dc9 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Wed, 16 Oct 2024 16:40:01 +0200 Subject: [PATCH 130/139] better comment --- src/plugins/condition/HistoricalTelemetryProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index 48507fb5e4..8b41ae0f15 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -110,7 +110,7 @@ export default class HistoricalTelemetryProvider { async #loadTelemetryCollections() { await Promise.all( Object.entries(this.#telemetryObjects).map(async ([keystring, telemetryObject]) => { - // delete size + // delete size as we need to scan the whole time bounds delete this.#telemetryOptions.size; const telemetryCollection = this.#openmct.telemetry.requestCollection( telemetryObject, From 07c5ba84241bc92622708be015218197aaef8cbf Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 17 Oct 2024 10:08:17 +0200 Subject: [PATCH 131/139] enforce size limit on computation --- .../condition/HistoricalTelemetryProvider.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index 8b41ae0f15..a59baf1f6e 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -110,11 +110,12 @@ export default class HistoricalTelemetryProvider { async #loadTelemetryCollections() { await Promise.all( Object.entries(this.#telemetryObjects).map(async ([keystring, telemetryObject]) => { - // delete size as we need to scan the whole time bounds - delete this.#telemetryOptions.size; + // clone telemetry options without size as we need to load all data + const telemetryOptionsWithoutSize = { ...this.#telemetryOptions }; + delete telemetryOptionsWithoutSize.size; const telemetryCollection = this.#openmct.telemetry.requestCollection( telemetryObject, - this.#telemetryOptions + telemetryOptionsWithoutSize ); await telemetryCollection.load(); this.#telemetryCollections[keystring] = telemetryCollection; @@ -133,7 +134,13 @@ export default class HistoricalTelemetryProvider { const referenceTelemetryKeyString = Object.keys(dataFrame)[0]; const referenceTelemetryCollection = this.#telemetryCollections[referenceTelemetryKeyString]; const referenceTelemetryData = referenceTelemetryCollection.getAll(); - referenceTelemetryData.forEach((datum) => { + const maxDataPointsToCompute = this.#telemetryOptions.size || referenceTelemetryData.length; + for ( + let i = 0; + i < referenceTelemetryData.length && historicalData.length < maxDataPointsToCompute; + i++ + ) { + const datum = referenceTelemetryData[i]; const timestamp = datum[referenceTelemetryCollection.timeKey]; const historicalDatum = this.#computeHistoricalDatum( timestamp, @@ -143,7 +150,7 @@ export default class HistoricalTelemetryProvider { if (historicalDatum) { historicalData.push(historicalDatum); } - }); + } return historicalData; } From c9843481e978c6467bbeb3414a7ac11b6686663d Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 17 Oct 2024 16:33:43 +0200 Subject: [PATCH 132/139] Revert "enforce size limit on computation" This reverts commit 07c5ba84241bc92622708be015218197aaef8cbf. --- .../condition/HistoricalTelemetryProvider.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index a59baf1f6e..8b41ae0f15 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -110,12 +110,11 @@ export default class HistoricalTelemetryProvider { async #loadTelemetryCollections() { await Promise.all( Object.entries(this.#telemetryObjects).map(async ([keystring, telemetryObject]) => { - // clone telemetry options without size as we need to load all data - const telemetryOptionsWithoutSize = { ...this.#telemetryOptions }; - delete telemetryOptionsWithoutSize.size; + // delete size as we need to scan the whole time bounds + delete this.#telemetryOptions.size; const telemetryCollection = this.#openmct.telemetry.requestCollection( telemetryObject, - telemetryOptionsWithoutSize + this.#telemetryOptions ); await telemetryCollection.load(); this.#telemetryCollections[keystring] = telemetryCollection; @@ -134,13 +133,7 @@ export default class HistoricalTelemetryProvider { const referenceTelemetryKeyString = Object.keys(dataFrame)[0]; const referenceTelemetryCollection = this.#telemetryCollections[referenceTelemetryKeyString]; const referenceTelemetryData = referenceTelemetryCollection.getAll(); - const maxDataPointsToCompute = this.#telemetryOptions.size || referenceTelemetryData.length; - for ( - let i = 0; - i < referenceTelemetryData.length && historicalData.length < maxDataPointsToCompute; - i++ - ) { - const datum = referenceTelemetryData[i]; + referenceTelemetryData.forEach((datum) => { const timestamp = datum[referenceTelemetryCollection.timeKey]; const historicalDatum = this.#computeHistoricalDatum( timestamp, @@ -150,7 +143,7 @@ export default class HistoricalTelemetryProvider { if (historicalDatum) { historicalData.push(historicalDatum); } - } + }); return historicalData; } From 6ca6a4cd008b13de1a6766d078e3d7f8ed0d5fac Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Thu, 17 Oct 2024 16:34:42 +0200 Subject: [PATCH 133/139] revert size checking --- src/plugins/condition/HistoricalTelemetryProvider.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index 8b41ae0f15..cc03887d57 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -110,11 +110,12 @@ export default class HistoricalTelemetryProvider { async #loadTelemetryCollections() { await Promise.all( Object.entries(this.#telemetryObjects).map(async ([keystring, telemetryObject]) => { - // delete size as we need to scan the whole time bounds - delete this.#telemetryOptions.size; + // clone telemetry options without size as we need to load all data + const telemetryOptionsWithoutSize = { ...this.#telemetryOptions }; + delete telemetryOptionsWithoutSize.size; const telemetryCollection = this.#openmct.telemetry.requestCollection( telemetryObject, - this.#telemetryOptions + telemetryOptionsWithoutSize ); await telemetryCollection.load(); this.#telemetryCollections[keystring] = telemetryCollection; From 96b1ef0db5e5ae67b1da2f18b1bee8ada466346e Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Tue, 22 Oct 2024 21:02:10 +0200 Subject: [PATCH 134/139] reduce size --- src/plugins/comps/components/CompsView.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 394cf212be..273a7e5098 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -210,8 +210,10 @@ const props = defineProps({ onBeforeMount(async () => { const telemetryOptions = { - strategy: 'minmax' + strategy: 'minmax', + size: 20, }; + // TODO: we should dynamically set size to the largest comp input window outputTelemetryCollection = openmct.telemetry.requestCollection(domainObject, telemetryOptions); outputTelemetryCollection.on('add', telemetryProcessor); outputTelemetryCollection.on('clear', clearData); From 9ca489cf12625d21d8a087404f537af03bcb6d05 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 28 Oct 2024 09:01:36 +0100 Subject: [PATCH 135/139] widen size to accomodate sample size --- src/plugins/comps/components/CompsView.vue | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 273a7e5098..5e5cf88648 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -209,9 +209,20 @@ const props = defineProps({ }); onBeforeMount(async () => { + let maxSampleSize = 20; + if (parameters.value) { + maxSampleSize = + parameters.value.reduce((max, param) => { + if (param.accumulateValues) { + return Math.max(max, param.sampleSize); + } + return max; + }, 0) + 20; + } + const telemetryOptions = { strategy: 'minmax', - size: 20, + size: maxSampleSize }; // TODO: we should dynamically set size to the largest comp input window outputTelemetryCollection = openmct.telemetry.requestCollection(domainObject, telemetryOptions); From 55063a004500fb10b2d514ece15da8e63994c221 Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Mon, 28 Oct 2024 09:24:23 +0100 Subject: [PATCH 136/139] removing debug statements for PR review --- .../functional/plugins/comps/comps.e2e.spec.js | 1 + src/plugins/comps/CompsManager.js | 16 ---------------- src/plugins/comps/CompsTelemetryProvider.js | 9 --------- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/e2e/tests/functional/plugins/comps/comps.e2e.spec.js b/e2e/tests/functional/plugins/comps/comps.e2e.spec.js index dae5c225d4..72ce7d86e9 100644 --- a/e2e/tests/functional/plugins/comps/comps.e2e.spec.js +++ b/e2e/tests/functional/plugins/comps/comps.e2e.spec.js @@ -27,6 +27,7 @@ import { import { expect, test } from '../../../../pluginFixtures.js'; test.describe('Comps', () => { + test.use({ failOnConsoleError: false }); test.beforeEach(async ({ page }) => { // Open a browser, navigate to the main page, and wait until all networkevents to resolve await page.goto('./', { waitUntil: 'domcontentloaded' }); diff --git a/src/plugins/comps/CompsManager.js b/src/plugins/comps/CompsManager.js index 50b0d0f354..0fc0651619 100644 --- a/src/plugins/comps/CompsManager.js +++ b/src/plugins/comps/CompsManager.js @@ -115,10 +115,6 @@ export default class CompsManager extends EventEmitter { const loadVersion = ++this.#loadVersion; if (!_.isEqual(this.#telemetryOptions, telemetryOptions)) { - console.debug( - `😩 Reloading comps manager ${this.#domainObject.name} due to telemetry options change.`, - telemetryOptions - ); this.#destroy(); } @@ -131,9 +127,6 @@ export default class CompsManager extends EventEmitter { await this.#loadComposition(); // Check if a newer load has been initiated if (loadVersion !== this.#loadVersion) { - console.debug( - `🔄 Reloading comps manager in composition wait ${this.#domainObject.name} due to newer load.` - ); await this.#currentLoadPromise; return; } @@ -145,16 +138,9 @@ export default class CompsManager extends EventEmitter { await this.#startListeningToUnderlyingTelemetry(); // Check again for newer load if (loadVersion !== this.#loadVersion) { - console.debug( - `🔄 Reloading comps manager in telemetry wait ${this.#domainObject.name} due to newer load.` - ); await this.#currentLoadPromise; return; } - console.debug( - `✅ Comps manager ${this.#domainObject.name} is ready.`, - this.#telemetryCollections - ); this.#loaded = true; } })(); @@ -259,8 +245,6 @@ export default class CompsManager extends EventEmitter { const imputedDatum = this.#getImputedDataUsingLOCF(fakeData, telemetryCollection); if (imputedDatum) { alignedValues.push(imputedDatum); - } else { - console.debug(`🚨 Missing data for ${keyString} at ${timestamp}`); } }); diff --git a/src/plugins/comps/CompsTelemetryProvider.js b/src/plugins/comps/CompsTelemetryProvider.js index 4c4f710b85..c53676d80d 100644 --- a/src/plugins/comps/CompsTelemetryProvider.js +++ b/src/plugins/comps/CompsTelemetryProvider.js @@ -80,11 +80,6 @@ export default class CompsTelemetryProvider { parameters, callbackID }; - console.debug( - `📝 Requesting calculation for ${domainObject.name} with callback ID ${callbackID}:`, - options, - payload - ); this.#sharedWorker.port.postMessage(payload); }); }); @@ -130,9 +125,6 @@ export default class CompsTelemetryProvider { size: 1 }; specificCompsManager.load(telemetryOptions); - console.debug( - `📝 Starting subscription for ${domainObject.name} with callback ID ${callbackID}` - ); return () => { delete this.#subscriptionCallbacks[callbackID]; specificCompsManager.stopListeningToUnderlyingTelemetry(); @@ -171,7 +163,6 @@ export default class CompsTelemetryProvider { console.error('📝 Error calculating request:', event.data); this.#requestPromises[callbackID].resolve([]); } else { - console.debug(`🧮 Calculation request result for ${callbackID}:`, result); this.#requestPromises[callbackID].resolve(result); } delete this.#requestPromises[callbackID]; From 402d9511150a85e693abcfe79bbcda92129632c6 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Thu, 14 Nov 2024 10:13:08 -0800 Subject: [PATCH 137/139] Closes #7823 - Markup/CSS sanding and shimming for derived telemetry front-end. - Toggle switch CSS improved to use `gap` instead of left margin. --- src/plugins/comps/components/CompsView.vue | 127 ++++++++++++--------- src/plugins/comps/components/comps.scss | 55 +++++++-- src/ui/components/toggle-switch.scss | 2 +- 3 files changed, 122 insertions(+), 62 deletions(-) diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 5e5cf88648..1c2b599e4d 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -53,8 +53,12 @@ -
-
diff --git a/src/plugins/comps/components/comps.scss b/src/plugins/comps/components/comps.scss index 3003c577d6..988abd34ee 100644 --- a/src/plugins/comps/components/comps.scss +++ b/src/plugins/comps/components/comps.scss @@ -56,25 +56,68 @@ gap: $interiorMarginSm; } + + &__apply-test-data-control { + padding: $interiorMargin 0; + } + + &__refs { + + } + &__ref { @include discreteItem(); - display: grid; - gap: $interiorMargin; - grid-template-columns: max-content max-content min-content 1fr; - padding: $interiorMargin; + align-items: start; + display: flex; + flex-direction: column; + padding: 0 $interiorMargin; line-height: 170%; // Aligns text with controls like selects + + > * + * { + border-top: 1px solid $colorInteriorBorder; + } + } + + &__ref-section { + align-items: baseline; + display: flex; + flex-wrap: wrap; + gap: $interiorMargin; + padding: $interiorMargin 0; + width: 100%; + } + + &__ref-sub-section { + align-items: baseline; + display: flex; + flex: 1 1 auto; + gap: $interiorMargin; + + &.ref-and-path { + flex: 0 1 auto; + flex-wrap: wrap; + } } &__path-and-field { align-items: start; display: flex; + flex-wrap: wrap; gap: $interiorMargin; + + .c-comp__ref-path { + word-break: break-all; + } + } + + &__label, + &__value { + white-space: nowrap; } &__expression { *[class*=value] { font-family: monospace; - //font-size: 1.1em; resize: vertical; // Only applies to textarea } div[class*=value] { @@ -87,7 +130,6 @@ border-radius: $basicCr; display: flex; // Creates hanging indent from :before icon padding: $interiorMarginSm $interiorMarginLg $interiorMarginSm $interiorMargin; - //text-wrap: normal; max-width: max-content; &:before { @@ -107,6 +149,5 @@ .--em { color: $colorBodyFgEm; - //font-weight: bold; } } diff --git a/src/ui/components/toggle-switch.scss b/src/ui/components/toggle-switch.scss index 402af4c082..f2f6f85533 100644 --- a/src/ui/components/toggle-switch.scss +++ b/src/ui/components/toggle-switch.scss @@ -25,6 +25,7 @@ .c-toggle-switch { cursor: pointer; display: inline-flex; + gap: $interiorMarginSm; align-items: center; vertical-align: middle; @@ -55,7 +56,6 @@ } &__label { - margin-left: $interiorMarginSm; white-space: nowrap; } From 64ae96e60272778e0ac92a0663917ae9c2bbe276 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Thu, 14 Nov 2024 10:13:08 -0800 Subject: [PATCH 138/139] Closes #7823 - Markup/CSS sanding and shimming for derived telemetry front-end. - Toggle switch CSS improved to use `gap` instead of left margin. --- src/plugins/comps/components/CompsView.vue | 127 ++++++++++++--------- src/plugins/comps/components/comps.scss | 55 +++++++-- src/ui/components/toggle-switch.scss | 2 +- 3 files changed, 122 insertions(+), 62 deletions(-) diff --git a/src/plugins/comps/components/CompsView.vue b/src/plugins/comps/components/CompsView.vue index 5e5cf88648..1c2b599e4d 100644 --- a/src/plugins/comps/components/CompsView.vue +++ b/src/plugins/comps/components/CompsView.vue @@ -53,8 +53,12 @@ -
-
diff --git a/src/plugins/comps/components/comps.scss b/src/plugins/comps/components/comps.scss index 3003c577d6..988abd34ee 100644 --- a/src/plugins/comps/components/comps.scss +++ b/src/plugins/comps/components/comps.scss @@ -56,25 +56,68 @@ gap: $interiorMarginSm; } + + &__apply-test-data-control { + padding: $interiorMargin 0; + } + + &__refs { + + } + &__ref { @include discreteItem(); - display: grid; - gap: $interiorMargin; - grid-template-columns: max-content max-content min-content 1fr; - padding: $interiorMargin; + align-items: start; + display: flex; + flex-direction: column; + padding: 0 $interiorMargin; line-height: 170%; // Aligns text with controls like selects + + > * + * { + border-top: 1px solid $colorInteriorBorder; + } + } + + &__ref-section { + align-items: baseline; + display: flex; + flex-wrap: wrap; + gap: $interiorMargin; + padding: $interiorMargin 0; + width: 100%; + } + + &__ref-sub-section { + align-items: baseline; + display: flex; + flex: 1 1 auto; + gap: $interiorMargin; + + &.ref-and-path { + flex: 0 1 auto; + flex-wrap: wrap; + } } &__path-and-field { align-items: start; display: flex; + flex-wrap: wrap; gap: $interiorMargin; + + .c-comp__ref-path { + word-break: break-all; + } + } + + &__label, + &__value { + white-space: nowrap; } &__expression { *[class*=value] { font-family: monospace; - //font-size: 1.1em; resize: vertical; // Only applies to textarea } div[class*=value] { @@ -87,7 +130,6 @@ border-radius: $basicCr; display: flex; // Creates hanging indent from :before icon padding: $interiorMarginSm $interiorMarginLg $interiorMarginSm $interiorMargin; - //text-wrap: normal; max-width: max-content; &:before { @@ -107,6 +149,5 @@ .--em { color: $colorBodyFgEm; - //font-weight: bold; } } diff --git a/src/ui/components/toggle-switch.scss b/src/ui/components/toggle-switch.scss index 402af4c082..f2f6f85533 100644 --- a/src/ui/components/toggle-switch.scss +++ b/src/ui/components/toggle-switch.scss @@ -25,6 +25,7 @@ .c-toggle-switch { cursor: pointer; display: inline-flex; + gap: $interiorMarginSm; align-items: center; vertical-align: middle; @@ -55,7 +56,6 @@ } &__label { - margin-left: $interiorMarginSm; white-space: nowrap; } From 7508b01e6fa503f4094a962f3412255f256045ae Mon Sep 17 00:00:00 2001 From: Khalid Adil Date: Tue, 3 Dec 2024 04:07:57 -0600 Subject: [PATCH 139/139] Evaluate all criteria --- .../condition/HistoricalTelemetryProvider.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/plugins/condition/HistoricalTelemetryProvider.js b/src/plugins/condition/HistoricalTelemetryProvider.js index cc03887d57..6d866d5af1 100644 --- a/src/plugins/condition/HistoricalTelemetryProvider.js +++ b/src/plugins/condition/HistoricalTelemetryProvider.js @@ -1,3 +1,5 @@ +import { evaluateResults } from './utils/evaluator.js'; + export default class HistoricalTelemetryProvider { #telemetryOptions; #telemetryObjects = {}; @@ -70,12 +72,17 @@ export default class HistoricalTelemetryProvider { for (let conditionIndex = 0; conditionIndex < this.#conditions.length; conditionIndex++) { const condition = this.#conditions[conditionIndex]; const { id } = condition; - const conditionCriteria = condition.criteria?.[0]; + const conditionCriteria = condition?.criteria.length > 0; let result = false; let defaultHit = false; if (conditionCriteria) { - const inputTelemetry = this.#getInputTelemetry(conditionCriteria, dataFrame, timestamp); - result = conditionCriteria.computeResult({ id, ...inputTelemetry }); + result = evaluateResults( + condition.criteria.map((criterion) => { + const inputTelemetry = this.#getInputTelemetry(criterion, dataFrame, timestamp); + return criterion.computeResult({ id, ...inputTelemetry }); + }), + condition?.trigger + ); } else { // default criteria is 'all' defaultHit = true;