From 0a0826f87e2ef43261d645f893b2d93f5c8beb39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 21:28:43 +0000 Subject: [PATCH 001/161] Bump plotly.js-basic-dist from 2.5.0 to 2.12.0 (#5153) * Bump plotly.js-basic-dist, plotly-gl2d from 2.5.0 to 2.12.0 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shefali Joshi --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9f6c33a307..a2d26fced0 100644 --- a/package.json +++ b/package.json @@ -57,8 +57,8 @@ "moment-timezone": "0.5.34", "node-bourbon": "4.2.3", "painterro": "1.2.56", - "plotly.js-basic-dist": "2.5.0", - "plotly.js-gl2d-dist": "2.5.0", + "plotly.js-basic-dist": "2.12.0", + "plotly.js-gl2d-dist": "2.12.0", "printj": "1.3.1", "request": "2.88.2", "resolve-url-loader": "5.0.0", From 58387e0902d39fc9ec26b492517aa6dea56aef78 Mon Sep 17 00:00:00 2001 From: Shefali Joshi Date: Mon, 9 May 2022 14:38:49 -0700 Subject: [PATCH 002/161] Prepare for release 2.0.4 (#5176) * Bump d3-selection from 1.3.2 to 3.0.0 Bumps [d3-selection](https://github.com/d3/d3-selection) from 1.3.2 to 3.0.0. - [Release notes](https://github.com/d3/d3-selection/releases) - [Commits](https://github.com/d3/d3-selection/compare/v1.3.2...v3.0.0) --- updated-dependencies: - dependency-name: d3-selection dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Prepare for sprint 2.0.4 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: John Hill --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a2d26fced0..efa576e240 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openmct", - "version": "2.0.3", + "version": "2.0.4-SNAPSHOT", "description": "The Open MCT core platform", "devDependencies": { "@babel/eslint-parser": "7.16.3", From 815e7d169c86c474fba9847a541ddf8964e2a772 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 20:26:35 -0700 Subject: [PATCH 003/161] Bump @percy/playwright from 1.0.2 to 1.0.3 (#5174) Bumps [@percy/playwright](https://github.com/percy/percy-playwright) from 1.0.2 to 1.0.3. - [Release notes](https://github.com/percy/percy-playwright/releases) - [Commits](https://github.com/percy/percy-playwright/compare/v1.0.2...v1.0.3) --- updated-dependencies: - dependency-name: "@percy/playwright" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index efa576e240..d79d3da691 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "@babel/eslint-parser": "7.16.3", "@braintree/sanitize-url": "6.0.0", "@percy/cli": "1.0.4", - "@percy/playwright": "1.0.2", + "@percy/playwright": "1.0.3", "@playwright/test": "1.21.1", "@types/eventemitter3": "^1.0.0", "@types/jasmine": "^4.0.1", From b8d9e41c019a3a04567d8638a8418c9662c01d53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 May 2022 03:37:05 +0000 Subject: [PATCH 004/161] Bump karma-coverage from 2.1.1 to 2.2.0 (#5181) Bumps [karma-coverage](https://github.com/karma-runner/karma-coverage) from 2.1.1 to 2.2.0. - [Release notes](https://github.com/karma-runner/karma-coverage/releases) - [Changelog](https://github.com/karma-runner/karma-coverage/blob/master/CHANGELOG.md) - [Commits](https://github.com/karma-runner/karma-coverage/compare/v2.1.1...v2.2.0) --- updated-dependencies: - dependency-name: karma-coverage dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d79d3da691..af5e219150 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "karma": "6.3.18", "karma-chrome-launcher": "3.1.1", "karma-cli": "2.0.0", - "karma-coverage": "2.1.1", + "karma-coverage": "2.2.0", "karma-coverage-istanbul-reporter": "3.0.3", "karma-firefox-launcher": "2.1.2", "karma-jasmine": "4.0.1", From 09da373d1cba66567e9447a1be3cc74a4ba9dd93 Mon Sep 17 00:00:00 2001 From: John Hill Date: Fri, 13 May 2022 10:55:34 -0700 Subject: [PATCH 005/161] Add console error checking to our e2e suite (#5177) Co-authored-by: unlikelyzero --- .github/ISSUE_TEMPLATE/bug_report.md | 1 + e2e/fixtures.js | 27 +++++++++++++++++++ e2e/tests/branding.e2e.spec.js | 3 ++- e2e/tests/example/eventGenerator.e2e.spec.js | 3 ++- .../SinewaveLimitProvider.e2e.spec.js | 3 ++- e2e/tests/moveObjects.e2e.spec.js | 3 ++- .../persistence/persistability.e2e.spec.js | 3 ++- .../ExportAsJSON/exportAsJson.e2e.spec.js | 3 ++- .../ImportAsJSON/importAsJson.e2e.spec.js | 3 ++- e2e/tests/plugins/clock/Clock.e2e.spec.js | 3 ++- .../plugins/condition/condition.e2e.spec.js | 3 ++- .../imagery/exampleImagery.e2e.spec.js | 6 ++++- e2e/tests/plugins/plot/autoscale.e2e.spec.js | 8 ++++-- e2e/tests/plugins/plot/logPlot.e2e.spec.js | 8 ++++-- .../timeConductor/timeConductor.e2e.spec.js | 8 +++--- e2e/tests/smoke.e2e.spec.js | 3 ++- package.json | 2 +- 17 files changed, 70 insertions(+), 20 deletions(-) create mode 100644 e2e/fixtures.js diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5fe33cf1ba..7ba460118a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -40,6 +40,7 @@ assignees: '' - [ ] Is there a workaround available? - [ ] Does this impact a critical component? - [ ] Is this just a visual bug with no functional impact? +- [ ] Does this block the execution of e2e tests? #### Additional Information diff --git a/e2e/fixtures.js b/e2e/fixtures.js new file mode 100644 index 0000000000..aef1399af5 --- /dev/null +++ b/e2e/fixtures.js @@ -0,0 +1,27 @@ +/* eslint-disable no-undef */ + +// This file extends the base functionality of the playwright test framework +const base = require('@playwright/test'); +const { expect } = require('@playwright/test'); + +exports.test = base.test.extend({ + page: async ({ baseURL, page }, use) => { + const messages = []; + page.on('console', msg => messages.push(`[${msg.type()}] ${msg.text()}`)); + await use(page); + await expect.soft(messages.toString()).not.toContain('[error]'); + }, + browser: async ({ playwright, browser }, use, workerInfo) => { + // Use browserless if configured + if (workerInfo.project.name.match(/browserless/)) { + const vBrowser = await playwright.chromium.connectOverCDP({ + endpointURL: 'ws://localhost:3003' + }); + await use(vBrowser); + } else { + // Use Local Browser for testing. + await use(browser); + } + } +}); + diff --git a/e2e/tests/branding.e2e.spec.js b/e2e/tests/branding.e2e.spec.js index 7a8c1b63d0..f86cc23b2c 100644 --- a/e2e/tests/branding.e2e.spec.js +++ b/e2e/tests/branding.e2e.spec.js @@ -24,7 +24,8 @@ This test suite is dedicated to tests which verify branding related components. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('Branding tests', () => { test('About Modal launches with basic branding properties', async ({ page }) => { diff --git a/e2e/tests/example/eventGenerator.e2e.spec.js b/e2e/tests/example/eventGenerator.e2e.spec.js index facd49059b..c94d652af4 100644 --- a/e2e/tests/example/eventGenerator.e2e.spec.js +++ b/e2e/tests/example/eventGenerator.e2e.spec.js @@ -24,7 +24,8 @@ This test suite is dedicated to tests which verify the basic operations surrounding the example event generator. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('Example Event Generator Operations', () => { test('Can create example event generator with a name', async ({ page }) => { diff --git a/e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js b/e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js index 6bf747aac3..24aad40a8b 100644 --- a/e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js +++ b/e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js @@ -24,7 +24,8 @@ This test suite is dedicated to tests which verify the basic operations surrounding conditionSets. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('Sine Wave Generator', () => { test('Create new Sine Wave Generator Object and validate create Form Logic', async ({ page }) => { diff --git a/e2e/tests/moveObjects.e2e.spec.js b/e2e/tests/moveObjects.e2e.spec.js index d6e28ee381..81a7bc9b7a 100644 --- a/e2e/tests/moveObjects.e2e.spec.js +++ b/e2e/tests/moveObjects.e2e.spec.js @@ -24,7 +24,8 @@ This test suite is dedicated to tests which verify the basic operations surrounding moving objects. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('Move item tests', () => { test('Create a basic object and verify that it can be moved to another folder', async ({ page }) => { diff --git a/e2e/tests/persistence/persistability.e2e.spec.js b/e2e/tests/persistence/persistability.e2e.spec.js index 56e48e6585..a9bec6a18a 100644 --- a/e2e/tests/persistence/persistability.e2e.spec.js +++ b/e2e/tests/persistence/persistability.e2e.spec.js @@ -24,7 +24,8 @@ This test suite is dedicated to tests which verify the basic operations surrounding conditionSets. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../fixtures.js'); +const { expect } = require('@playwright/test'); const path = require('path'); // https://github.com/nasa/openmct/issues/4323#issuecomment-1067282651 diff --git a/e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js b/e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js index 96c41c463d..f2095b351c 100644 --- a/e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js +++ b/e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js @@ -24,7 +24,8 @@ This test suite is dedicated to tests which verify the basic operations surrounding exportAsJSON. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('ExportAsJSON', () => { test.fixme('Create a basic object and verify that it can be exported as JSON from Tree', async ({ page }) => { diff --git a/e2e/tests/plugins/ImportAsJSON/importAsJson.e2e.spec.js b/e2e/tests/plugins/ImportAsJSON/importAsJson.e2e.spec.js index 29516c2b0a..8b61fdf23d 100644 --- a/e2e/tests/plugins/ImportAsJSON/importAsJson.e2e.spec.js +++ b/e2e/tests/plugins/ImportAsJSON/importAsJson.e2e.spec.js @@ -24,7 +24,8 @@ This test suite is dedicated to tests which verify the basic operations surrounding importAsJSON. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('ExportAsJSON', () => { test.fixme('Verify that domain object can be importAsJSON from Tree', async ({ page }) => { diff --git a/e2e/tests/plugins/clock/Clock.e2e.spec.js b/e2e/tests/plugins/clock/Clock.e2e.spec.js index 7ff0274c81..bdf8843bc2 100644 --- a/e2e/tests/plugins/clock/Clock.e2e.spec.js +++ b/e2e/tests/plugins/clock/Clock.e2e.spec.js @@ -24,7 +24,8 @@ This test suite is dedicated to tests which verify the basic operations surrounding Clock. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('Clock Generator', () => { diff --git a/e2e/tests/plugins/condition/condition.e2e.spec.js b/e2e/tests/plugins/condition/condition.e2e.spec.js index 225752548c..5b4cc14850 100644 --- a/e2e/tests/plugins/condition/condition.e2e.spec.js +++ b/e2e/tests/plugins/condition/condition.e2e.spec.js @@ -26,7 +26,8 @@ suite is sharing state between tests which is considered an anti-pattern. Implim demonstrate some playwright for test developers. This pattern should not be re-used in other CRUD suites. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../../fixtures.js'); +const { expect } = require('@playwright/test'); let conditionSetUrl; let getConditionSetIdentifierFromUrl; diff --git a/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js b/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js index 960f16ebe3..5f79da590e 100644 --- a/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js +++ b/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js @@ -26,7 +26,8 @@ but only assume that example imagery is present. */ /* globals process */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('Example Imagery', () => { @@ -41,6 +42,9 @@ test.describe('Example Imagery', () => { // Click text=Example Imagery await page.click('text=Example Imagery'); + // Click on My Items in Tree. Workaround for https://github.com/nasa/openmct/issues/5184 + await page.click('form[name="mctForm"] a:has-text("My Items")'); + // Click text=OK await Promise.all([ page.waitForNavigation({waitUntil: 'networkidle'}), diff --git a/e2e/tests/plugins/plot/autoscale.e2e.spec.js b/e2e/tests/plugins/plot/autoscale.e2e.spec.js index ecbaee404c..c6f1b6cf75 100644 --- a/e2e/tests/plugins/plot/autoscale.e2e.spec.js +++ b/e2e/tests/plugins/plot/autoscale.e2e.spec.js @@ -24,7 +24,8 @@ Testsuite for plot autoscale. */ -const { test: _test, expect } = require('@playwright/test'); +const { test: _test } = require('../../../fixtures.js'); +const { expect } = require('@playwright/test'); // create a new `test` API that will not append platform details to snapshot // file names, only for the tests in this file, so that the same snapshots will @@ -47,7 +48,10 @@ test.use({ }); test.describe('ExportAsJSON', () => { - test.slow('User can set autoscale with a valid range @snapshot', async ({ page }) => { + test('User can set autoscale with a valid range @snapshot', async ({ page }) => { + //This is necessary due to the size of the test suite. + await test.setTimeout(120 * 1000); + await page.goto('/', { waitUntil: 'networkidle' }); await setTimeRange(page); diff --git a/e2e/tests/plugins/plot/logPlot.e2e.spec.js b/e2e/tests/plugins/plot/logPlot.e2e.spec.js index 5341139b37..1e040c402f 100644 --- a/e2e/tests/plugins/plot/logPlot.e2e.spec.js +++ b/e2e/tests/plugins/plot/logPlot.e2e.spec.js @@ -25,10 +25,14 @@ Tests to verify log plot functionality. Note this test suite if very much under necessarily be used for reference when writing new tests in this area. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('Log plot tests', () => { - test.slow('Log Plot ticks are functionally correct in regular and log mode and after refresh', async ({ page }) => { + test('Log Plot ticks are functionally correct in regular and log mode and after refresh', async ({ page }) => { + //This is necessary due to the size of the test suite. + await test.setTimeout(120 * 1000); + await makeOverlayPlot(page); await testRegularTicks(page); await enableEditMode(page); diff --git a/e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js b/e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js index 4ca27a474c..7d68c74097 100644 --- a/e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js +++ b/e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js @@ -20,7 +20,8 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -const { test, expect } = require('@playwright/test'); +const { test } = require('../../../fixtures.js'); +const { expect } = require('@playwright/test'); test.describe('Time counductor operations', () => { test('validate start time does not exceeds end time', async ({ page }) => { @@ -68,7 +69,6 @@ test.describe('Time counductor operations', () => { }); }); - // Testing instructions: // Try to change the realtime offsets when in realtime (local clock) mode. test.describe('Time conductor input fields real-time mode', () => { @@ -82,7 +82,7 @@ test.describe('Time conductor input fields real-time mode', () => { // Click fixed timespan button await page.locator('.c-button__label >> text=Fixed Timespan').click(); - // Click local clock + // Click local clock await page.locator('.icon-clock >> text=Local Clock').click(); // Click time offset button @@ -101,7 +101,7 @@ test.describe('Time conductor input fields real-time mode', () => { await page.locator('.c-conductor__delta-button >> text=00:00:30').click(); // Input preceding time offset - await page.fill('.pr-time-controls__secs', '31') + await page.fill('.pr-time-controls__secs', '31'); // Click the check buttons await page.locator('.icon-check').click(); diff --git a/e2e/tests/smoke.e2e.spec.js b/e2e/tests/smoke.e2e.spec.js index 0d8591b634..43e73972f5 100644 --- a/e2e/tests/smoke.e2e.spec.js +++ b/e2e/tests/smoke.e2e.spec.js @@ -33,7 +33,8 @@ comfortable running this test during a live mission?" Avoid creating or deleting Make no assumptions about the order that elements appear in the DOM. */ -const { test, expect } = require('@playwright/test'); +const { test } = require('../fixtures.js'); +const { expect } = require('@playwright/test'); test('Verify that the create button appears and that the Folder Domain Object is available for selection', async ({ page }) => { diff --git a/package.json b/package.json index af5e219150..cd7678d5ec 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "test": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run", "test:firefox": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=FirefoxHeadless", "test:debug": "cross-env NODE_ENV=debug karma start --no-single-run", - "test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke default condition timeConductor branding clock", + "test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke default condition timeConductor branding clock exampleImagery", "test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome", "test:e2e:updatesnapshots": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome --grep @snapshot --update-snapshots", "test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js default", From 03e7d912bea4d83540b4751b3eee5ecba56c2931 Mon Sep 17 00:00:00 2001 From: David Tsay <3614296+davetsay@users.noreply.github.com> Date: Mon, 16 May 2022 11:58:36 -0700 Subject: [PATCH 006/161] Warn user if telemetry not all telemetry metadata matches time system (#4996) * warn user if telemetry not all telemetry metadata matches time system * create spec file for telemetry collections * Add tests (#4999) - Test for warn if metadata does not match active TimeSystem - Test for no warn if metadata matches active TimeSystem * unset timeKey if no matching domain found * Extract errors to constants file and update tests Co-authored-by: Jesse Mazzella --- src/api/telemetry/TelemetryCollection.js | 29 ++++-- src/api/telemetry/TelemetryCollectionSpec.js | 101 +++++++++++++++++++ src/api/telemetry/constants.js | 25 +++++ 3 files changed, 144 insertions(+), 11 deletions(-) create mode 100644 src/api/telemetry/TelemetryCollectionSpec.js create mode 100644 src/api/telemetry/constants.js diff --git a/src/api/telemetry/TelemetryCollection.js b/src/api/telemetry/TelemetryCollection.js index 4386a4729e..14085c2ad1 100644 --- a/src/api/telemetry/TelemetryCollection.js +++ b/src/api/telemetry/TelemetryCollection.js @@ -22,11 +22,7 @@ import _ from 'lodash'; import EventEmitter from 'EventEmitter'; - -const ERRORS = { - TIMESYSTEM_KEY: 'All telemetry metadata must have a telemetry value with a key that matches the key of the active time system.', - LOADED: 'Telemetry Collection has already been loaded.' -}; +import { LOADED_ERROR, TIMESYSTEM_KEY_NOTIFICATION, TIMESYSTEM_KEY_WARNING } from './constants'; /** Class representing a Telemetry Collection. */ @@ -61,7 +57,7 @@ export class TelemetryCollection extends EventEmitter { */ load() { if (this.loaded) { - this._error(ERRORS.LOADED); + this._error(LOADED_ERROR); } this._setTimeSystem(this.openmct.time.timeSystem()); @@ -267,6 +263,10 @@ export class TelemetryCollection extends EventEmitter { this.lastBounds = bounds; if (isTick) { + if (this.timeKey === undefined) { + return; + } + // need to check futureBuffer and need to check // if anything has fallen out of bounds let startIndex = 0; @@ -306,7 +306,6 @@ export class TelemetryCollection extends EventEmitter { if (added.length > 0) { this.emit('add', added); } - } else { // user bounds change, reset this._reset(); @@ -326,12 +325,16 @@ export class TelemetryCollection extends EventEmitter { let domains = this.metadata.valuesForHints(['domain']); let domain = domains.find((d) => d.key === timeSystem.key); - if (domain === undefined) { - this._error(ERRORS.TIMESYSTEM_KEY); + if (domain !== undefined) { + // timeKey is used to create a dummy datum used for sorting + this.timeKey = domain.source; + } else { + this.timeKey = undefined; + + this._warn(TIMESYSTEM_KEY_WARNING); + this.openmct.notifications.alert(TIMESYSTEM_KEY_NOTIFICATION); } - // timeKey is used to create a dummy datum used for sorting - this.timeKey = domain.source; // this defaults to key if no source is set let metadataValue = this.metadata.value(timeSystem.key) || { format: timeSystem.key }; let valueFormatter = this.openmct.telemetry.getValueFormatter(metadataValue); @@ -402,4 +405,8 @@ export class TelemetryCollection extends EventEmitter { _error(message) { throw new Error(message); } + + _warn(message) { + console.warn(message); + } } diff --git a/src/api/telemetry/TelemetryCollectionSpec.js b/src/api/telemetry/TelemetryCollectionSpec.js new file mode 100644 index 0000000000..49907c3f5c --- /dev/null +++ b/src/api/telemetry/TelemetryCollectionSpec.js @@ -0,0 +1,101 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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 { + createOpenMct, + resetApplicationState +} from 'utils/testing'; +import { TIMESYSTEM_KEY_WARNING } from './constants'; + +describe('Telemetry Collection', () => { + let openmct; + let mockMetadataProvider; + let mockMetadata = {}; + let domainObject; + + beforeEach(done => { + openmct = createOpenMct(); + openmct.on('start', done); + + domainObject = { + identifier: { + key: 'a', + namespace: 'b' + }, + type: 'sample-type' + }; + + mockMetadataProvider = { + key: 'mockMetadataProvider', + supportsMetadata() { + return true; + }, + getMetadata() { + return mockMetadata; + } + }; + + openmct.telemetry.addProvider(mockMetadataProvider); + openmct.startHeadless(); + }); + + afterEach(() => { + return resetApplicationState(); + }); + + it('Warns if telemetry metadata does not match the active timesystem', () => { + mockMetadata.values = [ + { + key: 'foo', + name: 'Bar', + hints: { + domain: 1 + } + } + ]; + + const telemetryCollection = openmct.telemetry.requestCollection(domainObject); + spyOn(telemetryCollection, '_warn'); + telemetryCollection.load(); + + expect(telemetryCollection._warn).toHaveBeenCalledOnceWith(TIMESYSTEM_KEY_WARNING); + }); + + it('Does not warn if telemetry metadata matches the active timesystem', () => { + mockMetadata.values = [ + { + key: 'utc', + name: 'Timestamp', + format: 'utc', + hints: { + domain: 1 + } + } + ]; + + const telemetryCollection = openmct.telemetry.requestCollection(domainObject); + spyOn(telemetryCollection, '_warn'); + telemetryCollection.load(); + + expect(telemetryCollection._warn).not.toHaveBeenCalled(); + }); +}); diff --git a/src/api/telemetry/constants.js b/src/api/telemetry/constants.js new file mode 100644 index 0000000000..66b5c50bbe --- /dev/null +++ b/src/api/telemetry/constants.js @@ -0,0 +1,25 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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 const TIMESYSTEM_KEY_WARNING = 'All telemetry metadata must have a telemetry value with a key that matches the key of the active time system.'; +export const TIMESYSTEM_KEY_NOTIFICATION = 'Telemetry metadata does not match the active time system.'; +export const LOADED_ERROR = 'Telemetry Collection has already been loaded.'; From e6b5870234ac8acecab44788206109e287020251 Mon Sep 17 00:00:00 2001 From: John Hill Date: Tue, 17 May 2022 11:07:59 -0700 Subject: [PATCH 007/161] Update PR Template to include cases which ignore testing instructions (#5204) Co-authored-by: Shefali Joshi --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 89fb12a9e3..8cbde6e73d 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -16,7 +16,7 @@ Closes + + + + diff --git a/src/plugins/charts/scatter/ScatterPlotViewProvider.js b/src/plugins/charts/scatter/ScatterPlotViewProvider.js new file mode 100644 index 0000000000..338d2eb3e3 --- /dev/null +++ b/src/plugins/charts/scatter/ScatterPlotViewProvider.js @@ -0,0 +1,79 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, 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 ScatterPlotView from './ScatterPlotView.vue'; +import { SCATTER_PLOT_KEY, SCATTER_PLOT_VIEW, TIME_STRIP_KEY } from './scatterPlotConstants.js'; +import Vue from 'vue'; + +export default function ScatterPlotViewProvider(openmct) { + function isCompactView(objectPath) { + let isChildOfTimeStrip = objectPath.find(object => object.type === TIME_STRIP_KEY); + + return isChildOfTimeStrip && !openmct.router.isNavigatedObject(objectPath); + } + + return { + key: SCATTER_PLOT_VIEW, + name: 'Scatter Plot', + cssClass: 'icon-telemetry', + canView(domainObject, objectPath) { + return domainObject && domainObject.type === SCATTER_PLOT_KEY; + }, + + canEdit(domainObject, objectPath) { + return domainObject && domainObject.type === SCATTER_PLOT_KEY; + }, + + view: function (domainObject, objectPath) { + let component; + + return { + show: function (element) { + let isCompact = isCompactView(objectPath); + component = new Vue({ + el: element, + components: { + ScatterPlotView + }, + provide: { + openmct, + domainObject, + path: objectPath + }, + data() { + return { + options: { + compact: isCompact + } + }; + }, + template: '' + }); + }, + destroy: function () { + component.$destroy(); + component = undefined; + } + }; + } + }; +} diff --git a/src/plugins/charts/scatter/ScatterPlotWithUnderlay.vue b/src/plugins/charts/scatter/ScatterPlotWithUnderlay.vue new file mode 100644 index 0000000000..796a252ac7 --- /dev/null +++ b/src/plugins/charts/scatter/ScatterPlotWithUnderlay.vue @@ -0,0 +1,393 @@ + + + diff --git a/src/plugins/charts/scatter/inspector/PlotOptions.vue b/src/plugins/charts/scatter/inspector/PlotOptions.vue new file mode 100644 index 0000000000..a72fcb8c9a --- /dev/null +++ b/src/plugins/charts/scatter/inspector/PlotOptions.vue @@ -0,0 +1,64 @@ + + + + diff --git a/src/plugins/charts/scatter/inspector/PlotOptionsBrowse.vue b/src/plugins/charts/scatter/inspector/PlotOptionsBrowse.vue new file mode 100644 index 0000000000..c7af21973c --- /dev/null +++ b/src/plugins/charts/scatter/inspector/PlotOptionsBrowse.vue @@ -0,0 +1,153 @@ + + + + diff --git a/src/plugins/charts/scatter/inspector/PlotOptionsEdit.vue b/src/plugins/charts/scatter/inspector/PlotOptionsEdit.vue new file mode 100644 index 0000000000..6781a27777 --- /dev/null +++ b/src/plugins/charts/scatter/inspector/PlotOptionsEdit.vue @@ -0,0 +1,262 @@ + + + diff --git a/src/plugins/charts/scatter/inspector/ScatterPlotInspectorViewProvider.js b/src/plugins/charts/scatter/inspector/ScatterPlotInspectorViewProvider.js new file mode 100644 index 0000000000..54487dfe37 --- /dev/null +++ b/src/plugins/charts/scatter/inspector/ScatterPlotInspectorViewProvider.js @@ -0,0 +1,48 @@ +import { SCATTER_PLOT_INSPECTOR_KEY, SCATTER_PLOT_KEY } from '../scatterPlotConstants'; +import Vue from 'vue'; +import PlotOptions from "./PlotOptions.vue"; + +export default function ScatterPlotInspectorViewProvider(openmct) { + return { + key: SCATTER_PLOT_INSPECTOR_KEY, + name: 'Bar Graph Inspector View', + canView: function (selection) { + if (selection.length === 0 || selection[0].length === 0) { + return false; + } + + let object = selection[0][0].context.item; + + return object + && object.type === SCATTER_PLOT_KEY; + }, + view: function (selection) { + let component; + + return { + show: function (element) { + component = new Vue({ + el: element, + components: { + PlotOptions + }, + provide: { + openmct, + domainObject: selection[0][0].context.item + }, + template: '' + }); + }, + destroy: function () { + if (component) { + component.$destroy(); + component = undefined; + } + } + }; + }, + priority: function () { + return 1; + } + }; +} diff --git a/src/plugins/charts/scatter/plugin.js b/src/plugins/charts/scatter/plugin.js new file mode 100644 index 0000000000..600c2970fd --- /dev/null +++ b/src/plugins/charts/scatter/plugin.js @@ -0,0 +1,127 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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 { SCATTER_PLOT_KEY } from './scatterPlotConstants.js'; +import ScatterPlotViewProvider from './ScatterPlotViewProvider'; +import ScatterPlotInspectorViewProvider from './inspector/ScatterPlotInspectorViewProvider'; +import ScatterPlotCompositionPolicy from './ScatterPlotCompositionPolicy'; +import Vue from "vue"; +import ScatterPlotForm from "./ScatterPlotForm.vue"; + +export default function () { + return function install(openmct) { + openmct.forms.addNewFormControl('scatter-plot-form-control', getScatterPlotFormControl(openmct)); + + openmct.types.addType(SCATTER_PLOT_KEY, { + key: SCATTER_PLOT_KEY, + name: "Scatter Plot", + cssClass: "icon-plot-scatter", + description: "View data as a scatter plot.", + creatable: true, + initialize: function (domainObject) { + domainObject.composition = []; + domainObject.configuration = { + styles: {}, + axes: {}, + ranges: {} + }; + }, + form: [ + { + name: 'Underlay data (JSON file)', + key: 'selectFile', + control: 'file-input', + text: 'Select File...', + type: 'application/json', + removable: true, + hideFromInspector: true, + property: [ + "selectFile" + ] + }, + { + name: "Underlay ranges", + control: "scatter-plot-form-control", + cssClass: "l-input", + key: "scatterPlotForm", + required: false, + hideFromInspector: false, + property: [ + "configuration", + "ranges" + ], + validate: ({ value }, callback) => { + const { rangeMin, rangeMax, domainMin, domainMax } = value; + const valid = { + rangeMin, + rangeMax, + domainMin, + domainMax + }; + + if (callback) { + callback(valid); + } + + const values = Object.values(valid); + const hasAllValues = values.every(rangeValue => rangeValue !== undefined); + const hasNoValues = values.every(rangeValue => rangeValue === undefined); + + return hasAllValues || hasNoValues; + } + } + ], + priority: 891 + }); + + openmct.objectViews.addProvider(new ScatterPlotViewProvider(openmct)); + + openmct.inspectorViews.addProvider(new ScatterPlotInspectorViewProvider(openmct)); + + openmct.composition.addPolicy(new ScatterPlotCompositionPolicy(openmct).allow); + }; + + function getScatterPlotFormControl(openmct) { + return { + show(element, model, onChange) { + const rowComponent = new Vue({ + el: element, + components: { + ScatterPlotForm + }, + provide: { + openmct + }, + data() { + return { + model, + onChange + }; + }, + template: `` + }); + + return rowComponent; + } + }; + } +} + diff --git a/src/plugins/charts/scatter/pluginSpec.js b/src/plugins/charts/scatter/pluginSpec.js new file mode 100644 index 0000000000..2eb17c7a45 --- /dev/null +++ b/src/plugins/charts/scatter/pluginSpec.js @@ -0,0 +1,421 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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 {createOpenMct, resetApplicationState} from "utils/testing"; +import Vue from "vue"; +import ScatterPlotPlugin from "./plugin"; +import ScatterPlot from './ScatterPlotView.vue'; +import EventEmitter from "EventEmitter"; +import { SCATTER_PLOT_VIEW, SCATTER_PLOT_KEY } from './scatterPlotConstants'; + +describe("the plugin", function () { + let element; + let child; + let openmct; + let telemetryPromise; + let telemetryPromiseResolve; + let mockObjectPath; + + beforeEach((done) => { + mockObjectPath = [ + { + name: 'mock folder', + type: 'fake-folder', + identifier: { + key: 'mock-folder', + namespace: '' + } + } + ]; + const testTelemetry = [ + { + 'utc': 1, + 'some-key': 'some-value 1', + 'some-other-key': 'some-other-value 1' + }, + { + 'utc': 2, + 'some-key': 'some-value 2', + 'some-other-key': 'some-other-value 2' + }, + { + 'utc': 3, + 'some-key': 'some-value 3', + 'some-other-key': 'some-other-value 3' + } + ]; + + openmct = createOpenMct(); + + telemetryPromise = new Promise((resolve) => { + telemetryPromiseResolve = resolve; + }); + + spyOn(openmct.telemetry, 'request').and.callFake(() => { + telemetryPromiseResolve(testTelemetry); + + return telemetryPromise; + }); + + openmct.install(new ScatterPlotPlugin()); + + element = document.createElement("div"); + element.style.width = "640px"; + element.style.height = "480px"; + child = document.createElement("div"); + child.style.width = "640px"; + child.style.height = "480px"; + element.appendChild(child); + document.body.appendChild(element); + + spyOn(window, 'ResizeObserver').and.returnValue({ + observe() {}, + unobserve() {}, + disconnect() {} + }); + + openmct.time.timeSystem("utc", { + start: 0, + end: 4 + }); + + openmct.types.addType("test-object", { + creatable: true + }); + + openmct.on("start", done); + openmct.startHeadless(); + }); + + afterEach((done) => { + openmct.time.timeSystem('utc', { + start: 0, + end: 1 + }); + resetApplicationState(openmct).then(done).catch(done); + }); + + describe("The scatter plot view", () => { + let testDomainObject; + let scatterPlotObject; + // eslint-disable-next-line no-unused-vars + let component; + let mockComposition; + + beforeEach(async () => { + scatterPlotObject = { + identifier: { + namespace: "", + key: "test-plot" + }, + type: "telemetry.plot.scatter-plot", + name: "Test Scatter Plot", + configuration: { + axes: {}, + styles: {} + } + }; + + testDomainObject = { + identifier: { + namespace: "", + key: "test-object" + }, + type: "test-object", + name: "Test Object", + telemetry: { + values: [{ + key: "utc", + format: "utc", + name: "Time", + hints: { + domain: 1 + } + }, { + key: "some-key", + name: "Some attribute", + hints: { + range: 1 + } + }, { + key: "some-other-key", + name: "Another attribute", + hints: { + range: 2 + } + }] + } + }; + + mockComposition = new EventEmitter(); + mockComposition.load = () => { + mockComposition.emit('add', testDomainObject); + + return [testDomainObject]; + }; + + spyOn(openmct.composition, 'get').and.returnValue(mockComposition); + + let viewContainer = document.createElement("div"); + child.append(viewContainer); + component = new Vue({ + el: viewContainer, + components: { + ScatterPlot + }, + provide: { + openmct: openmct, + domainObject: scatterPlotObject, + composition: openmct.composition.get(scatterPlotObject) + }, + template: "" + }); + + await Vue.nextTick(); + }); + + it("provides a scatter plot view", () => { + const applicableViews = openmct.objectViews.get(scatterPlotObject, mockObjectPath); + const plotViewProvider = applicableViews.find((viewProvider) => viewProvider.key === SCATTER_PLOT_VIEW); + expect(plotViewProvider).toBeDefined(); + }); + + it("Renders plotly scatter plot", () => { + let scatterPlotElement = element.querySelectorAll(".plotly"); + expect(scatterPlotElement.length).toBe(1); + }); + }); + + describe("the scatter plot objects", () => { + const mockObject = { + name: 'A very nice scatter plot', + key: SCATTER_PLOT_KEY, + creatable: true + }; + + it('defines a scatter plot object type with the correct key', () => { + const objectDef = openmct.types.get(SCATTER_PLOT_KEY).definition; + expect(objectDef.key).toEqual(mockObject.key); + }); + + it('is creatable', () => { + const objectDef = openmct.types.get(SCATTER_PLOT_KEY).definition; + expect(objectDef.creatable).toEqual(mockObject.creatable); + }); + }); + + describe("The scatter plot composition policy", () => { + it("allows composition for telemetry that contain at least 2 ranges", () => { + const parent = { + "composition": [], + "configuration": { + axes: {}, + styles: {} + }, + "name": "Some Scatter Plot", + "type": "telemetry.plot.scatter-plot", + "location": "mine", + "modified": 1631005183584, + "persisted": 1631005183502, + "identifier": { + "namespace": "", + "key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9" + } + }; + const testTelemetryObject = { + identifier: { + namespace: "", + key: "test-object" + }, + type: "test-object", + name: "Test Object", + telemetry: { + values: [{ + key: "some-key", + name: "Some attribute", + hints: { + domain: 1 + } + }, { + key: "some-other-key", + name: "Another attribute", + hints: { + range: 1 + } + }, { + key: "some-other-key2", + name: "Another attribute2", + hints: { + range: 2 + } + }] + } + }; + const composition = openmct.composition.get(parent); + expect(() => { + composition.add(testTelemetryObject); + }).not.toThrow(); + expect(parent.composition.length).toBe(1); + }); + + it("disallows composition for telemetry that don't contain at least 2 range hints", () => { + const parent = { + "composition": [], + "configuration": { + axes: {}, + styles: {} + }, + "name": "Some Scatter Plot", + "type": "telemetry.plot.scatter-plot", + "location": "mine", + "modified": 1631005183584, + "persisted": 1631005183502, + "identifier": { + "namespace": "", + "key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9" + } + }; + const testTelemetryObject = { + identifier: { + namespace: "", + key: "test-object" + }, + type: "test-object", + name: "Test Object", + telemetry: { + values: [{ + key: "some-key", + name: "Some attribute", + hints: { + domain: 1 + } + }, { + key: "some-other-key", + name: "Another attribute", + hints: { + range: 1 + } + }] + } + }; + const composition = openmct.composition.get(parent); + expect(() => { + composition.add(testTelemetryObject); + }).toThrow(); + expect(parent.composition.length).toBe(0); + }); + }); + describe('the inspector view', () => { + let mockComposition; + let testDomainObject; + let selection; + let plotInspectorView; + let viewContainer; + let optionsElement; + beforeEach(async () => { + testDomainObject = { + identifier: { + namespace: "", + key: "test-object" + }, + type: "test-object", + name: "Test Object", + telemetry: { + values: [{ + key: "utc", + format: "utc", + name: "Time", + hints: { + domain: 1 + } + }, { + key: "some-key", + name: "Some attribute", + hints: { + range: 1 + } + }, { + key: "some-other-key", + name: "Another attribute", + hints: { + range: 2 + } + }] + } + }; + + selection = [ + [ + { + context: { + item: { + id: "test-object", + identifier: { + key: "test-object", + namespace: '' + }, + type: "telemetry.plot.scatter-plot", + configuration: { + axes: {}, + styles: { + } + }, + composition: [ + { + key: '~Some~foo.scatter' + } + ] + } + } + } + ] + ]; + + mockComposition = new EventEmitter(); + mockComposition.load = () => { + mockComposition.emit('add', testDomainObject); + + return [testDomainObject]; + }; + + spyOn(openmct.composition, 'get').and.returnValue(mockComposition); + + viewContainer = document.createElement('div'); + child.append(viewContainer); + + const applicableViews = openmct.inspectorViews.get(selection); + plotInspectorView = applicableViews[0]; + plotInspectorView.show(viewContainer); + + await Vue.nextTick(); + optionsElement = element.querySelector('.c-scatter-plot-options'); + }); + + afterEach(() => { + plotInspectorView.destroy(); + }); + + it('it renders the options', () => { + expect(optionsElement).toBeDefined(); + }); + }); +}); diff --git a/src/plugins/charts/scatter/scatterPlotConstants.js b/src/plugins/charts/scatter/scatterPlotConstants.js new file mode 100644 index 0000000000..e458be37c6 --- /dev/null +++ b/src/plugins/charts/scatter/scatterPlotConstants.js @@ -0,0 +1,4 @@ +export const SCATTER_PLOT_VIEW = 'scatter-plot.view'; +export const SCATTER_PLOT_KEY = 'telemetry.plot.scatter-plot'; +export const SCATTER_PLOT_INSPECTOR_KEY = 'telemetry.plot.scatter-plot.inspector'; +export const TIME_STRIP_KEY = 'time-strip'; diff --git a/src/plugins/plan/Plan.vue b/src/plugins/plan/Plan.vue index 1f34e97a6f..89ad45bdd8 100644 --- a/src/plugins/plan/Plan.vue +++ b/src/plugins/plan/Plan.vue @@ -49,7 +49,7 @@ import * as d3Scale from 'd3-scale'; import TimelineAxis from "../../ui/components/TimeSystemAxis.vue"; import SwimLane from "@/ui/components/swim-lane/SwimLane.vue"; -import { getValidatedPlan } from "./util"; +import { getValidatedData } from "./util"; import Vue from "vue"; const PADDING = 1; @@ -161,7 +161,7 @@ export default { return clientWidth - 200; }, getPlanData(domainObject) { - this.planData = getValidatedPlan(domainObject); + this.planData = getValidatedData(domainObject); }, updateViewBounds(bounds) { if (bounds) { diff --git a/src/plugins/plan/util.js b/src/plugins/plan/util.js index cf119412f4..c5e3cc6b83 100644 --- a/src/plugins/plan/util.js +++ b/src/plugins/plan/util.js @@ -20,7 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -export function getValidatedPlan(domainObject) { +export function getValidatedData(domainObject) { let sourceMap = domainObject.sourceMap; let body = domainObject.selectFile.body; let json = {}; diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index 6b20e3c318..7beccebd54 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -37,7 +37,8 @@ define([ './URLIndicatorPlugin/URLIndicatorPlugin', './telemetryMean/plugin', './plot/plugin', - './charts/plugin', + './charts/bar/plugin', + './charts/scatter/plugin', './telemetryTable/plugin', './staticRootPlugin/plugin', './notebook/plugin', @@ -96,7 +97,8 @@ define([ URLIndicatorPlugin, TelemetryMean, PlotPlugin, - ChartPlugin, + BarChartPlugin, + ScatterPlotPlugin, TelemetryTablePlugin, StaticRootPlugin, Notebook, @@ -172,7 +174,8 @@ define([ plugins.ImageryPlugin = ImageryPlugin; plugins.Plot = PlotPlugin.default; - plugins.Chart = ChartPlugin.default; + plugins.BarChart = BarChartPlugin.default; + plugins.ScatterPlot = ScatterPlotPlugin.default; plugins.TelemetryTable = TelemetryTablePlugin; plugins.SummaryWidget = SummaryWidget; diff --git a/src/plugins/timeline/TimelineViewLayout.vue b/src/plugins/timeline/TimelineViewLayout.vue index b1764ec1ab..cc327b22a8 100644 --- a/src/plugins/timeline/TimelineViewLayout.vue +++ b/src/plugins/timeline/TimelineViewLayout.vue @@ -61,7 +61,7 @@ import TimelineObjectView from './TimelineObjectView.vue'; import TimelineAxis from '../../ui/components/TimeSystemAxis.vue'; import SwimLane from "@/ui/components/swim-lane/SwimLane.vue"; -import { getValidatedPlan } from "../plan/util"; +import { getValidatedData } from "../plan/util"; const unknownObjectType = { definition: { @@ -110,7 +110,7 @@ export default { let objectPath = [domainObject].concat(this.objectPath.slice()); let rowCount = 0; if (domainObject.type === 'plan') { - rowCount = Object.keys(getValidatedPlan(domainObject)).length; + rowCount = Object.keys(getValidatedData(domainObject)).length; } let height = domainObject.type === 'telemetry.plot.stacked' ? `${domainObject.composition.length * 100}px` : '100px'; diff --git a/src/plugins/timelist/Timelist.vue b/src/plugins/timelist/Timelist.vue index 517822cd6b..188c958008 100644 --- a/src/plugins/timelist/Timelist.vue +++ b/src/plugins/timelist/Timelist.vue @@ -35,7 +35,7 @@ diff --git a/src/MCT.js b/src/MCT.js index 3ea51a1d4e..0e46eab52e 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -242,8 +242,6 @@ define([ // Plugins that are installed by default this.install(this.plugins.Plot()); - this.install(this.plugins.ScatterPlot()); - this.install(this.plugins.BarChart()); this.install(this.plugins.TelemetryTable.default()); this.install(PreviewPlugin.default()); this.install(LicensesPlugin.default()); From 77804cff75a19b3fe79d4de970f63e246c2e9737 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 May 2022 19:06:32 +0000 Subject: [PATCH 029/161] Bump @percy/cli from 1.0.4 to 1.2.1 (#5244) Bumps [@percy/cli](https://github.com/percy/cli/tree/HEAD/packages/cli) from 1.0.4 to 1.2.1. - [Release notes](https://github.com/percy/cli/releases) - [Commits](https://github.com/percy/cli/commits/v1.2.1/packages/cli) --- updated-dependencies: - dependency-name: "@percy/cli" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: John Hill --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 91ecfed7c0..622b494fe1 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "devDependencies": { "@babel/eslint-parser": "7.16.3", "@braintree/sanitize-url": "6.0.0", - "@percy/cli": "1.0.4", + "@percy/cli": "1.2.1", "@percy/playwright": "1.0.3", "@playwright/test": "1.21.1", "@types/eventemitter3": "^1.0.0", From 7bb108c36b124695f976a4da5476c6a93efd53d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 May 2022 19:28:04 +0000 Subject: [PATCH 030/161] Bump webpack-dev-middleware from 5.3.1 to 5.3.3 (#5242) Bumps [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) from 5.3.1 to 5.3.3. - [Release notes](https://github.com/webpack/webpack-dev-middleware/releases) - [Changelog](https://github.com/webpack/webpack-dev-middleware/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-dev-middleware/compare/v5.3.1...v5.3.3) --- updated-dependencies: - dependency-name: webpack-dev-middleware dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: John Hill --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 622b494fe1..652d261ccf 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "vue-template-compiler": "2.6.14", "webpack": "5.68.0", "webpack-cli": "4.9.2", - "webpack-dev-middleware": "5.3.1", + "webpack-dev-middleware": "5.3.3", "webpack-hot-middleware": "2.25.1", "webpack-merge": "5.8.0", "zepto": "1.2.0" From d9ac0182c394903f3a7bd9d92c2c88a364924811 Mon Sep 17 00:00:00 2001 From: John Hill Date: Tue, 24 May 2022 13:10:14 -0700 Subject: [PATCH 031/161] Remove languages from bug report as we don't need it (#5213) Co-authored-by: Andrew Henry --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7ba460118a..747ec79bb6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -27,7 +27,7 @@ assignees: '' #### Environment + * Open MCT Version: * Deployment Type: * OS: From f74a35f45ae903ef4bb9514fd73959b591c0bb52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 May 2022 16:09:08 -0500 Subject: [PATCH 032/161] Bump uuid from 3.3.3 to 8.3.2 (#5170) --- example/exampleUser/ExampleUserProvider.js | 2 +- package.json | 2 +- src/api/forms/components/FormProperties.vue | 2 +- src/api/forms/components/controls/ToggleSwitchField.vue | 2 +- src/api/objects/InMemorySearchProvider.js | 2 +- src/exporters/ImageExporter.js | 2 +- src/plugins/condition/Condition.js | 2 +- src/plugins/condition/ConditionManager.js | 2 +- src/plugins/condition/components/Condition.vue | 2 +- src/plugins/condition/plugin.js | 2 +- src/plugins/displayLayout/components/DisplayLayout.vue | 2 +- src/plugins/duplicate/DuplicateTask.js | 2 +- src/plugins/exportAsJSONAction/ExportAsJSONAction.js | 2 +- src/plugins/flexibleLayout/utils/container.js | 2 +- src/plugins/flexibleLayout/utils/frame.js | 2 +- src/plugins/formActions/CreateAction.js | 2 +- src/plugins/importFromJSONAction/ImportFromJSONAction.js | 2 +- src/plugins/notebook/components/Sidebar.vue | 2 +- src/plugins/notebook/utils/notebook-image.js | 2 +- src/plugins/plan/inspector/PlanActivitiesView.vue | 2 +- src/plugins/plan/inspector/PlanActivityView.vue | 2 +- src/plugins/timelist/Timelist.vue | 2 +- src/utils/textHighlight/TextHighlight.vue | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/example/exampleUser/ExampleUserProvider.js b/example/exampleUser/ExampleUserProvider.js index bf25d7aaed..7e17de98ef 100644 --- a/example/exampleUser/ExampleUserProvider.js +++ b/example/exampleUser/ExampleUserProvider.js @@ -21,7 +21,7 @@ *****************************************************************************/ import EventEmitter from 'EventEmitter'; -import uuid from 'uuid'; +import { v4 as uuid } from 'uuid'; import createExampleUser from './exampleUserCreator'; export default class ExampleUserProvider extends EventEmitter { diff --git a/package.json b/package.json index 652d261ccf..5c58eb927a 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "sass-loader": "12.6.0", "sinon": "14.0.0", "style-loader": "^1.0.1", - "uuid": "3.3.3", + "uuid": "8.3.2", "vue": "2.6.14", "vue-eslint-parser": "8.3.0", "vue-loader": "15.9.8", diff --git a/src/api/forms/components/FormProperties.vue b/src/api/forms/components/FormProperties.vue index c43dca08d4..eac28b2f7e 100644 --- a/src/api/forms/components/FormProperties.vue +++ b/src/api/forms/components/FormProperties.vue @@ -81,7 +81,7 @@ diff --git a/src/plugins/operatorStatus/operatorStatus/OperatorStatusIndicator.js b/src/plugins/operatorStatus/operatorStatus/OperatorStatusIndicator.js new file mode 100644 index 0000000000..9eb96e938c --- /dev/null +++ b/src/plugins/operatorStatus/operatorStatus/OperatorStatusIndicator.js @@ -0,0 +1,63 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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 Vue from 'vue'; + +import AbstractStatusIndicator from '../AbstractStatusIndicator'; +import OperatorStatusComponent from './OperatorStatus.vue'; + +export default class OperatorStatusIndicator extends AbstractStatusIndicator { + createPopupComponent() { + const indicator = this.getIndicator(); + const popupElement = new Vue({ + components: { + OperatorStatus: OperatorStatusComponent + }, + provide: { + openmct: this.openmct, + indicator: indicator, + configuration: this.getConfiguration() + }, + data() { + return { + positionX: 0, + positionY: 0 + }; + }, + template: '' + }).$mount(); + + return popupElement; + } + + createIndicator() { + const operatorIndicator = this.openmct.indicators.simpleIndicator(); + + operatorIndicator.text("My Operator Status"); + operatorIndicator.description("Set my operator status"); + operatorIndicator.iconClass('icon-status-poll-question-mark'); + operatorIndicator.element.classList.add("c-indicator--operator-status"); + operatorIndicator.element.classList.add("no-minify"); + operatorIndicator.on('click', this.showPopup); + + return operatorIndicator; + } +} diff --git a/src/plugins/operatorStatus/plugin.js b/src/plugins/operatorStatus/plugin.js new file mode 100644 index 0000000000..3d449d1ebd --- /dev/null +++ b/src/plugins/operatorStatus/plugin.js @@ -0,0 +1,50 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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 OperatorStatusIndicator from './operatorStatus/OperatorStatusIndicator'; +import PollQuestionIndicator from './pollQuestion/PollQuestionIndicator'; + +/** + * @param {import('@/api/user/UserAPI').UserAPIConfiguration} configuration + * @returns {function} The plugin install function + */ +export default function operatorStatusPlugin(configuration) { + return function install(openmct) { + + if (openmct.user.hasProvider()) { + openmct.user.status.canProvideStatusForCurrentUser().then(canProvideStatus => { + if (canProvideStatus) { + const operatorStatusIndicator = new OperatorStatusIndicator(openmct, configuration); + + operatorStatusIndicator.install(); + } + }); + + openmct.user.status.canSetPollQuestion().then(canSetPollQuestion => { + if (canSetPollQuestion) { + const pollQuestionIndicator = new PollQuestionIndicator(openmct, configuration); + + pollQuestionIndicator.install(); + } + }); + } + }; +} diff --git a/src/plugins/operatorStatus/pollQuestion/PollQuestion.vue b/src/plugins/operatorStatus/pollQuestion/PollQuestion.vue new file mode 100644 index 0000000000..f279e57975 --- /dev/null +++ b/src/plugins/operatorStatus/pollQuestion/PollQuestion.vue @@ -0,0 +1,184 @@ + + + + diff --git a/src/plugins/operatorStatus/pollQuestion/PollQuestionIndicator.js b/src/plugins/operatorStatus/pollQuestion/PollQuestionIndicator.js new file mode 100644 index 0000000000..ea85d5905d --- /dev/null +++ b/src/plugins/operatorStatus/pollQuestion/PollQuestionIndicator.js @@ -0,0 +1,63 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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 Vue from 'vue'; + +import AbstractStatusIndicator from '../AbstractStatusIndicator'; +import PollQuestionComponent from './PollQuestion.vue'; + +export default class PollQuestionIndicator extends AbstractStatusIndicator { + createPopupComponent() { + const indicator = this.getIndicator(); + const pollQuestionElement = new Vue({ + components: { + PollQuestion: PollQuestionComponent + }, + provide: { + openmct: this.openmct, + indicator: indicator, + configuration: this.getConfiguration() + }, + data() { + return { + positionX: 0, + positionY: 0 + }; + }, + template: '' + }).$mount(); + + return pollQuestionElement; + } + + createIndicator() { + const pollQuestionIndicator = this.openmct.indicators.simpleIndicator(); + + pollQuestionIndicator.text("Poll Question"); + pollQuestionIndicator.description("Set the current poll question"); + pollQuestionIndicator.iconClass('icon-status-poll-edit'); + pollQuestionIndicator.element.classList.add("c-indicator--operator-status"); + pollQuestionIndicator.element.classList.add("no-minify"); + pollQuestionIndicator.on('click', this.showPopup); + + return pollQuestionIndicator; + } +} diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index 7beccebd54..e53ac68433 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -78,6 +78,7 @@ define([ './userIndicator/plugin', '../../example/exampleUser/plugin', './localStorage/plugin', + './operatorStatus/plugin', './gauge/GaugePlugin', './timelist/plugin' ], function ( @@ -138,6 +139,7 @@ define([ UserIndicator, ExampleUser, LocalStorage, + OperatorStatus, GaugePlugin, TimeList ) { @@ -217,6 +219,7 @@ define([ plugins.DeviceClassifier = DeviceClassifier.default; plugins.UserIndicator = UserIndicator.default; plugins.LocalStorage = LocalStorage.default; + plugins.OperatorStatus = OperatorStatus.default; plugins.Gauge = GaugePlugin.default; plugins.Timelist = TimeList.default; diff --git a/src/styles/_constants.scss b/src/styles/_constants.scss index 8d2d34179e..8b4994756e 100755 --- a/src/styles/_constants.scss +++ b/src/styles/_constants.scss @@ -156,6 +156,13 @@ $glyph-icon-notebook-page: '\e92c'; $glyph-icon-unlocked: '\e92d'; $glyph-icon-circle: '\e92e'; $glyph-icon-draft: '\e92f'; +$glyph-icon-circle-slash: '\e930'; +$glyph-icon-question-mark: '\e931'; +$glyph-icon-status-poll-check: '\e932'; +$glyph-icon-status-poll-caution: '\e933'; +$glyph-icon-status-poll-circle-slash: '\e934'; +$glyph-icon-status-poll-question-mark: '\e935'; +$glyph-icon-status-poll-edit: '\e936'; $glyph-icon-arrows-right-left: '\ea00'; $glyph-icon-arrows-up-down: '\ea01'; $glyph-icon-bullet: '\ea02'; @@ -264,6 +271,7 @@ $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'; /************************** GLYPHS AS DATA URI */ @@ -317,4 +325,5 @@ $bg-icon-bar-chart: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://w $bg-icon-map: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23000000' d='M448 32.7 384 64v448l64-31.3c35.2-17.21 64-60.1 64-95.3v-320c0-35.2-28.8-49.91-64-32.7ZM160 456l193.6 48.4v-448L160 8v448zM129.6.4 128 0 64 31.3C28.8 48.51 0 91.4 0 126.6v320c0 35.2 28.8 49.91 64 32.7l64-31.3 1.6.4Z'/%3e%3c/svg%3e"); $bg-icon-plan: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cg data-name='Layer 2'%3e%3cg data-name='Layer 1'%3e%3cpath fill='%23000000' d='M128 96V64a64.19 64.19 0 0 1 64-64h128a64.19 64.19 0 0 1 64 64v32Z'/%3e%3cpath fill='%23000000' d='M416 64v64H96V64c-52.8 0-96 43.2-96 96v256c0 52.8 43.2 96 96 96h320c52.8 0 96-43.2 96-96V160c0-52.8-43.2-96-96-96ZM64 288v-64h128v64Zm256 128H128v-64h192Zm128 0h-64v-64h64Zm0-128H256v-64h192Z'/%3e%3c/g%3e%3c/g%3e%3c/svg%3e"); $bg-icon-timelist: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cg data-name='Layer 2'%3e%3cpath d='M448 0H64A64.19 64.19 0 0 0 0 64v384a64.19 64.19 0 0 0 64 64h384a64.19 64.19 0 0 0 64-64V64a64.19 64.19 0 0 0-64-64ZM213.47 266.73a24 24 0 0 1-32.2 10.74L104 238.83V128a24 24 0 0 1 48 0v81.17l50.73 25.36a24 24 0 0 1 10.74 32.2ZM448 448H288v-64h160Zm0-96H288v-64h160Zm0-96H288v-64h160Zm0-96H288V96h160Z' data-name='Layer 1'/%3e%3c/g%3e%3c/svg%3e"); +$bg-icon-notebook-shift-log: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath d='M448 55.36c0-39.95-27.69-63.66-61.54-52.68L0 128h448V55.36ZM448 160H0v288c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V224c0-35.2-28.8-64-64-64ZM128 416H64v-64h64v64Zm0-96H64v-64h64v64Zm320 96H192v-64h256v64Zm0-96H192v-64h256v64Z'/%3e%3c/svg%3e"); $bg-icon-plot-scatter: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cg data-name='Layer 2'%3e%3cpath d='M96 0C43.2 0 0 43.2 0 96v320c0 52.8 43.2 96 96 96h320c52.8 0 96-43.2 96-96V96c0-52.8-43.2-96-96-96ZM64 176a48 48 0 1 1 48 48 48 48 0 0 1-48-48Zm80 240a48 48 0 1 1 48-48 48 48 0 0 1-48 48Zm128-96a48 48 0 1 1 48-48 48 48 0 0 1-48 48Zm0-160a48 48 0 1 1 48-48 48 48 0 0 1-48 48Zm128 256a48 48 0 1 1 48-48 48 48 0 0 1-48 48Z' data-name='Layer 1'/%3e%3c/g%3e%3c/svg%3e"); diff --git a/src/styles/_glyphs.scss b/src/styles/_glyphs.scss index ac82d60060..80b43eb3de 100755 --- a/src/styles/_glyphs.scss +++ b/src/styles/_glyphs.scss @@ -87,6 +87,13 @@ .icon-unlocked { @include glyphBefore($glyph-icon-unlocked); } .icon-circle { @include glyphBefore($glyph-icon-circle); } .icon-draft { @include glyphBefore($glyph-icon-draft); } +.icon-question-mark { @include glyphBefore($glyph-icon-question-mark); } +.icon-circle-slash { @include glyphBefore($glyph-icon-circle-slash); } +.icon-status-poll-check { @include glyphBefore($glyph-icon-status-poll-check); } +.icon-status-poll-caution { @include glyphBefore($glyph-icon-status-poll-caution); } +.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); } +.icon-status-poll-edit { @include glyphBefore($glyph-icon-status-poll-edit); } .icon-arrows-right-left { @include glyphBefore($glyph-icon-arrows-right-left); } .icon-arrows-up-down { @include glyphBefore($glyph-icon-arrows-up-down); } .icon-bullet { @include glyphBefore($glyph-icon-bullet); } @@ -195,6 +202,7 @@ .icon-map { @include glyphBefore($glyph-icon-map); } .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); } .icon-plot-scatter { @include glyphBefore($glyph-icon-plot-scatter); } /************************** 12 PX CLASSES */ @@ -256,4 +264,5 @@ .bg-icon-map { @include glyphBg($bg-icon-map); } .bg-icon-plan { @include glyphBg($bg-icon-plan); } .bg-icon-timelist { @include glyphBg($bg-icon-timelist); } +.bg-icon-notebook-shift-log { @include glyphBg($bg-icon-notebook-shift-log); } .bg-icon-plot-scatter { @include glyphBg($bg-icon-plot-scatter); } diff --git a/src/styles/fonts/Open MCT Symbols 16px.json b/src/styles/fonts/Open MCT Symbols 16px.json index 7e5d8a02a9..11cc387378 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": 1650916650636 + "created": 1651949568729 }, "iconSets": [ { @@ -391,13 +391,69 @@ "code": 59695, "tempChar": "" }, + { + "order": 212, + "id": 183, + "name": "icon-circle-slash", + "prevSize": 16, + "code": 59696, + "tempChar": "" + }, + { + "order": 213, + "id": 182, + "name": "icon-question-mark", + "prevSize": 16, + "code": 59697, + "tempChar": "" + }, + { + "order": 206, + "id": 179, + "name": "icon-status-poll-check", + "prevSize": 16, + "code": 59698, + "tempChar": "" + }, + { + "order": 207, + "id": 178, + "name": "icon-status-poll-caution", + "prevSize": 16, + "code": 59699, + "tempChar": "" + }, + { + "order": 210, + "id": 180, + "name": "icon-status-poll-circle-slash", + "prevSize": 16, + "code": 59700, + "tempChar": "" + }, + { + "order": 211, + "id": 181, + "name": "icon-status-poll-question-mark", + "prevSize": 16, + "code": 59701, + "tempChar": "" + }, + { + "order": 209, + "id": 176, + "name": "icon-status-poll-edit", + "prevSize": 16, + "code": 59702, + "tempChar": "" + }, { "order": 27, "id": 105, "name": "icon-arrows-right-left", "prevSize": 16, "code": 59904, - "tempChar": "" + "tempChar": "" }, { "order": 26, @@ -405,7 +461,7 @@ "name": "icon-arrows-up-down", "prevSize": 16, "code": 59905, - "tempChar": "" + "tempChar": "" }, { "order": 68, @@ -413,7 +469,7 @@ "name": "icon-bullet", "prevSize": 16, "code": 59906, - "tempChar": "" + "tempChar": "" }, { "order": 150, @@ -421,7 +477,7 @@ "prevSize": 16, "code": 59907, "name": "icon-calendar", - "tempChar": "" + "tempChar": "" }, { "order": 45, @@ -429,7 +485,7 @@ "name": "icon-chain-links", "prevSize": 16, "code": 59908, - "tempChar": "" + "tempChar": "" }, { "order": 73, @@ -437,7 +493,7 @@ "name": "icon-download", "prevSize": 16, "code": 59909, - "tempChar": "" + "tempChar": "" }, { "order": 39, @@ -445,7 +501,7 @@ "name": "icon-duplicate", "prevSize": 16, "code": 59910, - "tempChar": "" + "tempChar": "" }, { "order": 50, @@ -453,7 +509,7 @@ "name": "icon-folder-new", "prevSize": 16, "code": 59911, - "tempChar": "" + "tempChar": "" }, { "order": 138, @@ -461,7 +517,7 @@ "name": "icon-fullscreen-collapse", "prevSize": 16, "code": 59912, - "tempChar": "" + "tempChar": "" }, { "order": 139, @@ -469,7 +525,7 @@ "name": "icon-fullscreen-expand", "prevSize": 16, "code": 59913, - "tempChar": "" + "tempChar": "" }, { "order": 122, @@ -477,7 +533,7 @@ "name": "icon-layers", "prevSize": 16, "code": 59914, - "tempChar": "" + "tempChar": "" }, { "order": 151, @@ -485,7 +541,7 @@ "name": "icon-line-horz", "prevSize": 16, "code": 59915, - "tempChar": "" + "tempChar": "" }, { "order": 100, @@ -493,7 +549,7 @@ "name": "icon-magnify", "prevSize": 16, "code": 59916, - "tempChar": "" + "tempChar": "" }, { "order": 99, @@ -501,7 +557,7 @@ "name": "icon-magnify-in", "prevSize": 16, "code": 59917, - "tempChar": "" + "tempChar": "" }, { "order": 101, @@ -509,7 +565,7 @@ "name": "icon-magnify-out-v2", "prevSize": 16, "code": 59918, - "tempChar": "" + "tempChar": "" }, { "order": 103, @@ -517,7 +573,7 @@ "name": "icon-menu", "prevSize": 16, "code": 59919, - "tempChar": "" + "tempChar": "" }, { "order": 124, @@ -525,7 +581,7 @@ "name": "icon-move", "prevSize": 16, "code": 59920, - "tempChar": "" + "tempChar": "" }, { "order": 7, @@ -533,7 +589,7 @@ "name": "icon-new-window", "prevSize": 16, "code": 59921, - "tempChar": "" + "tempChar": "" }, { "order": 63, @@ -541,7 +597,7 @@ "name": "icon-paint-bucket-v2", "prevSize": 16, "code": 59922, - "tempChar": "" + "tempChar": "" }, { "order": 15, @@ -549,7 +605,7 @@ "name": "icon-pencil", "prevSize": 16, "code": 59923, - "tempChar": "" + "tempChar": "" }, { "order": 54, @@ -557,7 +613,7 @@ "name": "icon-pencil-edit-in-place", "prevSize": 16, "code": 59924, - "tempChar": "" + "tempChar": "" }, { "order": 40, @@ -565,7 +621,7 @@ "name": "icon-play", "prevSize": 16, "code": 59925, - "tempChar": "" + "tempChar": "" }, { "order": 125, @@ -573,7 +629,7 @@ "name": "icon-pause", "prevSize": 16, "code": 59926, - "tempChar": "" + "tempChar": "" }, { "order": 119, @@ -581,7 +637,7 @@ "name": "icon-plot-resource", "prevSize": 16, "code": 59927, - "tempChar": "" + "tempChar": "" }, { "order": 48, @@ -589,7 +645,7 @@ "name": "icon-pointer-left", "prevSize": 16, "code": 59928, - "tempChar": "" + "tempChar": "" }, { "order": 47, @@ -597,7 +653,7 @@ "name": "icon-pointer-right", "prevSize": 16, "code": 59929, - "tempChar": "" + "tempChar": "" }, { "order": 85, @@ -605,7 +661,7 @@ "name": "icon-refresh", "prevSize": 16, "code": 59930, - "tempChar": "" + "tempChar": "" }, { "order": 55, @@ -613,7 +669,7 @@ "name": "icon-save", "prevSize": 16, "code": 59931, - "tempChar": "" + "tempChar": "" }, { "order": 56, @@ -621,7 +677,7 @@ "name": "icon-save-as", "prevSize": 16, "code": 59932, - "tempChar": "" + "tempChar": "" }, { "order": 58, @@ -629,7 +685,7 @@ "name": "icon-sine", "prevSize": 16, "code": 59933, - "tempChar": "" + "tempChar": "" }, { "order": 113, @@ -637,7 +693,7 @@ "name": "icon-font", "prevSize": 16, "code": 59934, - "tempChar": "" + "tempChar": "" }, { "order": 41, @@ -645,7 +701,7 @@ "name": "icon-thumbs-strip", "prevSize": 16, "code": 59935, - "tempChar": "" + "tempChar": "" }, { "order": 146, @@ -653,7 +709,7 @@ "name": "icon-two-parts-both", "prevSize": 16, "code": 59936, - "tempChar": "" + "tempChar": "" }, { "order": 145, @@ -661,7 +717,7 @@ "name": "icon-two-parts-one-only", "prevSize": 16, "code": 59937, - "tempChar": "" + "tempChar": "" }, { "order": 82, @@ -669,7 +725,7 @@ "name": "icon-resync", "prevSize": 16, "code": 59938, - "tempChar": "" + "tempChar": "" }, { "order": 86, @@ -677,7 +733,7 @@ "name": "icon-reset", "prevSize": 16, "code": 59939, - "tempChar": "" + "tempChar": "" }, { "order": 61, @@ -685,7 +741,7 @@ "name": "icon-x-in-circle", "prevSize": 16, "code": 59940, - "tempChar": "" + "tempChar": "" }, { "order": 84, @@ -693,7 +749,7 @@ "name": "icon-brightness", "prevSize": 16, "code": 59941, - "tempChar": "" + "tempChar": "" }, { "order": 83, @@ -701,7 +757,7 @@ "name": "icon-contrast", "prevSize": 16, "code": 59942, - "tempChar": "" + "tempChar": "" }, { "order": 87, @@ -709,7 +765,7 @@ "name": "icon-expand", "prevSize": 16, "code": 59943, - "tempChar": "" + "tempChar": "" }, { "order": 89, @@ -717,7 +773,7 @@ "name": "icon-list-view", "prevSize": 16, "code": 59944, - "tempChar": "" + "tempChar": "" }, { "order": 133, @@ -725,7 +781,7 @@ "name": "icon-grid-snap-to", "prevSize": 16, "code": 59945, - "tempChar": "" + "tempChar": "" }, { "order": 132, @@ -733,7 +789,7 @@ "name": "icon-grid-snap-no", "prevSize": 16, "code": 59946, - "tempChar": "" + "tempChar": "" }, { "order": 94, @@ -741,7 +797,7 @@ "name": "icon-frame-show", "prevSize": 16, "code": 59947, - "tempChar": "" + "tempChar": "" }, { "order": 95, @@ -749,7 +805,7 @@ "name": "icon-frame-hide", "prevSize": 16, "code": 59948, - "tempChar": "" + "tempChar": "" }, { "order": 97, @@ -757,7 +813,7 @@ "name": "icon-import", "prevSize": 16, "code": 59949, - "tempChar": "" + "tempChar": "" }, { "order": 96, @@ -765,7 +821,7 @@ "name": "icon-export", "prevSize": 16, "code": 59950, - "tempChar": "" + "tempChar": "" }, { "order": 194, @@ -773,7 +829,7 @@ "name": "icon-font-size", "prevSize": 16, "code": 59951, - "tempChar": "" + "tempChar": "" }, { "order": 163, @@ -781,7 +837,7 @@ "name": "icon-clear-data", "prevSize": 16, "code": 59952, - "tempChar": "" + "tempChar": "" }, { "order": 173, @@ -789,7 +845,7 @@ "name": "icon-history", "prevSize": 16, "code": 59953, - "tempChar": "" + "tempChar": "" }, { "order": 181, @@ -797,7 +853,7 @@ "name": "icon-arrow-up-to-parent", "prevSize": 16, "code": 59954, - "tempChar": "" + "tempChar": "" }, { "order": 184, @@ -805,7 +861,7 @@ "name": "icon-crosshair-in-circle", "prevSize": 16, "code": 59955, - "tempChar": "" + "tempChar": "" }, { "order": 185, @@ -813,7 +869,7 @@ "name": "icon-target", "prevSize": 16, "code": 59956, - "tempChar": "" + "tempChar": "" }, { "order": 187, @@ -821,7 +877,7 @@ "name": "icon-items-collapse", "prevSize": 16, "code": 59957, - "tempChar": "" + "tempChar": "" }, { "order": 188, @@ -829,7 +885,7 @@ "name": "icon-items-expand", "prevSize": 16, "code": 59958, - "tempChar": "" + "tempChar": "" }, { "order": 190, @@ -837,7 +893,7 @@ "name": "icon-3-dots", "prevSize": 16, "code": 59959, - "tempChar": "" + "tempChar": "" }, { "order": 193, @@ -845,7 +901,7 @@ "name": "icon-grid-on", "prevSize": 16, "code": 59960, - "tempChar": "" + "tempChar": "" }, { "order": 192, @@ -853,7 +909,7 @@ "name": "icon-grid-off", "prevSize": 16, "code": 59961, - "tempChar": "" + "tempChar": "" }, { "order": 191, @@ -861,7 +917,7 @@ "name": "icon-camera", "prevSize": 16, "code": 59962, - "tempChar": "" + "tempChar": "" }, { "order": 196, @@ -869,7 +925,7 @@ "name": "icon-folders-collapse", "prevSize": 16, "code": 59963, - "tempChar": "" + "tempChar": "" }, { "order": 144, @@ -877,7 +933,7 @@ "name": "icon-activity", "prevSize": 16, "code": 60160, - "tempChar": "" + "tempChar": "" }, { "order": 104, @@ -885,7 +941,7 @@ "name": "icon-activity-mode", "prevSize": 16, "code": 60161, - "tempChar": "" + "tempChar": "" }, { "order": 137, @@ -893,7 +949,7 @@ "name": "icon-autoflow-tabular", "prevSize": 16, "code": 60162, - "tempChar": "" + "tempChar": "" }, { "order": 115, @@ -901,7 +957,7 @@ "name": "icon-clock", "prevSize": 16, "code": 60163, - "tempChar": "" + "tempChar": "" }, { "order": 2, @@ -909,7 +965,7 @@ "name": "icon-database", "prevSize": 16, "code": 60164, - "tempChar": "" + "tempChar": "" }, { "order": 3, @@ -917,7 +973,7 @@ "name": "icon-database-query", "prevSize": 16, "code": 60165, - "tempChar": "" + "tempChar": "" }, { "order": 67, @@ -925,7 +981,7 @@ "name": "icon-dataset", "prevSize": 16, "code": 60166, - "tempChar": "" + "tempChar": "" }, { "order": 59, @@ -933,7 +989,7 @@ "name": "icon-datatable", "prevSize": 16, "code": 60167, - "tempChar": "" + "tempChar": "" }, { "order": 136, @@ -941,7 +997,7 @@ "name": "icon-dictionary", "prevSize": 16, "code": 60168, - "tempChar": "" + "tempChar": "" }, { "order": 51, @@ -949,7 +1005,7 @@ "name": "icon-folder", "prevSize": 16, "code": 60169, - "tempChar": "" + "tempChar": "" }, { "order": 147, @@ -957,7 +1013,7 @@ "name": "icon-image", "prevSize": 16, "code": 60170, - "tempChar": "" + "tempChar": "" }, { "order": 4, @@ -965,7 +1021,7 @@ "name": "icon-layout", "prevSize": 16, "code": 60171, - "tempChar": "" + "tempChar": "" }, { "order": 24, @@ -973,7 +1029,7 @@ "name": "icon-object", "prevSize": 16, "code": 60172, - "tempChar": "" + "tempChar": "" }, { "order": 52, @@ -981,7 +1037,7 @@ "name": "icon-object-unknown", "prevSize": 16, "code": 60173, - "tempChar": "" + "tempChar": "" }, { "order": 105, @@ -989,7 +1045,7 @@ "name": "icon-packet", "prevSize": 16, "code": 60174, - "tempChar": "" + "tempChar": "" }, { "order": 126, @@ -997,7 +1053,7 @@ "name": "icon-page", "prevSize": 16, "code": 60175, - "tempChar": "" + "tempChar": "" }, { "order": 130, @@ -1005,7 +1061,7 @@ "name": "icon-plot-overlay", "prevSize": 16, "code": 60176, - "tempChar": "" + "tempChar": "" }, { "order": 80, @@ -1013,7 +1069,7 @@ "name": "icon-plot-stacked", "prevSize": 16, "code": 60177, - "tempChar": "" + "tempChar": "" }, { "order": 134, @@ -1021,7 +1077,7 @@ "name": "icon-session", "prevSize": 16, "code": 60178, - "tempChar": "" + "tempChar": "" }, { "order": 109, @@ -1029,7 +1085,7 @@ "name": "icon-tabular", "prevSize": 16, "code": 60179, - "tempChar": "" + "tempChar": "" }, { "order": 107, @@ -1037,7 +1093,7 @@ "name": "icon-tabular-lad", "prevSize": 16, "code": 60180, - "tempChar": "" + "tempChar": "" }, { "order": 106, @@ -1045,7 +1101,7 @@ "name": "icon-tabular-lad-set", "prevSize": 16, "code": 60181, - "tempChar": "" + "tempChar": "" }, { "order": 70, @@ -1053,7 +1109,7 @@ "name": "icon-tabular-realtime", "prevSize": 16, "code": 60182, - "tempChar": "" + "tempChar": "" }, { "order": 60, @@ -1061,7 +1117,7 @@ "name": "icon-tabular-scrolling", "prevSize": 16, "code": 60183, - "tempChar": "" + "tempChar": "" }, { "order": 131, @@ -1069,7 +1125,7 @@ "name": "icon-telemetry", "prevSize": 16, "code": 60184, - "tempChar": "" + "tempChar": "" }, { "order": 202, @@ -1077,7 +1133,7 @@ "name": "icon-timeline", "prevSize": 16, "code": 60185, - "tempChar": "" + "tempChar": "" }, { "order": 81, @@ -1085,7 +1141,7 @@ "name": "icon-timer", "prevSize": 16, "code": 60186, - "tempChar": "" + "tempChar": "" }, { "order": 69, @@ -1093,7 +1149,7 @@ "name": "icon-topic", "prevSize": 16, "code": 60187, - "tempChar": "" + "tempChar": "" }, { "order": 79, @@ -1101,7 +1157,7 @@ "name": "icon-box-with-dashed-lines-v2", "prevSize": 16, "code": 60188, - "tempChar": "" + "tempChar": "" }, { "order": 90, @@ -1109,7 +1165,7 @@ "name": "icon-summary-widget", "prevSize": 16, "code": 60189, - "tempChar": "" + "tempChar": "" }, { "order": 92, @@ -1117,7 +1173,7 @@ "name": "icon-notebook", "prevSize": 16, "code": 60190, - "tempChar": "" + "tempChar": "" }, { "order": 168, @@ -1125,7 +1181,7 @@ "name": "icon-tabs-view", "prevSize": 16, "code": 60191, - "tempChar": "" + "tempChar": "" }, { "order": 117, @@ -1133,7 +1189,7 @@ "name": "icon-flexible-layout", "prevSize": 16, "code": 60192, - "tempChar": "" + "tempChar": "" }, { "order": 166, @@ -1141,7 +1197,7 @@ "name": "icon-generator-sine", "prevSize": 16, "code": 60193, - "tempChar": "" + "tempChar": "" }, { "order": 167, @@ -1149,7 +1205,7 @@ "name": "icon-generator-event", "prevSize": 16, "code": 60194, - "tempChar": "" + "tempChar": "" }, { "order": 165, @@ -1157,7 +1213,7 @@ "name": "icon-gauge-v2", "prevSize": 16, "code": 60195, - "tempChar": "" + "tempChar": "" }, { "order": 170, @@ -1165,7 +1221,7 @@ "name": "icon-spectra", "prevSize": 16, "code": 60196, - "tempChar": "" + "tempChar": "" }, { "order": 171, @@ -1173,7 +1229,7 @@ "name": "icon-telemetry-spectra", "prevSize": 16, "code": 60197, - "tempChar": "" + "tempChar": "" }, { "order": 172, @@ -1181,7 +1237,7 @@ "name": "icon-pushbutton", "prevSize": 16, "code": 60198, - "tempChar": "" + "tempChar": "" }, { "order": 174, @@ -1189,7 +1245,7 @@ "name": "icon-conditional", "prevSize": 16, "code": 60199, - "tempChar": "" + "tempChar": "" }, { "order": 178, @@ -1197,7 +1253,7 @@ "name": "icon-condition-widget", "prevSize": 16, "code": 60200, - "tempChar": "" + "tempChar": "" }, { "order": 180, @@ -1205,7 +1261,7 @@ "name": "icon-alphanumeric", "prevSize": 16, "code": 60201, - "tempChar": "" + "tempChar": "" }, { "order": 183, @@ -1213,7 +1269,7 @@ "name": "icon-image-telemetry", "prevSize": 16, "code": 60202, - "tempChar": "" + "tempChar": "" }, { "order": 198, @@ -1221,7 +1277,7 @@ "name": "icon-telemetry-aggregate", "prevSize": 16, "code": 60203, - "tempChar": "" + "tempChar": "" }, { "order": 199, @@ -1229,7 +1285,7 @@ "name": "icon-bar-graph", "prevSize": 16, "code": 60204, - "tempChar": "" + "tempChar": "" }, { "order": 200, @@ -1237,7 +1293,7 @@ "name": "icon-map", "prevSize": 16, "code": 60205, - "tempChar": "" + "tempChar": "" }, { "order": 203, @@ -1245,7 +1301,7 @@ "name": "icon-plan", "prevSize": 16, "code": 60206, - "tempChar": "" + "tempChar": "" }, { "order": 204, @@ -1253,7 +1309,15 @@ "name": "icon-timelist", "prevSize": 16, "code": 60207, - "tempChar": "" + "tempChar": "" + }, + { + "order": 214, + "id": 184, + "name": "icon-notebook-restricted", + "prevSize": 16, + "code": 60209, + "tempChar": "" }, { "order": 205, @@ -2107,6 +2171,162 @@ ] } }, + { + "id": 183, + "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": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "icon-circle-slash" + ], + "colorPermutations": { + "12552552551": [ + {} + ] + } + }, + { + "id": 182, + "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": [ + {} + ], + "width": 697, + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "icon-question-mark" + ], + "colorPermutations": { + "12552552551": [ + {} + ] + } + }, + { + "id": 179, + "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": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "icon-status-poll-check" + ], + "colorPermutations": { + "12552552551": [ + {} + ] + } + }, + { + "id": 178, + "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-480zM781.36 704h-538.72c-44.96 0-63.5-31.94-41.2-70.98l270-472.48c22.3-39.040 58.82-39.040 81.12 0l269.98 472.48c22.3 39.040 3.78 70.98-41.2 70.98z", + "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": [ + {}, + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "icon-status-poll-caution" + ], + "colorPermutations": { + "12552552551": [ + {}, + {}, + {} + ] + } + }, + { + "id": 180, + "paths": [ + "M391.18 668.7c35.72 22.98 77.32 35.3 120.82 35.3 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.82l-309.52 309.52z", + "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": [ + {}, + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "icon-status-poll-circle-slash" + ], + "colorPermutations": { + "12552552551": [ + {}, + {}, + {} + ] + } + }, + { + "id": 181, + "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": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "icon-status-poll-question-mark" + ], + "colorPermutations": { + "12552552551": [ + {} + ] + } + }, + { + "id": 176, + "paths": [ + "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": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "icon-status-poll-edit" + ], + "colorPermutations": { + "12552552551": [ + {}, + {} + ] + } + }, { "id": 105, "paths": [ @@ -3326,15 +3546,21 @@ { "id": 76, "paths": [ - "M510-2l-512 320v384l512 320 512-320v-384l-512-320zM585.4 859.2c-21.2 20.8-46 30.8-76 30.8-31.2 0-56.2-9.8-76.2-29.6-20-20-29.6-44.8-29.6-76.2 0-30.4 10.2-55.2 31-76.2s45.2-31.2 74.8-31.2c29.6 0 54.2 10.4 75.6 32s31.8 46.4 31.8 76c-0.2 29-10.8 54-31.4 74.4zM638.2 546.6c-23.6 11.8-37.4 22-43.4 32.4-3.6 6.2-6 14.8-7.4 26.8v41h-161.4v-44.2c0-40.2 4.4-69.8 13-88 8-17.2 22.6-30.2 44.8-40l34.8-15.4c32-14.2 48.2-35.2 48.2-62.8 0-16-6-30.4-17.2-41.8-11.2-11.2-25.6-17.2-41.6-17.2-24 0-54.4 10-62.8 57.4l-2.2 12.2h-147l1.4-16.2c4-44.6 17-82.4 38.8-112.2 19.6-27 45.6-48.6 77-64.6s64.6-24 98.2-24c60.6 0 110.2 19.4 151.4 59.6 41.2 40 61.2 88 61.2 147.2 0 70.8-28.8 121.4-85.8 149.8z" + "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" ], + "isMulticolor": false, + "isMulticolor2": false, "colorPermutations": { - "12552552551": [] + "12552552551": [ + {} + ] } }, { @@ -4009,6 +4235,29 @@ ] } }, + { + "id": 184, + "paths": [ + "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": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "icon-notebook-restricted" + ], + "colorPermutations": { + "12552552551": [ + {}, + {} + ] + } + }, { "id": 176, "paths": [ diff --git a/src/styles/fonts/Open-MCT-Symbols-16px.svg b/src/styles/fonts/Open-MCT-Symbols-16px.svg index c6455e381c..38ce5985a3 100644 --- a/src/styles/fonts/Open-MCT-Symbols-16px.svg +++ b/src/styles/fonts/Open-MCT-Symbols-16px.svg @@ -3,165 +3,173 @@ Generated by IcoMoon - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 073e2c6ec556deac1f1e5c31eb9885033409d428..94ab53538b6ee4ee72e83b1e7a1afc6b78958239 100644 GIT binary patch delta 6255 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 diff --git a/src/styles/fonts/Open-MCT-Symbols-16px.woff b/src/styles/fonts/Open-MCT-Symbols-16px.woff index ca1cc26bede033633737bcd580ab3615e72ae99a..510d6e9a9b85dae9d62daa494a38a0bdad0131be 100644 GIT binary patch delta 6470 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 { + this.openmct.indicators.getIndicatorObjectsByPriority().forEach(this.addIndicator); + + this.openmct.indicators.on('addIndicator', this.addIndicator); + }, + methods: { + addIndicator(indicator) { this.$el.appendChild(indicator.element); - }); + } } + }; diff --git a/src/utils/raf.js b/src/utils/raf.js new file mode 100644 index 0000000000..d5c0c48fe5 --- /dev/null +++ b/src/utils/raf.js @@ -0,0 +1,14 @@ +export default function raf(callback) { + let rendering = false; + + return () => { + if (!rendering) { + rendering = true; + + requestAnimationFrame(() => { + callback(); + rendering = false; + }); + } + }; +} diff --git a/src/utils/rafSpec.js b/src/utils/rafSpec.js new file mode 100644 index 0000000000..0bf5ae9d9c --- /dev/null +++ b/src/utils/rafSpec.js @@ -0,0 +1,61 @@ +import raf from "./raf"; + +describe('The raf utility function', () => { + it('Throttles function calls that arrive in quick succession using Request Animation Frame', () => { + const unthrottledFunction = jasmine.createSpy('unthrottledFunction'); + const throttledCallback = jasmine.createSpy('throttledCallback'); + const throttledFunction = raf(throttledCallback); + + for (let i = 0; i < 10; i++) { + unthrottledFunction(); + throttledFunction(); + } + + return new Promise((resolve) => { + requestAnimationFrame(resolve); + }).then(() => { + expect(unthrottledFunction).toHaveBeenCalledTimes(10); + expect(throttledCallback).toHaveBeenCalledTimes(1); + }); + }); + it('Only invokes callback once per animation frame', () => { + const throttledCallback = jasmine.createSpy('throttledCallback'); + const throttledFunction = raf(throttledCallback); + + for (let i = 0; i < 10; i++) { + throttledFunction(); + } + + return new Promise(resolve => { + requestAnimationFrame(resolve); + }).then(() => { + return new Promise(resolve => { + requestAnimationFrame(resolve); + }); + }).then(() => { + expect(throttledCallback).toHaveBeenCalledTimes(1); + }); + }); + it('Invokes callback again if called in subsequent animation frame', () => { + const throttledCallback = jasmine.createSpy('throttledCallback'); + const throttledFunction = raf(throttledCallback); + + for (let i = 0; i < 10; i++) { + throttledFunction(); + } + + return new Promise(resolve => { + requestAnimationFrame(resolve); + }).then(() => { + for (let i = 0; i < 10; i++) { + throttledFunction(); + } + + return new Promise(resolve => { + requestAnimationFrame(resolve); + }); + }).then(() => { + expect(throttledCallback).toHaveBeenCalledTimes(2); + }); + }); +}); From 04ee6f49d623c88aab6169d6615c402574d12c57 Mon Sep 17 00:00:00 2001 From: Alize Nguyen Date: Thu, 2 Jun 2022 17:47:14 -0500 Subject: [PATCH 041/161] Remove all non legacy usage of zepto (#5159) * Removed Zepto * Added utility functions for compiling HTML templates and toggling classes on and off Co-authored-by: John Hill Co-authored-by: Andrew Henry --- package.json | 4 +- src/api/indicators/SimpleIndicator.js | 10 +- .../URLIndicatorPlugin/URLIndicator.js | 23 +-- .../URLIndicatorPlugin/URLIndicatorSpec.js | 41 ++--- .../autoflow/AutoflowTabularPluginSpec.js | 27 ++- .../licenses/third-party-licenses.json | 7 - src/plugins/summaryWidget/src/Condition.js | 41 +++-- .../summaryWidget/src/ConditionManager.js | 12 +- src/plugins/summaryWidget/src/Rule.js | 154 +++++++++++------- .../summaryWidget/src/SummaryWidget.js | 71 ++++---- src/plugins/summaryWidget/src/TestDataItem.js | 28 ++-- .../summaryWidget/src/TestDataManager.js | 18 +- src/plugins/summaryWidget/src/WidgetDnD.js | 27 +-- .../summaryWidget/src/input/ColorPalette.js | 21 +-- .../summaryWidget/src/input/IconPalette.js | 30 ++-- .../summaryWidget/src/input/Palette.js | 71 +++++--- src/plugins/summaryWidget/src/input/Select.js | 48 +++--- .../summaryWidget/test/ConditionSpec.js | 60 +++++-- src/plugins/summaryWidget/test/RuleSpec.js | 29 ++-- .../summaryWidget/test/SummaryWidgetSpec.js | 12 +- .../summaryWidget/test/TestDataItemSpec.js | 53 ++++-- .../summaryWidget/test/TestDataManagerSpec.js | 8 +- src/utils/template/templateHelpers.js | 14 ++ webpack.common.js | 7 - 24 files changed, 477 insertions(+), 339 deletions(-) create mode 100644 src/utils/template/templateHelpers.js diff --git a/package.json b/package.json index c1aac194e6..a62dd41924 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "eslint-plugin-vue": "8.5.0", "eslint-plugin-you-dont-need-lodash-underscore": "6.12.0", "eventemitter3": "1.2.0", - "exports-loader": "0.7.0", "express": "4.13.1", "file-saver": "2.0.5", "git-rev-sync": "3.0.2", @@ -74,8 +73,7 @@ "webpack-cli": "4.9.2", "webpack-dev-middleware": "5.3.3", "webpack-hot-middleware": "2.25.1", - "webpack-merge": "5.8.0", - "zepto": "1.2.0" + "webpack-merge": "5.8.0" }, "scripts": { "clean": "rm -rf ./dist ./node_modules ./package-lock.json", diff --git a/src/api/indicators/SimpleIndicator.js b/src/api/indicators/SimpleIndicator.js index 1ef99e6888..31ce745a52 100644 --- a/src/api/indicators/SimpleIndicator.js +++ b/src/api/indicators/SimpleIndicator.js @@ -22,6 +22,7 @@ import EventEmitter from 'EventEmitter'; import indicatorTemplate from './res/indicator-template.html'; +import { convertTemplateToHTML } from '@/utils/template/templateHelpers'; const DEFAULT_ICON_CLASS = 'icon-info'; @@ -30,7 +31,7 @@ class SimpleIndicator extends EventEmitter { super(); this.openmct = openmct; - this.element = compileTemplate(indicatorTemplate)[0]; + this.element = convertTemplateToHTML(indicatorTemplate)[0]; this.priority = openmct.priority.DEFAULT; this.textElement = this.element.querySelector('.js-indicator-text'); @@ -116,11 +117,4 @@ class SimpleIndicator extends EventEmitter { } } -function compileTemplate(htmlTemplate) { - const templateNode = document.createElement('template'); - templateNode.innerHTML = htmlTemplate; - - return templateNode.content.cloneNode(true).children; -} - export default SimpleIndicator; diff --git a/src/plugins/URLIndicatorPlugin/URLIndicator.js b/src/plugins/URLIndicatorPlugin/URLIndicator.js index 1bc83450e9..5a6785e54b 100644 --- a/src/plugins/URLIndicatorPlugin/URLIndicator.js +++ b/src/plugins/URLIndicatorPlugin/URLIndicator.js @@ -20,10 +20,8 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -define( - ['zepto'], - function ($) { - +define([], + function () { // Set of connection states; changing among these states will be // reflected in the indicator's appearance. // CONNECTED: Everything nominal, expect to be able to read/write. @@ -75,12 +73,17 @@ define( }; URLIndicator.prototype.fetchUrl = function () { - $.ajax({ - type: 'GET', - url: this.URLpath, - success: this.handleSuccess, - error: this.handleError - }); + fetch(this.URLpath) + .then(response => { + if (response.ok) { + this.handleSuccess(); + } else { + this.handleError(); + } + }) + .catch(error => { + this.handleError(); + }); }; URLIndicator.prototype.handleError = function (e) { diff --git a/src/plugins/URLIndicatorPlugin/URLIndicatorSpec.js b/src/plugins/URLIndicatorPlugin/URLIndicatorSpec.js index 408a98cd09..cf6cd39ff6 100644 --- a/src/plugins/URLIndicatorPlugin/URLIndicatorSpec.js +++ b/src/plugins/URLIndicatorPlugin/URLIndicatorSpec.js @@ -25,37 +25,35 @@ define( "utils/testing", "./URLIndicator", "./URLIndicatorPlugin", - "../../MCT", - "zepto" + "../../MCT" ], function ( testingUtils, URLIndicator, URLIndicatorPlugin, - MCT, - $ + MCT ) { - const defaultAjaxFunction = $.ajax; - describe("The URLIndicator", function () { let openmct; let indicatorElement; let pluginOptions; - let ajaxOptions; let urlIndicator; // eslint-disable-line + let fetchSpy; beforeEach(function () { jasmine.clock().install(); openmct = new testingUtils.createOpenMct(); spyOn(openmct.indicators, 'add'); - spyOn($, 'ajax'); - $.ajax.and.callFake(function (options) { - ajaxOptions = options; - }); + fetchSpy = spyOn(window, 'fetch').and.callFake(() => Promise.resolve({ + ok: true + })); }); afterEach(function () { - $.ajax = defaultAjaxFunction; + if (window.fetch.restore) { + window.fetch.restore(); + } + jasmine.clock().uninstall(); return testingUtils.resetApplicationState(openmct); @@ -96,11 +94,11 @@ define( expect(indicatorElement.classList.contains('iconClass-checked')).toBe(true); }); it("uses custom interval", function () { - expect($.ajax.calls.count()).toEqual(1); + expect(window.fetch).toHaveBeenCalledTimes(1); jasmine.clock().tick(1); - expect($.ajax.calls.count()).toEqual(1); + expect(window.fetch).toHaveBeenCalledTimes(1); jasmine.clock().tick(pluginOptions.interval + 1); - expect($.ajax.calls.count()).toEqual(2); + expect(window.fetch).toHaveBeenCalledTimes(2); }); it("uses custom label if supplied in initialization", function () { expect(indicatorElement.textContent.indexOf(pluginOptions.label) >= 0).toBe(true); @@ -120,18 +118,21 @@ define( it("requests the provided URL", function () { jasmine.clock().tick(pluginOptions.interval + 1); - expect(ajaxOptions.url).toEqual(pluginOptions.url); + expect(window.fetch).toHaveBeenCalledWith(pluginOptions.url); }); - it("indicates success if connection is nominal", function () { + it("indicates success if connection is nominal", async function () { jasmine.clock().tick(pluginOptions.interval + 1); - ajaxOptions.success(); + await urlIndicator.fetchUrl(); expect(indicatorElement.classList.contains('s-status-on')).toBe(true); }); - it("indicates an error when the server cannot be reached", function () { + it("indicates an error when the server cannot be reached", async function () { + fetchSpy.and.callFake(() => Promise.resolve({ + ok: false + })); jasmine.clock().tick(pluginOptions.interval + 1); - ajaxOptions.error(); + await urlIndicator.fetchUrl(); expect(indicatorElement.classList.contains('s-status-warning-hi')).toBe(true); }); }); diff --git a/src/plugins/autoflow/AutoflowTabularPluginSpec.js b/src/plugins/autoflow/AutoflowTabularPluginSpec.js index ce20cab1d6..5e5d49489d 100644 --- a/src/plugins/autoflow/AutoflowTabularPluginSpec.js +++ b/src/plugins/autoflow/AutoflowTabularPluginSpec.js @@ -21,7 +21,6 @@ *****************************************************************************/ import AutoflowTabularPlugin from './AutoflowTabularPlugin'; import AutoflowTabularConstants from './AutoflowTabularConstants'; -import $ from 'zepto'; import DOMObserver from './dom-observer'; import { createOpenMct, @@ -122,7 +121,7 @@ xdescribe("AutoflowTabularPlugin", () => { name: "Object " + key }; }); - testContainer = $('
')[0]; + testContainer = document.createElement('div'); domObserver = new DOMObserver(testContainer); testHistories = testKeys.reduce((histories, key, index) => { @@ -195,7 +194,7 @@ xdescribe("AutoflowTabularPlugin", () => { describe("when rows have been populated", () => { function rowsMatch() { - const rows = $(testContainer).find(".l-autoflow-row").length; + const rows = testContainer.querySelectorAll(".l-autoflow-row").length; return rows === testChildren.length; } @@ -241,20 +240,20 @@ xdescribe("AutoflowTabularPlugin", () => { const nextWidth = initialWidth + AutoflowTabularConstants.COLUMN_WIDTH_STEP; - expect($(testContainer).find('.l-autoflow-col').css('width')) + expect(testContainer.querySelector('.l-autoflow-col').css('width')) .toEqual(initialWidth + 'px'); - $(testContainer).find('.change-column-width').click(); + testContainer.querySelector('.change-column-width').click(); function widthHasChanged() { - const width = $(testContainer).find('.l-autoflow-col').css('width'); + const width = testContainer.querySelector('.l-autoflow-col').css('width'); return width !== initialWidth + 'px'; } return domObserver.when(widthHasChanged) .then(() => { - expect($(testContainer).find('.l-autoflow-col').css('width')) + expect(testContainer.querySelector('.l-autoflow-col').css('width')) .toEqual(nextWidth + 'px'); }); }); @@ -267,13 +266,13 @@ xdescribe("AutoflowTabularPlugin", () => { it("displays historical telemetry", () => { function rowTextDefined() { - return $(testContainer).find(".l-autoflow-item").filter(".r").text() !== ""; + return testContainer.querySelector(".l-autoflow-item").filter(".r").text() !== ""; } return domObserver.when(rowTextDefined).then(() => { testKeys.forEach((key, index) => { const datum = testHistories[key]; - const $cell = $(testContainer).find(".l-autoflow-row").eq(index).find(".r"); + const $cell = testContainer.querySelector(".l-autoflow-row").eq(index).find(".r"); expect($cell.text()).toEqual(String(datum.range)); }); }); @@ -294,7 +293,7 @@ xdescribe("AutoflowTabularPlugin", () => { return waitsForChange().then(() => { testData.forEach((datum, index) => { - const $cell = $(testContainer).find(".l-autoflow-row").eq(index).find(".r"); + const $cell = testContainer.querySelector(".l-autoflow-row").eq(index).find(".r"); expect($cell.text()).toEqual(String(datum.range)); }); }); @@ -312,7 +311,7 @@ xdescribe("AutoflowTabularPlugin", () => { return waitsForChange().then(() => { testKeys.forEach((datum, index) => { - const $cell = $(testContainer).find(".l-autoflow-row").eq(index).find(".r"); + const $cell = testContainer.querySelector(".l-autoflow-row").eq(index).find(".r"); expect($cell.hasClass(testClass)).toBe(true); }); }); @@ -322,16 +321,16 @@ xdescribe("AutoflowTabularPlugin", () => { const rowHeight = AutoflowTabularConstants.ROW_HEIGHT; const sliderHeight = AutoflowTabularConstants.SLIDER_HEIGHT; const count = testKeys.length; - const $container = $(testContainer); + const $container = testContainer; let promiseChain = Promise.resolve(); function columnsHaveAutoflowed() { - const itemsHeight = $container.find('.l-autoflow-items').height(); + const itemsHeight = $container.querySelector('.l-autoflow-items').height(); const availableHeight = itemsHeight - sliderHeight; const availableRows = Math.max(Math.floor(availableHeight / rowHeight), 1); const columns = Math.ceil(count / availableRows); - return $container.find('.l-autoflow-col').length === columns; + return $container.querySelector('.l-autoflow-col').length === columns; } $container.find('.abs').css({ diff --git a/src/plugins/licenses/third-party-licenses.json b/src/plugins/licenses/third-party-licenses.json index 184024eb41..c139298ce1 100644 --- a/src/plugins/licenses/third-party-licenses.json +++ b/src/plugins/licenses/third-party-licenses.json @@ -256,13 +256,6 @@ "licenseFile": "/Users/akhenry/Code/licenses/node_modules/vue/LICENSE", "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2013-present, Yuxi (Evan) You\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.", "copyright": "Copyright (c) 2013-present, Yuxi (Evan) You" - }, - "zepto@1.2.0": { - "licenses": "MIT", - "repository": "https://github.com/madrobby/zepto", - "path": "/Users/akhenry/Code/licenses/node_modules/zepto", - "licenseFile": "/Users/akhenry/Code/licenses/node_modules/zepto/README.md", - "licenseText": "Copyright (c) 2010-2018 Thomas Fuchs\nhttp://zeptojs.com/\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." } } diff --git a/src/plugins/summaryWidget/src/Condition.js b/src/plugins/summaryWidget/src/Condition.js index 997ad67b4f..66f9ecbeb2 100644 --- a/src/plugins/summaryWidget/src/Condition.js +++ b/src/plugins/summaryWidget/src/Condition.js @@ -4,16 +4,16 @@ define([ './input/KeySelect', './input/OperationSelect', './eventHelpers', - 'EventEmitter', - 'zepto' + '../../../utils/template/templateHelpers', + 'EventEmitter' ], function ( conditionTemplate, ObjectSelect, KeySelect, OperationSelect, eventHelpers, - EventEmitter, - $ + templateHelpers, + EventEmitter ) { /** * Represents an individual condition for a summary widget rule. Manages the @@ -31,12 +31,13 @@ define([ this.index = index; this.conditionManager = conditionManager; - this.domElement = $(conditionTemplate); + this.domElement = templateHelpers.convertTemplateToHTML(conditionTemplate)[0]; + this.eventEmitter = new EventEmitter(); this.supportedCallbacks = ['remove', 'duplicate', 'change']; - this.deleteButton = $('.t-delete', this.domElement); - this.duplicateButton = $('.t-duplicate', this.domElement); + this.deleteButton = this.domElement.querySelector('.t-delete'); + this.duplicateButton = this.domElement.querySelector('.t-duplicate'); this.selects = {}; this.valueInputs = []; @@ -105,9 +106,10 @@ define([ }); Object.values(this.selects).forEach(function (select) { - $('.t-configuration', self.domElement).append(select.getDOM()); + self.domElement.querySelector('.t-configuration').append(select.getDOM()); }); - this.listenTo($('.t-value-inputs', this.domElement), 'input', onValueInput); + + this.listenTo(this.domElement.querySelector('.t-value-inputs'), 'input', onValueInput); } Condition.prototype.getDOM = function (container) { @@ -132,7 +134,7 @@ define([ * Hide the appropriate inputs when this is the only condition */ Condition.prototype.hideButtons = function () { - this.deleteButton.hide(); + this.deleteButton.style.display = 'none'; }; /** @@ -172,14 +174,14 @@ define([ */ Condition.prototype.generateValueInputs = function (operation) { const evaluator = this.conditionManager.getEvaluator(); - const inputArea = $('.t-value-inputs', this.domElement); + const inputArea = this.domElement.querySelector('.t-value-inputs'); let inputCount; let inputType; let newInput; let index = 0; let emitChange = false; - inputArea.html(''); + inputArea.innerHTML = ''; this.valueInputs = []; this.config.values = this.config.values || []; @@ -189,17 +191,24 @@ define([ while (index < inputCount) { if (inputType === 'select') { - newInput = $(''); + const options = this.generateSelectOptions(); + + newInput = document.createElement("select"); + newInput.innerHTML = options; + emitChange = true; } else { const defaultValue = inputType === 'number' ? 0 : ''; const value = this.config.values[index] || defaultValue; this.config.values[index] = value; - newInput = $(''); + + newInput = document.createElement("input"); + newInput.type = `${inputType}`; + newInput.value = `${value}`; } - this.valueInputs.push(newInput.get(0)); - inputArea.append(newInput); + this.valueInputs.push(newInput); + inputArea.appendChild(newInput); index += 1; } diff --git a/src/plugins/summaryWidget/src/ConditionManager.js b/src/plugins/summaryWidget/src/ConditionManager.js index ff90bc7bc7..e502649030 100644 --- a/src/plugins/summaryWidget/src/ConditionManager.js +++ b/src/plugins/summaryWidget/src/ConditionManager.js @@ -2,13 +2,11 @@ define ([ './ConditionEvaluator', 'objectUtils', 'EventEmitter', - 'zepto', 'lodash' ], function ( ConditionEvaluator, objectUtils, EventEmitter, - $, _ ) { @@ -232,7 +230,10 @@ define ([ self.eventEmitter.emit('add', obj); - $('.w-summary-widget').removeClass('s-status-no-data'); + const summaryWidget = document.querySelector('.w-summary-widget'); + if (summaryWidget) { + summaryWidget.classList.remove('s-status-no-data'); + } } }; @@ -256,7 +257,10 @@ define ([ this.eventEmitter.emit('remove', identifier); if (_.isEmpty(this.compositionObjs)) { - $('.w-summary-widget').addClass('s-status-no-data'); + const summaryWidget = document.querySelector('.w-summary-widget'); + if (summaryWidget) { + summaryWidget.classList.add('s-status-no-data'); + } } }; diff --git a/src/plugins/summaryWidget/src/Rule.js b/src/plugins/summaryWidget/src/Rule.js index d9217f0e0c..0b8f28804f 100644 --- a/src/plugins/summaryWidget/src/Rule.js +++ b/src/plugins/summaryWidget/src/Rule.js @@ -4,18 +4,18 @@ define([ './input/ColorPalette', './input/IconPalette', './eventHelpers', + '../../../utils/template/templateHelpers', 'EventEmitter', - 'lodash', - 'zepto' + 'lodash' ], function ( ruleTemplate, Condition, ColorPalette, IconPalette, eventHelpers, + templateHelpers, EventEmitter, - _, - $ + _ ) { /** * An object representing a summary widget rule. Maintains a set of text @@ -41,7 +41,7 @@ define([ this.widgetDnD = widgetDnD; this.container = container; - this.domElement = $(ruleTemplate); + this.domElement = templateHelpers.convertTemplateToHTML(ruleTemplate)[0]; this.eventEmitter = new EventEmitter(); this.supportedCallbacks = ['remove', 'duplicate', 'change', 'conditionChange']; this.conditions = []; @@ -50,31 +50,32 @@ define([ this.remove = this.remove.bind(this); this.duplicate = this.duplicate.bind(this); - this.thumbnail = $('.t-widget-thumb', this.domElement); - this.thumbnailIcon = $('.js-sw__icon', this.domElement); - this.thumbnailLabel = $('.c-sw__label', this.domElement); - this.title = $('.rule-title', this.domElement); - this.description = $('.rule-description', this.domElement); - this.trigger = $('.t-trigger', this.domElement); - this.toggleConfigButton = $('.js-disclosure', this.domElement); - this.configArea = $('.widget-rule-content', this.domElement); - this.grippy = $('.t-grippy', this.domElement); - this.conditionArea = $('.t-widget-rule-config', this.domElement); - this.jsConditionArea = $('.t-rule-js-condition-input-holder', this.domElement); - this.deleteButton = $('.t-delete', this.domElement); - this.duplicateButton = $('.t-duplicate', this.domElement); - this.addConditionButton = $('.add-condition', this.domElement); + this.thumbnail = this.domElement.querySelector('.t-widget-thumb'); + this.thumbnailIcon = this.domElement.querySelector('.js-sw__icon'); + this.thumbnailLabel = this.domElement.querySelector('.c-sw__label'); + this.title = this.domElement.querySelector('.rule-title'); + this.description = this.domElement.querySelector('.rule-description'); + this.trigger = this.domElement.querySelector('.t-trigger'); + this.toggleConfigButton = this.domElement.querySelector('.js-disclosure'); + this.configArea = this.domElement.querySelector('.widget-rule-content'); + this.grippy = this.domElement.querySelector('.t-grippy'); + this.conditionArea = this.domElement.querySelector('.t-widget-rule-config'); + this.jsConditionArea = this.domElement.querySelector('.t-rule-js-condition-input-holder'); + this.deleteButton = this.domElement.querySelector('.t-delete'); + this.duplicateButton = this.domElement.querySelector('.t-duplicate'); + this.addConditionButton = this.domElement.querySelector('.add-condition'); /** * The text inputs for this rule: any input included in this object will * have the appropriate event handlers registered to it, and it's corresponding * field in the domain object will be updated with its value */ + this.textInputs = { - name: $('.t-rule-name-input', this.domElement), - label: $('.t-rule-label-input', this.domElement), - message: $('.t-rule-message-input', this.domElement), - jsCondition: $('.t-rule-js-condition-input', this.domElement) + name: this.domElement.querySelector('.t-rule-name-input'), + label: this.domElement.querySelector('.t-rule-label-input'), + message: this.domElement.querySelector('.t-rule-message-input'), + jsCondition: this.domElement.querySelector('.t-rule-js-condition-input') }; this.iconInput = new IconPalette('', container); @@ -94,7 +95,7 @@ define([ function onIconInput(icon) { self.config.icon = icon; self.updateDomainObject('icon', icon); - self.thumbnailIcon.removeClass().addClass(THUMB_ICON_CLASS + ' ' + icon); + self.thumbnailIcon.className = `${THUMB_ICON_CLASS + ' ' + icon}`; self.eventEmitter.emit('change'); } @@ -106,7 +107,7 @@ define([ */ function onColorInput(color, property) { self.config.style[property] = color; - self.thumbnail.css(property, color); + self.thumbnail.style[property] = color; self.eventEmitter.emit('change'); } @@ -116,7 +117,10 @@ define([ * @private */ function encodeMsg(msg) { - return $('
').text(msg).html(); + const div = document.createElement('div'); + div.innerText = msg; + + return div.innerText; } /** @@ -144,9 +148,9 @@ define([ self.config[inputKey] = text; self.updateDomainObject(); if (inputKey === 'name') { - self.title.html(text); + self.title.innerText = text; } else if (inputKey === 'label') { - self.thumbnailLabel.html(text); + self.thumbnailLabel.innerText = text; } self.eventEmitter.emit('change'); @@ -158,13 +162,14 @@ define([ * @private */ function onDragStart(event) { - $('.t-drag-indicator').each(function () { + document.querySelectorAll('.t-drag-indicator').forEach(indicator => { // eslint-disable-next-line no-invalid-this - $(this).html($('.widget-rule-header', self.domElement).clone().get(0)); + const ruleHeader = self.domElement.querySelectorAll('.widget-rule-header')[0].cloneNode(true); + indicator.innerHTML = ruleHeader; }); - self.widgetDnD.setDragImage($('.widget-rule-header', self.domElement).clone().get(0)); + self.widgetDnD.setDragImage(self.domElement.querySelectorAll('.widget-rule-header')[0].cloneNode(true)); self.widgetDnD.dragStart(self.config.id); - self.domElement.hide(); + self.domElement.style.display = 'none'; } /** @@ -172,20 +177,31 @@ define([ * @private */ function toggleConfig() { - self.configArea.toggleClass('expanded'); - self.toggleConfigButton.toggleClass('c-disclosure-triangle--expanded'); + if (self.configArea.classList.contains('expanded')) { + self.configArea.classList.remove('expanded'); + } else { + self.configArea.classList.add('expanded'); + } + + if (self.toggleConfigButton.classList.contains('c-disclosure-triangle--expanded')) { + self.toggleConfigButton.classList.remove('c-disclosure-triangle--expanded'); + } else { + self.toggleConfigButton.classList.add('c-disclosure-triangle--expanded'); + } + self.config.expanded = !self.config.expanded; } - $('.t-rule-label-input', this.domElement).before(this.iconInput.getDOM()); + const labelInput = this.domElement.querySelector('.t-rule-label-input'); + labelInput.parentNode.insertBefore(this.iconInput.getDOM(), labelInput); this.iconInput.set(self.config.icon); this.iconInput.on('change', function (value) { onIconInput(value); }); // Initialize thumbs when first loading - this.thumbnailIcon.removeClass().addClass(THUMB_ICON_CLASS + ' ' + self.config.icon); - this.thumbnailLabel.html(self.config.label); + this.thumbnailIcon.className = `${THUMB_ICON_CLASS + ' ' + self.config.icon}`; + this.thumbnailLabel.innerText = self.config.label; Object.keys(this.colorInputs).forEach(function (inputKey) { const input = self.colorInputs[inputKey]; @@ -198,15 +214,17 @@ define([ self.updateDomainObject(); }); - $('.t-style-input', self.domElement).append(input.getDOM()); + self.domElement.querySelector('.t-style-input').append(input.getDOM()); }); Object.keys(this.textInputs).forEach(function (inputKey) { - self.textInputs[inputKey].prop('value', self.config[inputKey] || ''); - self.listenTo(self.textInputs[inputKey], 'input', function () { - // eslint-disable-next-line no-invalid-this - onTextInput(this, inputKey); - }); + if (self.textInputs[inputKey]) { + self.textInputs[inputKey].value = self.config[inputKey] || ''; + self.listenTo(self.textInputs[inputKey], 'input', function () { + // eslint-disable-next-line no-invalid-this + onTextInput(this, inputKey); + }); + } }); this.listenTo(this.deleteButton, 'click', this.remove); @@ -217,15 +235,15 @@ define([ this.listenTo(this.toggleConfigButton, 'click', toggleConfig); this.listenTo(this.trigger, 'change', onTriggerInput); - this.title.html(self.config.name); - this.description.html(self.config.description); - this.trigger.prop('value', self.config.trigger); + this.title.innerHTML = self.config.name; + this.description.innerHTML = self.config.description; + this.trigger.value = self.config.trigger; this.listenTo(this.grippy, 'mousedown', onDragStart); this.widgetDnD.on('drop', function () { // eslint-disable-next-line no-invalid-this this.domElement.show(); - $('.t-drag-indicator').hide(); + document.querySelector('.t-drag-indicator').style.display = 'none'; }, this); if (!this.conditionManager.loadCompleted()) { @@ -233,21 +251,21 @@ define([ } if (!this.config.expanded) { - this.configArea.removeClass('expanded'); - this.toggleConfigButton.removeClass('c-disclosure-triangle--expanded'); + this.configArea.classList.remove('expanded'); + this.toggleConfigButton.classList.remove('c-disclosure-triangle--expanded'); } if (this.domainObject.configuration.ruleOrder.length === 2) { - $('.t-grippy', this.domElement).hide(); + this.domElement.querySelector('.t-grippy').style.display = 'none'; } this.refreshConditions(); //if this is the default rule, hide elements that don't apply if (this.config.id === 'default') { - $('.t-delete', this.domElement).hide(); - $('.t-widget-rule-config', this.domElement).hide(); - $('.t-grippy', this.domElement).hide(); + this.domElement.querySelector('.t-delete').style.display = 'none'; + this.domElement.querySelector('.t-widget-rule-config').style.display = 'none'; + this.domElement.querySelector('.t-grippy').style.display = 'none'; } } @@ -304,8 +322,8 @@ define([ * During a rule drag event, show the placeholder element after this rule */ Rule.prototype.showDragIndicator = function () { - $('.t-drag-indicator').hide(); - $('.t-drag-indicator', this.domElement).show(); + document.querySelector('.t-drag-indicator').style.display = 'none'; + this.domElement.querySelector('.t-drag-indicator').style.display = ''; }; /** @@ -397,7 +415,10 @@ define([ const triggerContextStr = self.config.trigger === 'any' ? ' or ' : ' and '; self.conditions = []; - $('.t-condition', this.domElement).remove(); + + this.domElement.querySelectorAll('.t-condition').forEach(condition => { + condition.remove(); + }); this.config.conditions.forEach(function (condition, index) { const newCondition = new Condition(condition, index, self.conditionManager); @@ -408,16 +429,23 @@ define([ }); if (this.config.trigger === 'js') { - this.jsConditionArea.show(); - this.addConditionButton.hide(); + if (this.jsConditionArea) { + this.jsConditionArea.style.display = ''; + } + + this.addConditionButton.style.display = 'none'; } else { - this.jsConditionArea.hide(); - this.addConditionButton.show(); + if (this.jsConditionArea) { + this.jsConditionArea.style.display = 'none'; + } + + this.addConditionButton.style.display = ''; self.conditions.forEach(function (condition) { $condition = condition.getDOM(); - $('li:last-of-type', self.conditionArea).before($condition); + const lastOfType = self.conditionArea.querySelector('li:last-of-type'); + lastOfType.parentNode.insertBefore($condition, lastOfType); if (loopCnt > 0) { - $('.t-condition-context', $condition).html(triggerContextStr + ' when'); + $condition.querySelector('.t-condition-context').innerHTML = triggerContextStr + ' when'; } loopCnt++; @@ -489,7 +517,7 @@ define([ } description = (description === '' ? this.config.description : description); - this.description.html(description); + this.description.innerHTML = self.config.description; this.config.description = description; }; diff --git a/src/plugins/summaryWidget/src/SummaryWidget.js b/src/plugins/summaryWidget/src/SummaryWidget.js index 1a5c1ceba0..e9c1442bf2 100644 --- a/src/plugins/summaryWidget/src/SummaryWidget.js +++ b/src/plugins/summaryWidget/src/SummaryWidget.js @@ -5,9 +5,9 @@ define([ './TestDataManager', './WidgetDnD', './eventHelpers', + '../../../utils/template/templateHelpers', 'objectUtils', 'lodash', - 'zepto', '@braintree/sanitize-url' ], function ( widgetTemplate, @@ -16,9 +16,9 @@ define([ TestDataManager, WidgetDnD, eventHelpers, + templateHelpers, objectUtils, _, - $, urlSanitizeLib ) { @@ -54,20 +54,22 @@ define([ this.activeId = 'default'; this.rulesById = {}; - this.domElement = $(widgetTemplate); - this.toggleRulesControl = $('.t-view-control-rules', this.domElement); - this.toggleTestDataControl = $('.t-view-control-test-data', this.domElement); - this.widgetButton = this.domElement.children('#widget'); + this.domElement = templateHelpers.convertTemplateToHTML(widgetTemplate)[0]; + this.toggleRulesControl = this.domElement.querySelector('.t-view-control-rules'); + this.toggleTestDataControl = this.domElement.querySelector('.t-view-control-test-data'); + + this.widgetButton = this.domElement.querySelector(':scope > #widget'); + this.editing = false; this.container = ''; - this.editListenerUnsubscribe = $.noop; + this.editListenerUnsubscribe = () => {}; - this.outerWrapper = $('.widget-edit-holder', this.domElement); - this.ruleArea = $('#ruleArea', this.domElement); - this.configAreaRules = $('.widget-rules-wrapper', this.domElement); + this.outerWrapper = this.domElement.querySelector('.widget-edit-holder'); + this.ruleArea = this.domElement.querySelector('#ruleArea'); + this.configAreaRules = this.domElement.querySelector('.widget-rules-wrapper'); - this.testDataArea = $('.widget-test-data', this.domElement); - this.addRuleButton = $('#addRule', this.domElement); + this.testDataArea = this.domElement.querySelector('.widget-test-data'); + this.addRuleButton = this.domElement.querySelector('#addRule'); this.conditionManager = new ConditionManager(this.domainObject, this.openmct); this.testDataManager = new TestDataManager(this.domainObject, this.conditionManager, this.openmct); @@ -87,8 +89,17 @@ define([ * @private */ function toggleTestData() { - self.outerWrapper.toggleClass('expanded-widget-test-data'); - self.toggleTestDataControl.toggleClass('c-disclosure-triangle--expanded'); + if (self.outerWrapper.classList.contains('expanded-widget-test-data')) { + self.outerWrapper.classList.remove('expanded-widget-test-data'); + } else { + self.outerWrapper.classList.add('expanded-widget-test-data'); + } + + if (self.toggleTestDataControl.classList.contains('c-disclosure-triangle--expanded')) { + self.toggleTestDataControl.classList.remove('c-disclosure-triangle--expanded'); + } else { + self.toggleTestDataControl.classList.add('c-disclosure-triangle--expanded'); + } } this.listenTo(this.toggleTestDataControl, 'click', toggleTestData); @@ -98,8 +109,8 @@ define([ * @private */ function toggleRules() { - self.outerWrapper.toggleClass('expanded-widget-rules'); - self.toggleRulesControl.toggleClass('c-disclosure-triangle--expanded'); + templateHelpers.toggleClass(self.outerWrapper, 'expanded-widget-rules'); + templateHelpers.toggleClass(self.toggleRulesControl, 'c-disclosure-triangle--expanded'); } this.listenTo(this.toggleRulesControl, 'click', toggleRules); @@ -113,15 +124,15 @@ define([ */ SummaryWidget.prototype.addHyperlink = function (url, openNewTab) { if (url) { - this.widgetButton.attr('href', urlSanitizeLib.sanitizeUrl(url)); + this.widgetButton.href = urlSanitizeLib.sanitizeUrl(url); } else { - this.widgetButton.removeAttr('href'); + this.widgetButton.removeAttribute('href'); } if (openNewTab === 'newTab') { - this.widgetButton.attr('target', '_blank'); + this.widgetButton.target = '_blank'; } else { - this.widgetButton.removeAttr('target'); + this.widgetButton.removeAttribute('target'); } }; @@ -149,8 +160,8 @@ define([ SummaryWidget.prototype.show = function (container) { const self = this; this.container = container; - $(container).append(this.domElement); - $('.widget-test-data', this.domElement).append(this.testDataManager.getDOM()); + this.container.append(this.domElement); + this.domElement.querySelector('.widget-test-data').append(this.testDataManager.getDOM()); this.widgetDnD = new WidgetDnD(this.domElement, this.domainObject.configuration.ruleOrder, this.rulesById); this.initRule('default', 'Default'); this.domainObject.configuration.ruleOrder.forEach(function (ruleId) { @@ -190,7 +201,7 @@ define([ const self = this; const ruleOrder = self.domainObject.configuration.ruleOrder; const rules = self.rulesById; - self.ruleArea.html(''); + self.ruleArea.innerHTML = ''; Object.values(ruleOrder).forEach(function (ruleId) { self.ruleArea.append(rules[ruleId].getDOM()); }); @@ -205,9 +216,9 @@ define([ rules.forEach(function (ruleKey, index, array) { if (array.length > 2 && index > 0) { - $('.t-grippy', rulesById[ruleKey].domElement).show(); + rulesById[ruleKey].domElement.querySelector('.t-grippy').style.display = ''; } else { - $('.t-grippy', rulesById[ruleKey].domElement).hide(); + rulesById[ruleKey].domElement.querySelector('.t-grippy').style.display = 'none'; } }); }; @@ -218,10 +229,10 @@ define([ SummaryWidget.prototype.updateWidget = function () { const WIDGET_ICON_CLASS = 'c-sw__icon js-sw__icon'; const activeRule = this.rulesById[this.activeId]; - this.applyStyle($('#widget', this.domElement), activeRule.getProperty('style')); - $('#widget', this.domElement).prop('title', activeRule.getProperty('message')); - $('#widgetLabel', this.domElement).html(activeRule.getProperty('label')); - $('#widgetIcon', this.domElement).removeClass().addClass(WIDGET_ICON_CLASS + ' ' + activeRule.getProperty('icon')); + this.applyStyle(this.domElement.querySelector('#widget'), activeRule.getProperty('style')); + this.domElement.querySelector('#widget').title = activeRule.getProperty('message'); + this.domElement.querySelector('#widgetLabel').innerHTML = activeRule.getProperty('label'); + this.domElement.querySelector('#widgetIcon').classList = WIDGET_ICON_CLASS + ' ' + activeRule.getProperty('icon'); }; /** @@ -356,7 +367,7 @@ define([ */ SummaryWidget.prototype.applyStyle = function (elem, style) { Object.keys(style).forEach(function (propId) { - elem.css(propId, style[propId]); + elem.style[propId] = style[propId]; }); }; diff --git a/src/plugins/summaryWidget/src/TestDataItem.js b/src/plugins/summaryWidget/src/TestDataItem.js index 32b737a90e..ae005c46d0 100644 --- a/src/plugins/summaryWidget/src/TestDataItem.js +++ b/src/plugins/summaryWidget/src/TestDataItem.js @@ -3,15 +3,15 @@ define([ './input/ObjectSelect', './input/KeySelect', './eventHelpers', - 'EventEmitter', - 'zepto' + '../../../utils/template/templateHelpers', + 'EventEmitter' ], function ( itemTemplate, ObjectSelect, KeySelect, eventHelpers, - EventEmitter, - $ + templateHelpers, + EventEmitter ) { /** @@ -31,12 +31,12 @@ define([ this.index = index; this.conditionManager = conditionManager; - this.domElement = $(itemTemplate); + this.domElement = templateHelpers.convertTemplateToHTML(itemTemplate)[0]; this.eventEmitter = new EventEmitter(); this.supportedCallbacks = ['remove', 'duplicate', 'change']; - this.deleteButton = $('.t-delete', this.domElement); - this.duplicateButton = $('.t-duplicate', this.domElement); + this.deleteButton = this.domElement.querySelector('.t-delete'); + this.duplicateButton = this.domElement.querySelector('.t-duplicate'); this.selects = {}; this.valueInputs = []; @@ -101,7 +101,7 @@ define([ }); Object.values(this.selects).forEach(function (select) { - $('.t-configuration', self.domElement).append(select.getDOM()); + self.domElement.querySelector('.t-configuration').append(select.getDOM()); }); this.listenTo(this.domElement, 'input', onValueInput); } @@ -139,7 +139,7 @@ define([ * Hide the appropriate inputs when this is the only item */ TestDataItem.prototype.hideButtons = function () { - this.deleteButton.hide(); + this.deleteButton.style.display = 'none'; }; /** @@ -177,17 +177,21 @@ define([ */ TestDataItem.prototype.generateValueInput = function (key) { const evaluator = this.conditionManager.getEvaluator(); - const inputArea = $('.t-value-inputs', this.domElement); + const inputArea = this.domElement.querySelector('.t-value-inputs'); const dataType = this.conditionManager.getTelemetryPropertyType(this.config.object, key); const inputType = evaluator.getInputTypeById(dataType); - inputArea.html(''); + inputArea.innerHTML = ''; if (inputType) { if (!this.config.value) { this.config.value = (inputType === 'number' ? 0 : ''); } - this.valueInput = $(' ').get(0); + const newInput = document.createElement("input"); + newInput.type = `${inputType}`; + newInput.value = `${this.config.value}`; + + this.valueInput = newInput; inputArea.append(this.valueInput); } }; diff --git a/src/plugins/summaryWidget/src/TestDataManager.js b/src/plugins/summaryWidget/src/TestDataManager.js index 819cc5ee3f..70240453d6 100644 --- a/src/plugins/summaryWidget/src/TestDataManager.js +++ b/src/plugins/summaryWidget/src/TestDataManager.js @@ -2,13 +2,13 @@ define([ './eventHelpers', '../res/testDataTemplate.html', './TestDataItem', - 'zepto', + '../../../utils/template/templateHelpers', 'lodash' ], function ( eventHelpers, testDataTemplate, TestDataItem, - $, + templateHelpers, _ ) { @@ -28,13 +28,13 @@ define([ this.openmct = openmct; this.evaluator = this.manager.getEvaluator(); - this.domElement = $(testDataTemplate); + this.domElement = templateHelpers.convertTemplateToHTML(testDataTemplate)[0]; this.config = this.domainObject.configuration.testDataConfig; this.testCache = {}; - this.itemArea = $('.t-test-data-config', this.domElement); - this.addItemButton = $('.add-test-condition', this.domElement); - this.testDataInput = $('.t-test-data-checkbox', this.domElement); + this.itemArea = this.domElement.querySelector('.t-test-data-config'); + this.addItemButton = this.domElement.querySelector('.add-test-condition'); + this.testDataInput = this.domElement.querySelector('.t-test-data-checkbox'); /** * Toggles whether the associated {ConditionEvaluator} uses the actual @@ -139,7 +139,10 @@ define([ } self.items = []; - $('.t-test-data-item', this.domElement).remove(); + + this.domElement.querySelectorAll('.t-test-data-item').forEach(item => { + item.remove(); + }); this.config.forEach(function (item, index) { const newItem = new TestDataItem(item, index, self.manager); @@ -150,7 +153,6 @@ define([ }); self.items.forEach(function (item) { - // $('li:last-of-type', self.itemArea).before(item.getDOM()); self.itemArea.prepend(item.getDOM()); }); diff --git a/src/plugins/summaryWidget/src/WidgetDnD.js b/src/plugins/summaryWidget/src/WidgetDnD.js index e9ee2f0400..90cd3b6971 100644 --- a/src/plugins/summaryWidget/src/WidgetDnD.js +++ b/src/plugins/summaryWidget/src/WidgetDnD.js @@ -1,11 +1,11 @@ define([ '../res/ruleImageTemplate.html', 'EventEmitter', - 'zepto' + '../../../utils/template/templateHelpers' ], function ( ruleImageTemplate, EventEmitter, - $ + templateHelpers ) { /** @@ -19,8 +19,8 @@ define([ this.ruleOrder = ruleOrder; this.rulesById = rulesById; - this.imageContainer = $(ruleImageTemplate); - this.image = $('.t-drag-rule-image', this.imageContainer); + this.imageContainer = templateHelpers.convertTemplateToHTML(ruleImageTemplate)[0]; + this.image = this.imageContainer.querySelector('.t-drag-rule-image'); this.draggingId = ''; this.draggingRulePrevious = ''; this.eventEmitter = new EventEmitter(); @@ -29,18 +29,18 @@ define([ this.drag = this.drag.bind(this); this.drop = this.drop.bind(this); - $(this.container).on('mousemove', this.drag); - $(document).on('mouseup', this.drop); - $(this.container).before(this.imageContainer); - $(this.imageContainer).hide(); + this.container.addEventListener('mousemove', this.drag); + document.addEventListener('mouseup', this.drop); + this.container.parentNode.insertBefore(this.imageContainer, this.container); + this.imageContainer.style.display = 'none'; } /** * Remove event listeners registered to elements external to the widget */ WidgetDnD.prototype.destroy = function () { - $(this.container).off('mousemove', this.drag); - $(document).off('mouseup', this.drop); + this.container.removeEventListener('mousemove', this.drag); + document.removeEventListener('mouseup', this.drop); }; /** @@ -81,7 +81,8 @@ define([ let target = ''; ruleOrder.forEach(function (ruleId, index) { - offset = rulesById[ruleId].getDOM().offset(); + const ruleDOM = rulesById[ruleId].getDOM(); + offset = window.innerWidth - (ruleDOM.offsetLeft + ruleDOM.offsetWidth); y = offset.top; height = offset.height; if (index === 0) { @@ -114,7 +115,7 @@ define([ this.imageContainer.show(); this.imageContainer.offset({ top: event.pageY - this.image.height() / 2, - left: event.pageX - $('.t-grippy', this.image).width() + left: event.pageX - this.image.querySelector('.t-grippy').style.width }); }; @@ -129,7 +130,7 @@ define([ dragTarget = this.getDropLocation(event); this.imageContainer.offset({ top: event.pageY - this.image.height() / 2, - left: event.pageX - $('.t-grippy', this.image).width() + left: event.pageX - this.image.querySelector('.t-grippy').style.width }); if (this.rulesById[dragTarget]) { this.rulesById[dragTarget].showDragIndicator(); diff --git a/src/plugins/summaryWidget/src/input/ColorPalette.js b/src/plugins/summaryWidget/src/input/ColorPalette.js index 0bbe236419..2319f98304 100644 --- a/src/plugins/summaryWidget/src/input/ColorPalette.js +++ b/src/plugins/summaryWidget/src/input/ColorPalette.js @@ -1,10 +1,8 @@ define([ - './Palette', - 'zepto' + './Palette' ], function ( - Palette, - $ + Palette ) { //The colors that will be used to instantiate this palette if none are provided @@ -33,17 +31,16 @@ function ( this.palette.setNullOption('rgba(0,0,0,0)'); - const domElement = $(this.palette.getDOM()); + const domElement = this.palette.getDOM(); const self = this; - $('.c-button--menu', domElement).addClass('c-button--swatched'); - $('.t-swatch', domElement).addClass('color-swatch'); - $('.c-palette', domElement).addClass('c-palette--color'); + domElement.querySelector('.c-button--menu').classList.add('c-button--swatched'); + domElement.querySelector('.t-swatch').classList.add('color-swatch'); + domElement.querySelector('.c-palette').classList.add('c-palette--color'); - $('.c-palette__item', domElement).each(function () { + domElement.querySelectorAll('.c-palette__item').forEach(item => { // eslint-disable-next-line no-invalid-this - const elem = this; - $(elem).css('background-color', elem.dataset.item); + item.style.backgroundColor = item.dataset.item; }); /** @@ -53,7 +50,7 @@ function ( */ function updateSwatch() { const color = self.palette.getCurrent(); - $('.color-swatch', domElement).css('background-color', color); + domElement.querySelector('.color-swatch').style.backgroundColor = color; } this.palette.on('change', updateSwatch); diff --git a/src/plugins/summaryWidget/src/input/IconPalette.js b/src/plugins/summaryWidget/src/input/IconPalette.js index cdc011d5da..557cc4d958 100644 --- a/src/plugins/summaryWidget/src/input/IconPalette.js +++ b/src/plugins/summaryWidget/src/input/IconPalette.js @@ -1,9 +1,7 @@ define([ - './Palette', - 'zepto' + './Palette' ], function ( - Palette, - $ + Palette ) { //The icons that will be used to instantiate this palette if none are provided const DEFAULT_ICONS = [ @@ -45,20 +43,19 @@ define([ this.icons = icons || DEFAULT_ICONS; this.palette = new Palette(cssClass, container, this.icons); - this.palette.setNullOption(' '); - this.oldIcon = this.palette.current || ' '; + this.palette.setNullOption(''); + this.oldIcon = this.palette.current || ''; - const domElement = $(this.palette.getDOM()); + const domElement = this.palette.getDOM(); const self = this; - $('.c-button--menu', domElement).addClass('c-button--swatched'); - $('.t-swatch', domElement).addClass('icon-swatch'); - $('.c-palette', domElement).addClass('c-palette--icon'); + domElement.querySelector('.c-button--menu').classList.add('c-button--swatched'); + domElement.querySelector('.t-swatch').classList.add('icon-swatch'); + domElement.querySelector('.c-palette').classList.add('c-palette--icon'); - $('.c-palette-item', domElement).each(function () { + domElement.querySelectorAll('.c-palette-item').forEach(item => { // eslint-disable-next-line no-invalid-this - const elem = this; - $(elem).addClass(elem.dataset.item); + item.classList.add(item.dataset.item); }); /** @@ -67,8 +64,11 @@ define([ * @private */ function updateSwatch() { - $('.icon-swatch', domElement).removeClass(self.oldIcon) - .addClass(self.palette.getCurrent()); + if (self.oldIcon) { + domElement.querySelector('.icon-swatch').classList.remove(self.oldIcon); + } + + domElement.querySelector('.icon-swatch').classList.add(self.palette.getCurrent()); self.oldIcon = self.palette.getCurrent(); } diff --git a/src/plugins/summaryWidget/src/input/Palette.js b/src/plugins/summaryWidget/src/input/Palette.js index ff1d3b5500..96df813de2 100644 --- a/src/plugins/summaryWidget/src/input/Palette.js +++ b/src/plugins/summaryWidget/src/input/Palette.js @@ -1,13 +1,13 @@ define([ '../eventHelpers', '../../res/input/paletteTemplate.html', - 'EventEmitter', - 'zepto' + '../../../../utils/template/templateHelpers', + 'EventEmitter' ], function ( eventHelpers, paletteTemplate, - EventEmitter, - $ + templateHelpers, + EventEmitter ) { /** * Instantiates a new Open MCT Color Palette input @@ -28,36 +28,41 @@ define([ this.items = items; this.container = container; - this.domElement = $(paletteTemplate); + this.domElement = templateHelpers.convertTemplateToHTML(paletteTemplate)[0]; + this.itemElements = { - nullOption: $('.c-palette__item-none .c-palette__item', this.domElement) + nullOption: this.domElement.querySelector('.c-palette__item-none .c-palette__item') }; this.eventEmitter = new EventEmitter(); this.supportedCallbacks = ['change']; this.value = this.items[0]; this.nullOption = ' '; - this.button = $('.js-button', this.domElement); - this.menu = $('.c-menu', this.domElement); + this.button = this.domElement.querySelector('.js-button'); + this.menu = this.domElement.querySelector('.c-menu'); this.hideMenu = this.hideMenu.bind(this); - self.button.addClass(this.cssClass); + if (this.cssClass) { + self.button.classList.add(this.cssClass); + } + self.setNullOption(this.nullOption); self.items.forEach(function (item) { - const itemElement = $('
'); - $('.c-palette__items', self.domElement).append(itemElement); - self.itemElements[item] = itemElement; + const itemElement = `
`; + const temp = document.createElement('div'); + temp.innerHTML = itemElement; + self.itemElements[item] = temp.firstChild; + self.domElement.querySelector('.c-palette__items').appendChild(temp.firstChild); }); - $('.c-menu', self.domElement).hide(); + self.domElement.querySelector('.c-menu').style.display = 'none'; - this.listenTo($(document), 'click', this.hideMenu); - this.listenTo($('.js-button', self.domElement), 'click', function (event) { + this.listenTo(window.document, 'click', this.hideMenu); + this.listenTo(self.domElement.querySelector('.js-button'), 'click', function (event) { event.stopPropagation(); - $('.c-menu', self.container).hide(); - $('.c-menu', self.domElement).show(); + self.container.querySelector('.c-menu').style.display = 'none'; + self.domElement.querySelector('.c-menu').style.display = ''; }); /** @@ -70,10 +75,12 @@ define([ const elem = event.currentTarget; const item = elem.dataset.item; self.set(item); - $('.c-menu', self.domElement).hide(); + self.domElement.querySelector('.c-menu').style.display = 'none'; } - this.listenTo($('.c-palette__item', self.domElement), 'click', handleItemClick); + self.domElement.querySelectorAll('.c-palette__item').forEach(item => { + this.listenTo(item, 'click', handleItemClick); + }); } /** @@ -91,7 +98,7 @@ define([ }; Palette.prototype.hideMenu = function () { - $('.c-menu', this.domElement).hide(); + this.domElement.querySelector('.c-menu').style.display = 'none'; }; /** @@ -141,12 +148,16 @@ define([ * Update the view assoicated with the currently selected item */ Palette.prototype.updateSelected = function (item) { - $('.c-palette__item', this.domElement).removeClass('is-selected'); - this.itemElements[item].addClass('is-selected'); + this.domElement.querySelectorAll('.c-palette__item').forEach(paletteItem => { + if (paletteItem.classList.contains('is-selected')) { + paletteItem.classList.remove('is-selected'); + } + }); + this.itemElements[item].classList.add('is-selected'); if (item === 'nullOption') { - $('.t-swatch', this.domElement).addClass('no-selection'); + this.domElement.querySelector('.t-swatch').classList.add('no-selection'); } else { - $('.t-swatch', this.domElement).removeClass('no-selection'); + this.domElement.querySelector('.t-swatch').classList.remove('no-selection'); } }; @@ -157,14 +168,20 @@ define([ */ Palette.prototype.setNullOption = function (item) { this.nullOption = item; - this.itemElements.nullOption.data('item', item); + this.itemElements.nullOption.data = { item: item }; }; /** * Hides the 'no selection' option to be hidden in the view if it doesn't apply */ Palette.prototype.toggleNullOption = function () { - $('.c-palette__item-none', this.domElement).toggle(); + const elem = this.domElement.querySelector('.c-palette__item-none'); + + if (elem.style.display === 'none') { + this.domElement.querySelector('.c-palette__item-none').style.display = 'flex'; + } else { + this.domElement.querySelector('.c-palette__item-none').style.display = 'none'; + } }; return Palette; diff --git a/src/plugins/summaryWidget/src/input/Select.js b/src/plugins/summaryWidget/src/input/Select.js index 3f89034caf..676a9791b2 100644 --- a/src/plugins/summaryWidget/src/input/Select.js +++ b/src/plugins/summaryWidget/src/input/Select.js @@ -1,13 +1,13 @@ define([ '../eventHelpers', '../../res/input/selectTemplate.html', - 'EventEmitter', - 'zepto' + '../../../../utils/template/templateHelpers', + 'EventEmitter' ], function ( eventHelpers, selectTemplate, - EventEmitter, - $ + templateHelpers, + EventEmitter ) { /** @@ -20,7 +20,8 @@ define([ const self = this; - this.domElement = $(selectTemplate); + this.domElement = templateHelpers.convertTemplateToHTML(selectTemplate)[0]; + this.options = []; this.eventEmitter = new EventEmitter(); this.supportedCallbacks = ['change']; @@ -35,12 +36,12 @@ define([ */ function onChange(event) { const elem = event.target; - const value = self.options[$(elem).prop('selectedIndex')]; + const value = self.options[elem.selectedIndex]; self.eventEmitter.emit('change', value[0]); } - this.listenTo($('select', this.domElement), 'change', onChange, this); + this.listenTo(this.domElement.querySelector('select'), 'change', onChange, this); } /** @@ -74,16 +75,19 @@ define([ const self = this; let selectedIndex = 0; - selectedIndex = $('select', this.domElement).prop('selectedIndex'); - $('option', this.domElement).remove(); + selectedIndex = this.domElement.querySelector('select').selectedIndex; - self.options.forEach(function (option, index) { - $('select', self.domElement) - .append(''); + this.domElement.querySelector('select').innerHTML = ''; + + self.options.forEach(function (option) { + const optionElement = document.createElement('option'); + optionElement.value = option[0]; + optionElement.innerText = `+ ${option[1]}`; + + self.domElement.querySelector('select').appendChild(optionElement); }); - $('select', this.domElement).prop('selectedIndex', selectedIndex); + this.domElement.querySelector('select').selectedIndex = selectedIndex; }; /** @@ -120,7 +124,7 @@ define([ selectedIndex = index; } }); - $('select', this.domElement).prop('selectedIndex', selectedIndex); + this.domElement.querySelector('select').selectedIndex = selectedIndex; selectedOption = this.options[selectedIndex]; this.eventEmitter.emit('change', selectedOption[0]); @@ -131,17 +135,21 @@ define([ * @return {string} */ Select.prototype.getSelected = function () { - return $('select', this.domElement).prop('value'); + return this.domElement.querySelector('select').value; }; Select.prototype.hide = function () { - $(this.domElement).addClass('hidden'); - $('.equal-to').addClass('hidden'); + this.domElement.classList.add('hidden'); + if (this.domElement.querySelector('.equal-to')) { + this.domElement.querySelector('.equal-to').classList.add('hidden'); + } }; Select.prototype.show = function () { - $(this.domElement).removeClass('hidden'); - $('.equal-to').removeClass('hidden'); + this.domElement.classList.remove('hidden'); + if (this.domElement.querySelector('.equal-to')) { + this.domElement.querySelector('.equal-to').classList.remove('hidden'); + } }; Select.prototype.destroy = function () { diff --git a/src/plugins/summaryWidget/test/ConditionSpec.js b/src/plugins/summaryWidget/test/ConditionSpec.js index a69742065b..8b166bf872 100644 --- a/src/plugins/summaryWidget/test/ConditionSpec.js +++ b/src/plugins/summaryWidget/test/ConditionSpec.js @@ -20,7 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -define(['../src/Condition', 'zepto'], function (Condition, $) { +define(['../src/Condition'], function (Condition) { xdescribe('A summary widget condition', function () { let testCondition; let mockConfig; @@ -33,7 +33,7 @@ define(['../src/Condition', 'zepto'], function (Condition, $) { let generateValuesSpy; beforeEach(function () { - mockContainer = $(document.createElement('div')); + mockContainer = document.createElement('div'); mockConfig = { object: 'object1', @@ -78,7 +78,7 @@ define(['../src/Condition', 'zepto'], function (Condition, $) { it('exposes a DOM element to represent itself in the view', function () { mockContainer.append(testCondition.getDOM()); - expect($('.t-condition', mockContainer).get().length).toEqual(1); + expect(mockContainer.querySelectorAll('.t-condition').length).toEqual(1); }); it('responds to a change in its object select', function () { @@ -111,41 +111,59 @@ define(['../src/Condition', 'zepto'], function (Condition, $) { }); it('generates value inputs of the appropriate type and quantity', function () { + let inputs; + mockContainer.append(testCondition.getDOM()); mockEvaluator.getInputType.and.returnValue('number'); mockEvaluator.getInputCount.and.returnValue(3); testCondition.generateValueInputs(''); - expect($('input', mockContainer).filter('[type=number]').get().length).toEqual(3); - expect($('input', mockContainer).eq(0).prop('valueAsNumber')).toEqual(1); - expect($('input', mockContainer).eq(1).prop('valueAsNumber')).toEqual(2); - expect($('input', mockContainer).eq(2).prop('valueAsNumber')).toEqual(3); + + inputs = mockContainer.querySelectorAll('input'); + const numberInputs = Array.from(inputs).filter(input => input.type === 'number'); + + expect(numberInputs.length).toEqual(3); + expect(numberInputs[0].valueAsNumber).toEqual(1); + expect(numberInputs[1].valueAsNumber).toEqual(2); + expect(numberInputs[2].valueAsNumber).toEqual(3); mockEvaluator.getInputType.and.returnValue('text'); mockEvaluator.getInputCount.and.returnValue(2); testCondition.config.values = ['Text I Am', 'Text It Is']; testCondition.generateValueInputs(''); - expect($('input', mockContainer).filter('[type=text]').get().length).toEqual(2); - expect($('input', mockContainer).eq(0).prop('value')).toEqual('Text I Am'); - expect($('input', mockContainer).eq(1).prop('value')).toEqual('Text It Is'); + + inputs = mockContainer.querySelectorAll('input'); + const textInputs = Array.from(inputs).filter(input => input.type === 'text'); + + expect(textInputs.length).toEqual(2); + expect(textInputs[0].value).toEqual('Text I Am'); + expect(textInputs[1].value).toEqual('Text It Is'); }); it('ensures reasonable defaults on values if none are provided', function () { + let inputs; + mockContainer.append(testCondition.getDOM()); mockEvaluator.getInputType.and.returnValue('number'); mockEvaluator.getInputCount.and.returnValue(3); testCondition.config.values = []; testCondition.generateValueInputs(''); - expect($('input', mockContainer).eq(0).prop('valueAsNumber')).toEqual(0); - expect($('input', mockContainer).eq(1).prop('valueAsNumber')).toEqual(0); - expect($('input', mockContainer).eq(2).prop('valueAsNumber')).toEqual(0); + + inputs = Array.from(mockContainer.querySelectorAll('input')); + + expect(inputs[0].valueAsNumber).toEqual(0); + expect(inputs[1].valueAsNumber).toEqual(0); + expect(inputs[2].valueAsNumber).toEqual(0); expect(testCondition.config.values).toEqual([0, 0, 0]); mockEvaluator.getInputType.and.returnValue('text'); mockEvaluator.getInputCount.and.returnValue(2); testCondition.config.values = []; testCondition.generateValueInputs(''); - expect($('input', mockContainer).eq(0).prop('value')).toEqual(''); - expect($('input', mockContainer).eq(1).prop('value')).toEqual(''); + + inputs = Array.from(mockContainer.querySelectorAll('input')); + + expect(inputs[0].value).toEqual(''); + expect(inputs[1].value).toEqual(''); expect(testCondition.config.values).toEqual(['', '']); }); @@ -154,8 +172,16 @@ define(['../src/Condition', 'zepto'], function (Condition, $) { mockEvaluator.getInputType.and.returnValue('number'); mockEvaluator.getInputCount.and.returnValue(3); testCondition.generateValueInputs(''); - $('input', mockContainer).eq(1).prop('value', 9001); - $('input', mockContainer).eq(1).trigger('input'); + + const event = new Event('input', { + bubbles: true, + cancelable: true + }); + const inputs = mockContainer.querySelectorAll('input'); + + inputs[1].value = 9001; + inputs[1].dispatchEvent(event); + expect(changeSpy).toHaveBeenCalledWith({ value: 9001, property: 'values[1]', diff --git a/src/plugins/summaryWidget/test/RuleSpec.js b/src/plugins/summaryWidget/test/RuleSpec.js index 4d6c5b7149..df5108f7ae 100644 --- a/src/plugins/summaryWidget/test/RuleSpec.js +++ b/src/plugins/summaryWidget/test/RuleSpec.js @@ -1,4 +1,4 @@ -define(['../src/Rule', 'zepto'], function (Rule, $) { +define(['../src/Rule'], function (Rule) { describe('A Summary Widget Rule', function () { let mockRuleConfig; let mockDomainObject; @@ -78,7 +78,7 @@ define(['../src/Rule', 'zepto'], function (Rule, $) { 'dragStart' ]); - mockContainer = $(document.createElement('div')); + mockContainer = document.createElement('div'); removeSpy = jasmine.createSpy('removeCallback'); duplicateSpy = jasmine.createSpy('duplicateCallback'); @@ -99,7 +99,7 @@ define(['../src/Rule', 'zepto'], function (Rule, $) { it('gets its DOM element', function () { mockContainer.append(testRule.getDOM()); - expect($('.l-widget-rule', mockContainer).get().length).toBeGreaterThan(0); + expect(mockContainer.querySelectorAll('.l-widget-rule').length).toBeGreaterThan(0); }); it('gets its configuration properties', function () { @@ -185,7 +185,7 @@ define(['../src/Rule', 'zepto'], function (Rule, $) { it('builds condition view from condition configuration', function () { mockContainer.append(testRule.getDOM()); - expect($('.t-condition', mockContainer).get().length).toEqual(2); + expect(mockContainer.querySelectorAll('.t-condition').length).toEqual(2); }); it('responds to input of style properties, and updates the preview', function () { @@ -196,9 +196,9 @@ define(['../src/Rule', 'zepto'], function (Rule, $) { testRule.colorInputs.color.set('#999999'); expect(mockRuleConfig.style.color).toEqual('#999999'); - expect(testRule.thumbnail.css('background-color')).toEqual('rgb(67, 67, 67)'); - expect(testRule.thumbnail.css('border-color')).toEqual('rgb(102, 102, 102)'); - expect(testRule.thumbnail.css('color')).toEqual('rgb(153, 153, 153)'); + expect(testRule.thumbnail.style['background-color']).toEqual('rgb(67, 67, 67)'); + expect(testRule.thumbnail.style['border-color']).toEqual('rgb(102, 102, 102)'); + expect(testRule.thumbnail.style.color).toEqual('rgb(153, 153, 153)'); expect(changeSpy).toHaveBeenCalled(); }); @@ -228,8 +228,12 @@ define(['../src/Rule', 'zepto'], function (Rule, $) { // }); it('allows input for when the rule triggers', function () { - testRule.trigger.prop('value', 'all'); - testRule.trigger.trigger('change'); + testRule.trigger.value = 'all'; + const event = new Event('change', { + bubbles: true, + cancelable: true + }); + testRule.trigger.dispatchEvent(event); expect(testRule.config.trigger).toEqual('all'); expect(conditionChangeSpy).toHaveBeenCalled(); }); @@ -247,7 +251,12 @@ define(['../src/Rule', 'zepto'], function (Rule, $) { }); it('initiates a drag event when its grippy is clicked', function () { - testRule.grippy.trigger('mousedown'); + const event = new Event('mousedown', { + bubbles: true, + cancelable: true + }); + testRule.grippy.dispatchEvent(event); + expect(mockWidgetDnD.setDragImage).toHaveBeenCalled(); expect(mockWidgetDnD.dragStart).toHaveBeenCalledWith('mockRule'); }); diff --git a/src/plugins/summaryWidget/test/SummaryWidgetSpec.js b/src/plugins/summaryWidget/test/SummaryWidgetSpec.js index 1bee993e2d..877b1b366d 100644 --- a/src/plugins/summaryWidget/test/SummaryWidgetSpec.js +++ b/src/plugins/summaryWidget/test/SummaryWidgetSpec.js @@ -20,7 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -define(['../src/SummaryWidget', 'zepto'], function (SummaryWidget, $) { +define(['../src/SummaryWidget'], function (SummaryWidget) { xdescribe('The Summary Widget', function () { let summaryWidget; let mockDomainObject; @@ -111,7 +111,7 @@ define(['../src/SummaryWidget', 'zepto'], function (SummaryWidget, $) { }); it('builds rules and rule placeholders in view from configuration', function () { - expect($('.l-widget-rule', summaryWidget.ruleArea).get().length).toEqual(2); + expect(summaryWidget.ruleArea.querySelectorAll('.l-widget-rule').length).toEqual(2); }); it('allows initializing a new rule with a particular identifier', function () { @@ -130,7 +130,7 @@ define(['../src/SummaryWidget', 'zepto'], function (SummaryWidget, $) { mockDomainObject.configuration.ruleOrder.forEach(function (ruleId) { expect(mockDomainObject.configuration.ruleConfigById[ruleId]).toBeDefined(); }); - expect($('.l-widget-rule', summaryWidget.ruleArea).get().length).toEqual(6); + expect(summaryWidget.ruleArea.querySelectorAll('.l-widget-rule').length).toEqual(6); }); it('allows duplicating a rule from source configuration', function () { @@ -186,10 +186,10 @@ define(['../src/SummaryWidget', 'zepto'], function (SummaryWidget, $) { it('adds hyperlink to the widget button and sets newTab preference', function () { summaryWidget.addHyperlink('https://www.nasa.gov', 'newTab'); - const widgetButton = $('#widget', mockContainer); + const widgetButton = mockContainer.querySelector('#widget'); - expect(widgetButton.attr('href')).toEqual('https://www.nasa.gov'); - expect(widgetButton.attr('target')).toEqual('_blank'); + expect(widgetButton.href).toEqual('https://www.nasa.gov/'); + expect(widgetButton.target).toEqual('_blank'); }); }); }); diff --git a/src/plugins/summaryWidget/test/TestDataItemSpec.js b/src/plugins/summaryWidget/test/TestDataItemSpec.js index dffa6c6f22..171753efe4 100644 --- a/src/plugins/summaryWidget/test/TestDataItemSpec.js +++ b/src/plugins/summaryWidget/test/TestDataItemSpec.js @@ -1,4 +1,4 @@ -define(['../src/TestDataItem', 'zepto'], function (TestDataItem, $) { +define(['../src/TestDataItem'], function (TestDataItem) { describe('A summary widget test data item', function () { let testDataItem; let mockConfig; @@ -11,7 +11,7 @@ define(['../src/TestDataItem', 'zepto'], function (TestDataItem, $) { let generateValueSpy; beforeEach(function () { - mockContainer = $(document.createElement('div')); + mockContainer = document.createElement('div'); mockConfig = { object: 'object1', @@ -56,7 +56,7 @@ define(['../src/TestDataItem', 'zepto'], function (TestDataItem, $) { it('exposes a DOM element to represent itself in the view', function () { mockContainer.append(testDataItem.getDOM()); - expect($('.t-test-data-item', mockContainer).get().length).toEqual(1); + expect(mockContainer.querySelectorAll('.t-test-data-item').length).toEqual(1); }); it('responds to a change in its object select', function () { @@ -80,34 +80,54 @@ define(['../src/TestDataItem', 'zepto'], function (TestDataItem, $) { }); it('generates a value input of the appropriate type', function () { + let inputs; + mockContainer.append(testDataItem.getDOM()); mockEvaluator.getInputTypeById.and.returnValue('number'); testDataItem.generateValueInput(''); - expect($('input', mockContainer).filter('[type=number]').get().length).toEqual(1); - expect($('input', mockContainer).prop('valueAsNumber')).toEqual(1); + + inputs = mockContainer.querySelectorAll('input'); + const numberInputs = Array.from(inputs).filter(input => input.type === 'number'); + + expect(numberInputs.length).toEqual(1); + expect(inputs[0].valueAsNumber).toEqual(1); mockEvaluator.getInputTypeById.and.returnValue('text'); testDataItem.config.value = 'Text I Am'; testDataItem.generateValueInput(''); - expect($('input', mockContainer).filter('[type=text]').get().length).toEqual(1); - expect($('input', mockContainer).prop('value')).toEqual('Text I Am'); + + inputs = mockContainer.querySelectorAll('input'); + const textInputs = Array.from(inputs).filter(input => input.type === 'text'); + + expect(textInputs.length).toEqual(1); + expect(inputs[0].value).toEqual('Text I Am'); }); it('ensures reasonable defaults on values if none are provided', function () { + let inputs; + mockContainer.append(testDataItem.getDOM()); mockEvaluator.getInputTypeById.and.returnValue('number'); testDataItem.config.value = undefined; testDataItem.generateValueInput(''); - expect($('input', mockContainer).filter('[type=number]').get().length).toEqual(1); - expect($('input', mockContainer).prop('valueAsNumber')).toEqual(0); + + inputs = mockContainer.querySelectorAll('input'); + const numberInputs = Array.from(inputs).filter(input => input.type === 'number'); + + expect(numberInputs.length).toEqual(1); + expect(inputs[0].valueAsNumber).toEqual(0); expect(testDataItem.config.value).toEqual(0); mockEvaluator.getInputTypeById.and.returnValue('text'); testDataItem.config.value = undefined; testDataItem.generateValueInput(''); - expect($('input', mockContainer).filter('[type=text]').get().length).toEqual(1); - expect($('input', mockContainer).prop('value')).toEqual(''); + + inputs = mockContainer.querySelectorAll('input'); + const textInputs = Array.from(inputs).filter(input => input.type === 'text'); + + expect(textInputs.length).toEqual(1); + expect(inputs[0].value).toEqual(''); expect(testDataItem.config.value).toEqual(''); }); @@ -115,8 +135,15 @@ define(['../src/TestDataItem', 'zepto'], function (TestDataItem, $) { mockContainer.append(testDataItem.getDOM()); mockEvaluator.getInputTypeById.and.returnValue('number'); testDataItem.generateValueInput(''); - $('input', mockContainer).prop('value', 9001); - $('input', mockContainer).trigger('input'); + + const event = new Event('input', { + bubbles: true, + cancelable: true + }); + + mockContainer.querySelector('input').value = 9001; + mockContainer.querySelector('input').dispatchEvent(event); + expect(changeSpy).toHaveBeenCalledWith({ value: 9001, property: 'value', diff --git a/src/plugins/summaryWidget/test/TestDataManagerSpec.js b/src/plugins/summaryWidget/test/TestDataManagerSpec.js index 70042250d3..59ce37d92c 100644 --- a/src/plugins/summaryWidget/test/TestDataManagerSpec.js +++ b/src/plugins/summaryWidget/test/TestDataManagerSpec.js @@ -1,4 +1,4 @@ -define(['../src/TestDataManager', 'zepto'], function (TestDataManager, $) { +define(['../src/TestDataManager'], function (TestDataManager) { describe('A Summary Widget Rule', function () { let mockDomainObject; let mockOpenMCT; @@ -103,7 +103,7 @@ define(['../src/TestDataManager', 'zepto'], function (TestDataManager, $) { mockConditionManager.getObjectName.and.returnValue('Object Name'); mockConditionManager.getTelemetryPropertyName.and.returnValue('Property Name'); - mockContainer = $(document.createElement('div')); + mockContainer = document.createElement('div'); testDataManager = new TestDataManager(mockDomainObject, mockConditionManager, mockOpenMCT); }); @@ -114,7 +114,7 @@ define(['../src/TestDataManager', 'zepto'], function (TestDataManager, $) { it('exposes a DOM element to represent itself in the view', function () { mockContainer.append(testDataManager.getDOM()); - expect($('.t-widget-test-data-content', mockContainer).get().length).toBeGreaterThan(0); + expect(mockContainer.querySelectorAll('.t-widget-test-data-content').length).toBeGreaterThan(0); }); it('generates a test cache in the format expected by a condition evaluator', function () { @@ -207,7 +207,7 @@ define(['../src/TestDataManager', 'zepto'], function (TestDataManager, $) { it('builds item view from item configuration', function () { mockContainer.append(testDataManager.getDOM()); - expect($('.t-test-data-item', mockContainer).get().length).toEqual(3); + expect(mockContainer.querySelectorAll('.t-test-data-item').length).toEqual(3); }); it('can remove a item from its configuration', function () { diff --git a/src/utils/template/templateHelpers.js b/src/utils/template/templateHelpers.js new file mode 100644 index 0000000000..70d381ce7d --- /dev/null +++ b/src/utils/template/templateHelpers.js @@ -0,0 +1,14 @@ +export function convertTemplateToHTML(templateString) { + const template = document.createElement('template'); + template.innerHTML = templateString; + + return template.content.cloneNode(true).children; +} + +export function toggleClass(element, className) { + if (element.classList.contains(className)) { + element.classList.remove(className); + } else { + element.classList.add(className); + } +} diff --git a/webpack.common.js b/webpack.common.js index 5b1de5da4f..20f9705f48 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -101,13 +101,6 @@ const config = { test: /\.html$/, type: 'asset/source' }, - { - test: /zepto/, - use: [ - "imports-loader?this=>window", - "exports-loader?Zepto" - ] - }, { test: /\.(jpg|jpeg|png|svg)$/, type: 'asset/resource', From 40a74510648761fc6e82b0ed60aebb774f175041 Mon Sep 17 00:00:00 2001 From: Shefali Joshi Date: Fri, 3 Jun 2022 09:46:27 -0700 Subject: [PATCH 042/161] Fix stackplots static style (#5045) * [4864] Fixes cancelling edit properties console error * Get the style receiver when the styleRuleManager is initialized. This prevents any ambiguity about which element should receive the style * Don't subscribe if the styleRuleManager has been destroyed Co-authored-by: John Hill Co-authored-by: Jamie V Co-authored-by: Nikhil Co-authored-by: Andrew Henry --- .circleci/config.yml | 10 +++++----- src/plugins/condition/StyleRuleManager.js | 6 ++++-- src/plugins/formActions/EditPropertiesAction.js | 10 +++++++++- src/plugins/formActions/pluginSpec.js | 7 +++++++ 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3268c660a6..8863b9e057 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,7 +31,7 @@ commands: type: string steps: - when: - condition: + condition: equal: [false, << pipeline.parameters.BUST_CACHE >> ] steps: - restore_cache: @@ -41,7 +41,7 @@ commands: parameters: node-version: type: string - steps: + steps: - save_cache: key: deps-{{ .Branch }}--<< parameters.node-version >>--{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }} paths: @@ -61,7 +61,7 @@ commands: upload_code_covio: description: "Command to upload code coverage reports to codecov.io" steps: - - run: curl -Os https://uploader.codecov.io/latest/linux/codecov;chmod +x codecov;./codecov + - run: curl -Os https://uploader.codecov.io/latest/linux/codecov;chmod +x codecov;./codecov orbs: node: circleci/node@4.9.0 browser-tools: circleci/browser-tools@1.3.0 @@ -101,7 +101,7 @@ jobs: equal: [ "FirefoxESR", <> ] steps: - browser-tools/install-firefox: - version: "91.7.1esr" #https://archive.mozilla.org/pub/firefox/releases/ + version: "91.7.1esr" #https://archive.mozilla.org/pub/firefox/releases/ - when: condition: equal: [ "FirefoxHeadless", <> ] @@ -158,7 +158,7 @@ workflows: - lint: name: node16-lint node-version: lts/gallium - - unit-test: + - unit-test: name: node14-chrome node-version: lts/fermium browser: ChromeHeadless diff --git a/src/plugins/condition/StyleRuleManager.js b/src/plugins/condition/StyleRuleManager.js index e7f201ca7e..18063b337c 100644 --- a/src/plugins/condition/StyleRuleManager.js +++ b/src/plugins/condition/StyleRuleManager.js @@ -78,11 +78,13 @@ export default class StyleRuleManager extends EventEmitter { this.openmct.objects.get(this.conditionSetIdentifier).then((conditionSetDomainObject) => { this.openmct.telemetry.request(conditionSetDomainObject) .then(output => { - if (output && output.length) { + if (output && output.length && (this.conditionSetIdentifier && this.openmct.objects.areIdsEqual(conditionSetDomainObject.identifier, this.conditionSetIdentifier))) { this.handleConditionSetResultUpdated(output[0]); } }); - this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(conditionSetDomainObject, this.handleConditionSetResultUpdated.bind(this)); + if (this.conditionSetIdentifier && this.openmct.objects.areIdsEqual(conditionSetDomainObject.identifier, this.conditionSetIdentifier)) { + this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(conditionSetDomainObject, this.handleConditionSetResultUpdated.bind(this)); + } }); } diff --git a/src/plugins/formActions/EditPropertiesAction.js b/src/plugins/formActions/EditPropertiesAction.js index 53afadfe90..65ceaaadd1 100644 --- a/src/plugins/formActions/EditPropertiesAction.js +++ b/src/plugins/formActions/EditPropertiesAction.js @@ -76,6 +76,13 @@ export default class EditPropertiesAction extends PropertiesAction { } } + /** + * @private + */ + _onCancel() { + //noop + } + /** * @private */ @@ -87,6 +94,7 @@ export default class EditPropertiesAction extends PropertiesAction { formStructure.title = 'Edit ' + this.domainObject.name; return this.openmct.forms.showForm(formStructure) - .then(this._onSave.bind(this)); + .then(this._onSave.bind(this)) + .catch(this._onCancel.bind(this)); } } diff --git a/src/plugins/formActions/pluginSpec.js b/src/plugins/formActions/pluginSpec.js index 9c4cbb2cc0..232ff0d303 100644 --- a/src/plugins/formActions/pluginSpec.js +++ b/src/plugins/formActions/pluginSpec.js @@ -123,6 +123,9 @@ describe('EditPropertiesAction plugin', () => { } editPropertiesAction.invoke([domainObject]) + .then(() => { + done(); + }) .catch(() => { done(); }); @@ -208,6 +211,10 @@ describe('EditPropertiesAction plugin', () => { }; editPropertiesAction.invoke([domainObject]) + .then(() => { + expect(domainObject.name).toEqual(name); + done(); + }) .catch(() => { expect(domainObject.name).toEqual(name); From 1c525f50c88cb662699811c620e59ee285b67abd Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Fri, 3 Jun 2022 09:53:21 -0700 Subject: [PATCH 043/161] Display Layout toolbar refinements for units (#5197) * Fixes #3197 - Moved position of hide/show units toggle button. - Added labels to many toolbar buttons, including hide/show units, hide/show frame, edit text, more. - Added label to toolbar-toggle-button.vue. - Added separator between stackOrder button and position inputs. * Fixes #3197 - Removed unwanted margin in alphanumerics when label is hidden. Co-authored-by: Shefali Joshi --- .../displayLayout/DisplayLayoutToolbar.js | 40 ++++++++++++------- .../components/telemetry-view.scss | 8 ++-- src/plugins/displayLayout/pluginSpec.js | 2 +- .../components/toolbar-toggle-button.vue | 12 ++++-- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/plugins/displayLayout/DisplayLayoutToolbar.js b/src/plugins/displayLayout/DisplayLayoutToolbar.js index 24038b8555..5bcf3ee45d 100644 --- a/src/plugins/displayLayout/DisplayLayoutToolbar.js +++ b/src/plugins/displayLayout/DisplayLayoutToolbar.js @@ -211,13 +211,15 @@ define(['lodash'], function (_) { options: [ { value: false, - icon: 'icon-frame-show', - title: "Frame visible" + icon: 'icon-frame-hide', + title: "Frame visible", + label: 'Hide frame' }, { value: true, - icon: 'icon-frame-hide', - title: "Frame hidden" + icon: 'icon-frame-show', + title: "Frame hidden", + label: 'Show frame' } ] }; @@ -401,6 +403,7 @@ define(['lodash'], function (_) { }, icon: "icon-pencil", title: "Edit text properties", + label: "Edit text", dialog: DIALOG_FORM.text }; } @@ -514,12 +517,14 @@ define(['lodash'], function (_) { { value: true, icon: 'icon-eye-open', - title: "Show units" + title: "Show units", + label: "Show units" }, { value: false, icon: 'icon-eye-disabled', - title: "Hide units" + title: "Hide units", + label: "Hide units" } ] }; @@ -562,6 +567,7 @@ define(['lodash'], function (_) { domainObject: selectedParent, icon: "icon-object", title: "Switch the way this telemetry is displayed", + label: "View type", options: viewOptions, method: function (option) { displayLayoutContext.switchViewType(selectedItemContext, option.value, selection); @@ -662,9 +668,9 @@ define(['lodash'], function (_) { 'display-mode': [], 'telemetry-value': [], 'style': [], + 'unit-toggle': [], 'position': [], 'duplicate': [], - 'unit-toggle': [], 'remove': [], 'toggle-grid': [] }; @@ -689,6 +695,7 @@ define(['lodash'], function (_) { if (toolbar.position.length === 0) { toolbar.position = [ getStackOrder(selectedParent, selectionPath), + getSeparator(), getXInput(selectedParent, selectedObjects), getYInput(selectedParent, selectedObjects), getHeightInput(selectedParent, selectedObjects), @@ -712,9 +719,17 @@ define(['lodash'], function (_) { toolbar['telemetry-value'] = [getTelemetryValueMenu(selectionPath, selectedObjects)]; } + if (toolbar['unit-toggle'].length === 0) { + let toggleUnitsButton = getToggleUnitsButton(selectedParent, selectedObjects); + if (toggleUnitsButton) { + toolbar['unit-toggle'] = [toggleUnitsButton]; + } + } + if (toolbar.position.length === 0) { toolbar.position = [ getStackOrder(selectedParent, selectionPath), + getSeparator(), getXInput(selectedParent, selectedObjects), getYInput(selectedParent, selectedObjects), getHeightInput(selectedParent, selectedObjects), @@ -729,17 +744,11 @@ define(['lodash'], function (_) { if (toolbar.viewSwitcher.length === 0) { toolbar.viewSwitcher = [getViewSwitcherMenu(selectedParent, selectionPath, selectedObjects)]; } - - if (toolbar['unit-toggle'].length === 0) { - let toggleUnitsButton = getToggleUnitsButton(selectedParent, selectedObjects); - if (toggleUnitsButton) { - toolbar['unit-toggle'] = [toggleUnitsButton]; - } - } } else if (layoutItem.type === 'text-view') { if (toolbar.position.length === 0) { toolbar.position = [ getStackOrder(selectedParent, selectionPath), + getSeparator(), getXInput(selectedParent, selectedObjects), getYInput(selectedParent, selectedObjects), getHeightInput(selectedParent, selectedObjects), @@ -758,6 +767,7 @@ define(['lodash'], function (_) { if (toolbar.position.length === 0) { toolbar.position = [ getStackOrder(selectedParent, selectionPath), + getSeparator(), getXInput(selectedParent, selectedObjects), getYInput(selectedParent, selectedObjects), getHeightInput(selectedParent, selectedObjects), @@ -772,6 +782,7 @@ define(['lodash'], function (_) { if (toolbar.position.length === 0) { toolbar.position = [ getStackOrder(selectedParent, selectionPath), + getSeparator(), getXInput(selectedParent, selectedObjects), getYInput(selectedParent, selectedObjects), getHeightInput(selectedParent, selectedObjects), @@ -786,6 +797,7 @@ define(['lodash'], function (_) { if (toolbar.position.length === 0) { toolbar.position = [ getStackOrder(selectedParent, selectionPath), + getSeparator(), getXInput(selectedParent, selectedObjects), getYInput(selectedParent, selectedObjects), getX2Input(selectedParent, selectedObjects), diff --git a/src/plugins/displayLayout/components/telemetry-view.scss b/src/plugins/displayLayout/components/telemetry-view.scss index 0dbfc75ac6..8b73d118a0 100644 --- a/src/plugins/displayLayout/components/telemetry-view.scss +++ b/src/plugins/displayLayout/components/telemetry-view.scss @@ -17,14 +17,14 @@ } } - > * + * { - margin-left: $interiorMargin; - } - &__value { @include isLimit(); } + &__label { + margin-right: $interiorMargin; + } + .c-frame & { @include abs(); border: 1px solid transparent; diff --git a/src/plugins/displayLayout/pluginSpec.js b/src/plugins/displayLayout/pluginSpec.js index 643f13be6e..a1ac3764a6 100644 --- a/src/plugins/displayLayout/pluginSpec.js +++ b/src/plugins/displayLayout/pluginSpec.js @@ -351,7 +351,7 @@ describe('the plugin', function () { it('provides controls including separators', () => { const displayLayoutToolbar = openmct.toolbars.get(selection); - expect(displayLayoutToolbar.length).toBe(7); + expect(displayLayoutToolbar.length).toBe(8); }); }); }); diff --git a/src/ui/toolbar/components/toolbar-toggle-button.vue b/src/ui/toolbar/components/toolbar-toggle-button.vue index e3d37c4c5f..27ca3d62f0 100644 --- a/src/ui/toolbar/components/toolbar-toggle-button.vue +++ b/src/ui/toolbar/components/toolbar-toggle-button.vue @@ -5,9 +5,15 @@ :title="nextValue.title" :class="[nextValue.icon, {'c-icon-button--mixed': nonSpecific}]" @click="cycle" - >
-
- + > +
+ {{ nextValue.label }} +
+ + diff --git a/src/ui/components/tags/TagEditor.vue b/src/ui/components/tags/TagEditor.vue new file mode 100644 index 0000000000..65d9ace133 --- /dev/null +++ b/src/ui/components/tags/TagEditor.vue @@ -0,0 +1,155 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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. + *****************************************************************************/ + + + + diff --git a/src/ui/components/tags/TagSelection.vue b/src/ui/components/tags/TagSelection.vue new file mode 100644 index 0000000000..3163ae0456 --- /dev/null +++ b/src/ui/components/tags/TagSelection.vue @@ -0,0 +1,152 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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. + *****************************************************************************/ + + + + diff --git a/src/ui/components/tags/tags.scss b/src/ui/components/tags/tags.scss new file mode 100644 index 0000000000..ebd3e7a184 --- /dev/null +++ b/src/ui/components/tags/tags.scss @@ -0,0 +1,67 @@ +/******************************* TAGS */ +.c-tag { + border-radius: 10px; //TODO: convert to theme constant + display: inline-flex; + padding: 1px 10px; //TODO: convert to theme constant + + > * + * { + margin-left: $interiorMargin; + } + + &__remove-btn { + color: inherit !important; + display: none; + opacity: 0; + overflow: hidden; + padding: 1px !important; + transition: $transIn; + width: 0; + + &:hover { + opacity: 1; + } + } + + /* SEARCH RESULTS */ + &.--is-not-search-match { + opacity: 0.5; + } +} + +/******************************* TAG EDITOR */ +.c-tag-applier { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + + > * + * { + margin-left: $interiorMargin; + } + + &__add-btn { + &:before { font-size: 0.9em; } + } + + .c-tag { + flex-direction: row; + align-items: center; + padding-right: 3px !important; + + &__remove-btn { + display: block; + } + } +} + +/******************************* HOVERS */ +.has-tag-applier { + // Apply this class to all components that should trigger tag removal btn on hover + &:hover { + .c-tag__remove-btn { + width: 1.1em; + opacity: 0.7; + transition: $transOut; + } + } + } diff --git a/src/ui/layout/Layout.vue b/src/ui/layout/Layout.vue index 2ded6498d6..ee52964363 100644 --- a/src/ui/layout/Layout.vue +++ b/src/ui/layout/Layout.vue @@ -18,6 +18,9 @@ }" > + + + + + + diff --git a/src/ui/layout/search/GrandSearch.vue b/src/ui/layout/search/GrandSearch.vue new file mode 100644 index 0000000000..788ae1e589 --- /dev/null +++ b/src/ui/layout/search/GrandSearch.vue @@ -0,0 +1,145 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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. + *****************************************************************************/ + + + + diff --git a/src/ui/layout/search/ObjectSearchResult.vue b/src/ui/layout/search/ObjectSearchResult.vue new file mode 100644 index 0000000000..2e3416a8ee --- /dev/null +++ b/src/ui/layout/search/ObjectSearchResult.vue @@ -0,0 +1,102 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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. + *****************************************************************************/ + + + + diff --git a/src/ui/layout/search/SearchResultsDropDown.vue b/src/ui/layout/search/SearchResultsDropDown.vue new file mode 100644 index 0000000000..21e1487cb8 --- /dev/null +++ b/src/ui/layout/search/SearchResultsDropDown.vue @@ -0,0 +1,99 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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. + *****************************************************************************/ + + + + diff --git a/src/ui/layout/search/search.scss b/src/ui/layout/search/search.scss new file mode 100644 index 0000000000..fe3e3513db --- /dev/null +++ b/src/ui/layout/search/search.scss @@ -0,0 +1,137 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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. + *****************************************************************************/ + +/******************************* EXPANDED SEARCH 2022 */ +.c-gsearch { + .l-shell__head & { + // Search input in the shell head + width: 20%; + + .c-search { + background: rgba($colorHeadFg, 0.2); + box-shadow: none; + } + } + + &__results-wrapper { + @include menuOuter(); + display: flex; + flex-direction: column; + padding: $interiorMarginLg; + min-width: 500px; + max-height: 500px; + } + + &__results, + &__results-section { + flex: 1 1 auto; + } + + &__results { + // Holds n __results-sections + padding-right: $interiorMargin; // Fend off scrollbar + overflow-y: auto; + + > * + * { + margin-top: $interiorMarginLg; + } + } + + &__results-section { + > * + * { + margin-top: $interiorMarginSm; + } + } + + &__results-section-title { + @include propertiesHeader(); + } +} + +.c-gsearch-result { + display: flex; + padding: $interiorMargin $interiorMarginSm; + + > * + * { + margin-left: $interiorMarginLg; + } + + + .c-gsearch-result { + border-top: 1px solid $colorInteriorBorder; + } + + &__type-icon, + &__more-options-button { + flex: 0 0 auto; + } + + &__type-icon { + color: $colorItemTreeIcon; + font-size: 2.2em; + + // TEMP: uses object-label component, hide label part + .c-object-label__name { + display: none; + } + } + + &__more-options-button { + display: none; // TEMP until enabled + } + + &__body { + flex: 1 1 auto; + + > * + * { + margin-top: $interiorMarginSm; + } + + .c-location { + font-size: 0.9em; + opacity: 0.8; + } + } + + &__tags { + display: flex; + + > * + * { + margin-left: $interiorMargin; + } + } + + &__title { + border-radius: $basicCr; + color: pullForward($colorBodyFg, 30%); + cursor: pointer; + font-size: 1.15em; + padding: 3px $interiorMarginSm; + + &:hover { + background-color: $colorItemTreeHoverBg; + } + } + + .c-tag { + font-size: 0.9em; + } +} diff --git a/src/ui/mixins/context-menu-gesture.js b/src/ui/mixins/context-menu-gesture.js index 404015f383..ad7fa0de31 100644 --- a/src/ui/mixins/context-menu-gesture.js +++ b/src/ui/mixins/context-menu-gesture.js @@ -33,6 +33,10 @@ export default { }, methods: { showContextMenu(event) { + if (this.readOnly) { + return; + } + event.preventDefault(); event.stopPropagation(); diff --git a/src/ui/router/Browse.js b/src/ui/router/Browse.js index 05106815ae..1c8f622457 100644 --- a/src/ui/router/Browse.js +++ b/src/ui/router/Browse.js @@ -133,9 +133,7 @@ define([ composition.load() .then(children => { let lastChild = children[children.length - 1]; - if (!lastChild) { - console.debug('Unable to navigate to anything. No root objects found.'); - } else { + if (lastChild) { let lastChildId = openmct.objects.makeKeyString(lastChild.identifier); openmct.router.setPath(`#/browse/${lastChildId}`); } From 59c0da1b5753fc1fd1630d42a401c4de822131eb Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Fri, 3 Jun 2022 14:34:03 -0700 Subject: [PATCH 050/161] Add units to Gauges (#5196) * Fixes #3197 - Code and styling to allow units display. Co-authored-by: Shefali Joshi Co-authored-by: Nikhil Co-authored-by: Andrew Henry --- src/plugins/gauge/GaugePlugin.js | 46 ++++++++++++------- src/plugins/gauge/GaugePluginSpec.js | 38 ++++++++------- src/plugins/gauge/components/Gauge.vue | 38 +++++++++++++-- .../gauge/components/GaugeFormController.vue | 2 + src/plugins/gauge/gauge.scss | 12 ++--- 5 files changed, 94 insertions(+), 42 deletions(-) diff --git a/src/plugins/gauge/GaugePlugin.js b/src/plugins/gauge/GaugePlugin.js index c9db912df1..441e53cd57 100644 --- a/src/plugins/gauge/GaugePlugin.js +++ b/src/plugins/gauge/GaugePlugin.js @@ -49,6 +49,7 @@ export default function () { gaugeType: GAUGE_TYPES[0][1], isDisplayMinMax: true, isDisplayCurVal: true, + isDisplayUnits: true, isUseTelemetryLimits: true, limitLow: 10, limitHigh: 90, @@ -59,6 +60,23 @@ export default function () { }; }, form: [ + { + name: "Gauge type", + options: GAUGE_TYPES.map(type => { + return { + name: type[0], + value: type[1] + }; + }), + control: "select", + cssClass: "l-input-sm", + key: "gaugeController", + property: [ + "configuration", + "gaugeController", + "gaugeType" + ] + }, { name: "Display current value", control: "toggleSwitch", @@ -70,6 +88,17 @@ export default function () { "isDisplayCurVal" ] }, + { + name: "Display units", + control: "toggleSwitch", + cssClass: "l-input", + key: "isDisplayUnits", + property: [ + "configuration", + "gaugeController", + "isDisplayUnits" + ] + }, { name: "Display range values", control: "toggleSwitch", @@ -92,23 +121,6 @@ export default function () { "precision" ] }, - { - name: "Gauge type", - options: GAUGE_TYPES.map(type => { - return { - name: type[0], - value: type[1] - }; - }), - control: "select", - cssClass: "l-input-sm", - key: "gaugeController", - property: [ - "configuration", - "gaugeController", - "gaugeType" - ] - }, { name: "Value ranges and limits", control: "gauge-controller", diff --git a/src/plugins/gauge/GaugePluginSpec.js b/src/plugins/gauge/GaugePluginSpec.js index 5894498063..0c6b3d7a1f 100644 --- a/src/plugins/gauge/GaugePluginSpec.js +++ b/src/plugins/gauge/GaugePluginSpec.js @@ -63,30 +63,30 @@ describe('Gauge plugin', () => { }); it('Plugin installed by default', () => { - const gaugueType = openmct.types.get('gauge'); + const GaugeType = openmct.types.get('gauge'); - expect(gaugueType).not.toBeNull(); - expect(gaugueType.definition.name).toEqual('Gauge'); + expect(GaugeType).not.toBeNull(); + expect(GaugeType.definition.name).toEqual('Gauge'); }); - it('Gaugue plugin is creatable', () => { - const gaugueType = openmct.types.get('gauge'); + it('Gauge plugin is creatable', () => { + const GaugeType = openmct.types.get('gauge'); - expect(gaugueType.definition.creatable).toBeTrue(); + expect(GaugeType.definition.creatable).toBeTrue(); }); - it('Gaugue plugin is creatable', () => { - const gaugueType = openmct.types.get('gauge'); + it('Gauge plugin is creatable', () => { + const GaugeType = openmct.types.get('gauge'); - expect(gaugueType.definition.creatable).toBeTrue(); + expect(GaugeType.definition.creatable).toBeTrue(); }); - it('Gaugue form controller', () => { + it('Gauge form controller', () => { const gaugeController = openmct.forms.getFormControl('gauge-controller'); expect(gaugeController).toBeDefined(); }); - describe('Gaugue with Filled Dial', () => { + describe('Gauge with Filled Dial', () => { let gaugeViewProvider; let gaugeView; let gaugeViewObject; @@ -105,6 +105,7 @@ describe('Gauge plugin', () => { gaugeType: 'dial-filled', isDisplayMinMax: true, isDisplayCurVal: true, + isDisplayUnits: true, isUseTelemetryLimits: false, limitLow: -0.9, limitHigh: 0.9, @@ -222,7 +223,7 @@ describe('Gauge plugin', () => { }); }); - describe('Gaugue with Needle Dial', () => { + describe('Gauge with Needle Dial', () => { let gaugeViewProvider; let gaugeView; let gaugeViewObject; @@ -240,6 +241,7 @@ describe('Gauge plugin', () => { gaugeType: 'dial-needle', isDisplayMinMax: true, isDisplayCurVal: true, + isDisplayUnits: true, isUseTelemetryLimits: false, limitLow: -0.9, limitHigh: 0.9, @@ -357,7 +359,7 @@ describe('Gauge plugin', () => { }); }); - describe('Gaugue with Vertical Meter', () => { + describe('Gauge with Vertical Meter', () => { let gaugeViewProvider; let gaugeView; let gaugeViewObject; @@ -375,6 +377,7 @@ describe('Gauge plugin', () => { gaugeType: 'meter-vertical', isDisplayMinMax: true, isDisplayCurVal: true, + isDisplayUnits: true, isUseTelemetryLimits: false, limitLow: -0.9, limitHigh: 0.9, @@ -492,7 +495,7 @@ describe('Gauge plugin', () => { }); }); - describe('Gaugue with Vertical Meter Inverted', () => { + describe('Gauge with Vertical Meter Inverted', () => { let gaugeViewProvider; let gaugeView; let gaugeViewObject; @@ -506,6 +509,7 @@ describe('Gauge plugin', () => { gaugeType: 'meter-vertical', isDisplayMinMax: true, isDisplayCurVal: true, + isDisplayUnits: true, isUseTelemetryLimits: false, limitLow: -0.9, limitHigh: 0.9, @@ -574,7 +578,7 @@ describe('Gauge plugin', () => { }); }); - describe('Gaugue with Horizontal Meter', () => { + describe('Gauge with Horizontal Meter', () => { let gaugeViewProvider; let gaugeView; let gaugeViewObject; @@ -588,6 +592,7 @@ describe('Gauge plugin', () => { gaugeType: 'meter-vertical', isDisplayMinMax: true, isDisplayCurVal: true, + isDisplayUnits: true, isUseTelemetryLimits: false, limitLow: -0.9, limitHigh: 0.9, @@ -656,7 +661,7 @@ describe('Gauge plugin', () => { }); }); - describe('Gaugue with Filled Dial with Use Telemetry Limits', () => { + describe('Gauge with Filled Dial with Use Telemetry Limits', () => { let gaugeViewProvider; let gaugeView; let gaugeViewObject; @@ -673,6 +678,7 @@ describe('Gauge plugin', () => { gaugeType: 'dial-filled', isDisplayMinMax: true, isDisplayCurVal: true, + isDisplayUnits: true, isUseTelemetryLimits: true, limitLow: 10, limitHigh: 90, diff --git a/src/plugins/gauge/components/Gauge.vue b/src/plugins/gauge/components/Gauge.vue index 19fa4a8218..5c1ed0f503 100644 --- a/src/plugins/gauge/components/Gauge.vue +++ b/src/plugins/gauge/components/Gauge.vue @@ -64,11 +64,11 @@ @@ -79,6 +79,17 @@ style="transform: translate(50%, 70%)" >{{ curVal }} + + {{ units }} + {{ curVal }} + > + {{ curVal }} + {{ units }} + + {{ units }} @@ -288,12 +315,15 @@ export default { precision: gaugeController.precision, displayMinMax: gaugeController.isDisplayMinMax, displayCurVal: gaugeController.isDisplayCurVal, + displayUnits: gaugeController.isDisplayUnits, limitHigh: gaugeController.limitHigh, limitLow: gaugeController.limitLow, rangeHigh: gaugeController.max, rangeLow: gaugeController.min, gaugeType: gaugeController.gaugeType, - activeTimeSystem: this.openmct.time.timeSystem() + showUnits: gaugeController.showUnits, + activeTimeSystem: this.openmct.time.timeSystem(), + units: '' }; }, computed: { @@ -524,6 +554,8 @@ export default { const length = values.length; this.updateValue(values[length - 1]); }); + + this.units = this.metadata.value(this.valueKey).unit || ''; }, round(val, decimals = this.precision) { let precision = Math.pow(10, decimals); diff --git a/src/plugins/gauge/components/GaugeFormController.vue b/src/plugins/gauge/components/GaugeFormController.vue index ea80457880..648e0c12d3 100644 --- a/src/plugins/gauge/components/GaugeFormController.vue +++ b/src/plugins/gauge/components/GaugeFormController.vue @@ -111,6 +111,7 @@ export default { isUseTelemetryLimits: this.model.value.isUseTelemetryLimits, isDisplayMinMax: this.model.value.isDisplayMinMax, isDisplayCurVal: this.model.value.isDisplayCurVal, + isDisplayUnits: this.model.value.isDisplayUnits, limitHigh: this.model.value.limitHigh, limitLow: this.model.value.limitLow, max: this.model.value.max, @@ -125,6 +126,7 @@ export default { gaugeType: this.model.value.gaugeType, isDisplayMinMax: this.isDisplayMinMax, isDisplayCurVal: this.isDisplayCurVal, + isDisplayUnits: this.isDisplayUnits, isUseTelemetryLimits: this.isUseTelemetryLimits, limitLow: this.limitLow, limitHigh: this.limitHigh, diff --git a/src/plugins/gauge/gauge.scss b/src/plugins/gauge/gauge.scss index a56f566a6e..3ce533a033 100644 --- a/src/plugins/gauge/gauge.scss +++ b/src/plugins/gauge/gauge.scss @@ -16,13 +16,12 @@ // Both dial and meter types overflow: hidden; - &__range { + &__range, + &__units, + &__units text { $c: $colorGaugeRange; color: $c; - - text { - fill: $c; - } + fill: $c; } &__wrapper { @@ -66,7 +65,8 @@ svg[class*='c-dial'] { transition: transform $transitionTimeGauge; } - &__current-value-text { + &__current-value-text, + &__units-text { fill: $colorGaugeTextValue; font-family: $heroFont; } From 111b0d0d68d3f93cdd37b8b5ba81eaa1d989d38c Mon Sep 17 00:00:00 2001 From: Nikhil Date: Fri, 3 Jun 2022 18:24:43 -0700 Subject: [PATCH 051/161] Imagery layers (#4968) * Moved imagery controls to a separate component * Zoom pan controls moved to component * Implement adjustments to encapsulate state into ImageryControls * Track modifier key pressed for layouts * image control popup open/close fix * Styling for imagery local controls Co-authored-by: Michael Rogers Co-authored-by: Shefali Joshi Co-authored-by: Andrew Henry Co-authored-by: Scott Bell Co-authored-by: Charles Hacskaylo Co-authored-by: unlikelyzero Co-authored-by: Jamie Vigliotta Co-authored-by: John Hill --- e2e/test-data/PerformanceDisplayLayout.json | 2 +- e2e/tests/performance/imagery.perf.spec.js | 2 +- .../imagery/exampleImagery.e2e.spec.js | 57 +++-- example/imagery/plugin.js | 19 +- .../overlays/components/OverlayComponent.vue | 1 + .../displayLayout/components/LayoutFrame.vue | 3 +- .../components/layout-frame.scss | 4 - .../imagery/components/FilterSettings.vue | 74 ++++++ .../imagery/components/ImageControls.vue | 131 ++++++----- .../imagery/components/ImageryView.vue | 125 +++++++--- .../components/ImageryViewMenuSwitcher.vue | 65 ++++++ .../imagery/components/LayerSettings.vue | 59 +++++ .../imagery/components/ZoomSettings.vue | 89 +++++++ .../imagery/components/imagery-view.scss | 220 +++++++++++------- .../layers/example-imagery-layer-16x9.png | Bin 0 -> 8554 bytes .../layers/example-imagery-layer-safe.png | Bin 0 -> 9245 bytes .../layers/example-imagery-layer-scale.png | Bin 0 -> 11616 bytes src/plugins/imagery/pluginSpec.js | 24 ++ .../telemetryTable/components/table.scss | 5 +- src/styles/_controls.scss | 25 ++ src/styles/_global.scss | 19 ++ src/styles/_legacy-plots.scss | 4 +- src/styles/_table.scss | 2 +- src/ui/components/ObjectFrame.vue | 25 ++ src/ui/components/object-frame.scss | 12 +- webpack.common.js | 4 + 26 files changed, 748 insertions(+), 223 deletions(-) create mode 100644 src/plugins/imagery/components/FilterSettings.vue create mode 100644 src/plugins/imagery/components/ImageryViewMenuSwitcher.vue create mode 100644 src/plugins/imagery/components/LayerSettings.vue create mode 100644 src/plugins/imagery/components/ZoomSettings.vue create mode 100644 src/plugins/imagery/layers/example-imagery-layer-16x9.png create mode 100644 src/plugins/imagery/layers/example-imagery-layer-safe.png create mode 100644 src/plugins/imagery/layers/example-imagery-layer-scale.png diff --git a/e2e/test-data/PerformanceDisplayLayout.json b/e2e/test-data/PerformanceDisplayLayout.json index eebc7635ad..de81d7b4ca 100644 --- a/e2e/test-data/PerformanceDisplayLayout.json +++ b/e2e/test-data/PerformanceDisplayLayout.json @@ -1 +1 @@ -{"openmct":{"21338566-d472-4377-aed1-21b79272c8de":{"identifier":{"key":"21338566-d472-4377-aed1-21b79272c8de","namespace":""},"name":"Performance Display Layout","type":"layout","composition":[{"key":"644c2e47-2903-475f-8a4a-6be1588ee02f","namespace":""}],"configuration":{"items":[{"width":32,"height":18,"x":1,"y":1,"identifier":{"key":"644c2e47-2903-475f-8a4a-6be1588ee02f","namespace":""},"hasFrame":true,"fontSize":"default","font":"default","type":"subobject-view","id":"5aeb5a71-3149-41ed-9d8a-d34b0a18b053"}],"layoutGrid":[10,10]},"modified":1652228997384,"location":"mine","persisted":1652228997384},"644c2e47-2903-475f-8a4a-6be1588ee02f":{"identifier":{"key":"644c2e47-2903-475f-8a4a-6be1588ee02f","namespace":""},"name":"Performance Example Imagery","type":"example.imagery","configuration":{"imageLocation":"","imageLoadDelayInMilliSeconds":20000,"imageSamples":[]},"telemetry":{"values":[{"name":"Name","key":"name"},{"name":"Time","key":"utc","format":"utc","hints":{"domain":2}},{"name":"Local Time","key":"local","format":"local-format","hints":{"domain":1}},{"name":"Image","key":"url","format":"image","hints":{"image":1}},{"name":"Image Download Name","key":"imageDownloadName","format":"imageDownloadName","hints":{"imageDownloadName":1}}]},"modified":1652228997375,"location":"21338566-d472-4377-aed1-21b79272c8de","persisted":1652228997375}},"rootId":"21338566-d472-4377-aed1-21b79272c8de"} \ No newline at end of file +{"openmct":{"b3cee102-86dd-4c0a-8eec-4d5d276f8691":{"identifier":{"key":"b3cee102-86dd-4c0a-8eec-4d5d276f8691","namespace":""},"name":"Performance Display Layout","type":"layout","composition":[{"key":"9666e7b4-be0c-47a5-94b8-99accad7155e","namespace":""}],"configuration":{"items":[{"width":32,"height":18,"x":12,"y":9,"identifier":{"key":"9666e7b4-be0c-47a5-94b8-99accad7155e","namespace":""},"hasFrame":true,"fontSize":"default","font":"default","type":"subobject-view","id":"23ca351d-a67d-46aa-a762-290eb742d2f1"}],"layoutGrid":[10,10]},"modified":1654299875432,"location":"mine","persisted":1654299878751},"9666e7b4-be0c-47a5-94b8-99accad7155e":{"identifier":{"key":"9666e7b4-be0c-47a5-94b8-99accad7155e","namespace":""},"name":"Performance Example Imagery","type":"example.imagery","configuration":{"imageLocation":"","imageLoadDelayInMilliSeconds":20000,"imageSamples":[],"layers":[{"source":"dist/imagery/example-imagery-layer-16x9.png","name":"16:9","visible":false},{"source":"dist/imagery/example-imagery-layer-safe.png","name":"Safe","visible":false},{"source":"dist/imagery/example-imagery-layer-scale.png","name":"Scale","visible":false}]},"telemetry":{"values":[{"name":"Name","key":"name"},{"name":"Time","key":"utc","format":"utc","hints":{"domain":2}},{"name":"Local Time","key":"local","format":"local-format","hints":{"domain":1}},{"name":"Image","key":"url","format":"image","hints":{"image":1},"layers":[{"source":"dist/imagery/example-imagery-layer-16x9.png","name":"16:9"},{"source":"dist/imagery/example-imagery-layer-safe.png","name":"Safe"},{"source":"dist/imagery/example-imagery-layer-scale.png","name":"Scale"}]},{"name":"Image Download Name","key":"imageDownloadName","format":"imageDownloadName","hints":{"imageDownloadName":1}}]},"modified":1654299840077,"location":"b3cee102-86dd-4c0a-8eec-4d5d276f8691","persisted":1654299840078}},"rootId":"b3cee102-86dd-4c0a-8eec-4d5d276f8691"} \ No newline at end of file diff --git a/e2e/tests/performance/imagery.perf.spec.js b/e2e/tests/performance/imagery.perf.spec.js index e7033ef10d..433bc1699d 100644 --- a/e2e/tests/performance/imagery.perf.spec.js +++ b/e2e/tests/performance/imagery.perf.spec.js @@ -164,7 +164,7 @@ test.describe('Performance tests', () => { console.log('jpgResourceTiming ' + JSON.stringify(jpgResourceTiming)); // Click Close Icon - await page.locator('.c-click-icon').click(); + await page.locator('[aria-label="Close"]').click(); await page.evaluate(() => window.performance.mark("view-large-close-button")); //await client.send('HeapProfiler.enable'); diff --git a/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js b/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js index d5c204cdb2..0a570e5c2a 100644 --- a/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js +++ b/e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js @@ -32,7 +32,6 @@ const { expect } = require('@playwright/test'); test.describe('Example Imagery', () => { test.beforeEach(async ({ page }) => { - page.on('console', msg => console.log(msg.text())); //Go to baseURL await page.goto('/', { waitUntil: 'networkidle' }); @@ -61,19 +60,19 @@ test.describe('Example Imagery', () => { test('Can use Mouse Wheel to zoom in and out of latest image', async ({ page }) => { const bgImageLocator = page.locator(backgroundImageSelector); const deltaYStep = 100; //equivalent to 1x zoom - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const originalImageDimensions = await page.locator(backgroundImageSelector).boundingBox(); // zoom in - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); await page.mouse.wheel(0, deltaYStep * 2); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const imageMouseZoomedIn = await page.locator(backgroundImageSelector).boundingBox(); // zoom out - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); await page.mouse.wheel(0, -deltaYStep); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const imageMouseZoomedOut = await page.locator(backgroundImageSelector).boundingBox(); expect(imageMouseZoomedIn.height).toBeGreaterThan(originalImageDimensions.height); @@ -88,11 +87,11 @@ test.describe('Example Imagery', () => { const panHotkey = process.platform === 'linux' ? ['Control', 'Alt'] : ['Alt']; const bgImageLocator = page.locator(backgroundImageSelector); - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); // zoom in await page.mouse.wheel(0, deltaYStep * 2); - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const zoomedBoundingBox = await bgImageLocator.boundingBox(); const imageCenterX = zoomedBoundingBox.x + zoomedBoundingBox.width / 2; const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2; @@ -151,22 +150,22 @@ test.describe('Example Imagery', () => { test('Can use + - buttons to zoom on the image', async ({ page }) => { const bgImageLocator = page.locator(backgroundImageSelector); - await bgImageLocator.hover(); - const zoomInBtn = page.locator('.t-btn-zoom-in'); - const zoomOutBtn = page.locator('.t-btn-zoom-out'); + await bgImageLocator.hover({trial: true}); + const zoomInBtn = page.locator('.t-btn-zoom-in').nth(0); + const zoomOutBtn = page.locator('.t-btn-zoom-out').nth(0); const initialBoundingBox = await bgImageLocator.boundingBox(); await zoomInBtn.click(); await zoomInBtn.click(); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const zoomedInBoundingBox = await bgImageLocator.boundingBox(); expect(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height); expect(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width); await zoomOutBtn.click(); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const zoomedOutBoundingBox = await bgImageLocator.boundingBox(); expect(zoomedOutBoundingBox.height).toBeLessThan(zoomedInBoundingBox.height); expect(zoomedOutBoundingBox.width).toBeLessThan(zoomedInBoundingBox.width); @@ -176,18 +175,18 @@ test.describe('Example Imagery', () => { test('Can use the reset button to reset the image', async ({ page }) => { const bgImageLocator = page.locator(backgroundImageSelector); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); - const zoomInBtn = page.locator('.t-btn-zoom-in'); - const zoomResetBtn = page.locator('.t-btn-zoom-reset'); + const zoomInBtn = page.locator('.t-btn-zoom-in').nth(0); + const zoomResetBtn = page.locator('.t-btn-zoom-reset').nth(0); const initialBoundingBox = await bgImageLocator.boundingBox(); await zoomInBtn.click(); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); await zoomInBtn.click(); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const zoomedInBoundingBox = await bgImageLocator.boundingBox(); expect.soft(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height); @@ -195,7 +194,7 @@ test.describe('Example Imagery', () => { await zoomResetBtn.click(); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const resetBoundingBox = await bgImageLocator.boundingBox(); expect.soft(resetBoundingBox.height).toBeLessThan(zoomedInBoundingBox.height); @@ -209,18 +208,18 @@ test.describe('Example Imagery', () => { const bgImageLocator = page.locator(backgroundImageSelector); const pausePlayButton = page.locator('.c-button.pause-play'); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); // open the time conductor drop down - await page.locator('.c-conductor__controls button.c-mode-button').click(); + await page.locator('button:has-text("Fixed Timespan")').click(); // Click local clock - await page.locator('.icon-clock >> text=Local Clock').click(); + await page.locator('[data-testid="conductor-modeOption-realtime"]').click(); await expect.soft(pausePlayButton).not.toHaveClass(/is-paused/); - const zoomInBtn = page.locator('.t-btn-zoom-in'); + const zoomInBtn = page.locator('.t-btn-zoom-in').nth(0); await zoomInBtn.click(); // wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); return expect(pausePlayButton).not.toHaveClass(/is-paused/); }); @@ -267,7 +266,7 @@ test('Example Imagery in Display layout', async ({ page }) => { await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery'); const bgImageLocator = page.locator(backgroundImageSelector); - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); // Click previous image button const previousImageButton = page.locator('.c-nav--prev'); @@ -279,7 +278,7 @@ test('Example Imagery in Display layout', async ({ page }) => { // Zoom in const originalImageDimensions = await page.locator(backgroundImageSelector).boundingBox(); - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const deltaYStep = 100; // equivalent to 1x zoom await page.mouse.wheel(0, deltaYStep * 2); const zoomedBoundingBox = await bgImageLocator.boundingBox(); @@ -287,7 +286,7 @@ test('Example Imagery in Display layout', async ({ page }) => { const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2; // Wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const imageMouseZoomedIn = await page.locator(backgroundImageSelector).boundingBox(); expect(imageMouseZoomedIn.height).toBeGreaterThan(originalImageDimensions.height); expect(imageMouseZoomedIn.width).toBeGreaterThan(originalImageDimensions.width); @@ -311,11 +310,11 @@ test('Example Imagery in Display layout', async ({ page }) => { await page.locator('[data-testid=conductor-modeOption-realtime]').click(); // Zoom in on next image - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); await page.mouse.wheel(0, deltaYStep * 2); // Wait for zoom animation to finish - await bgImageLocator.hover(); + await bgImageLocator.hover({trial: true}); const imageNextMouseZoomedIn = await page.locator(backgroundImageSelector).boundingBox(); expect(imageNextMouseZoomedIn.height).toBeGreaterThan(originalImageDimensions.height); expect(imageNextMouseZoomedIn.width).toBeGreaterThan(originalImageDimensions.width); diff --git a/example/imagery/plugin.js b/example/imagery/plugin.js index 6823ede509..47d6f4ef70 100644 --- a/example/imagery/plugin.js +++ b/example/imagery/plugin.js @@ -59,7 +59,8 @@ export default function () { object.configuration = { imageLocation: '', imageLoadDelayInMilliSeconds: DEFAULT_IMAGE_LOAD_DELAY_IN_MILISECONDS, - imageSamples: [] + imageSamples: [], + layers: [] }; object.telemetry = { @@ -90,7 +91,21 @@ export default function () { format: 'image', hints: { image: 1 - } + }, + layers: [ + { + source: 'dist/imagery/example-imagery-layer-16x9.png', + name: '16:9' + }, + { + source: 'dist/imagery/example-imagery-layer-safe.png', + name: 'Safe' + }, + { + source: 'dist/imagery/example-imagery-layer-scale.png', + name: 'Scale' + } + ] }, { name: 'Image Download Name', diff --git a/src/api/overlays/components/OverlayComponent.vue b/src/api/overlays/components/OverlayComponent.vue index f8a66f7597..9742fd7367 100644 --- a/src/api/overlays/components/OverlayComponent.vue +++ b/src/api/overlays/components/OverlayComponent.vue @@ -7,6 +7,7 @@
diff --git a/src/plugins/displayLayout/components/LayoutFrame.vue b/src/plugins/displayLayout/components/LayoutFrame.vue index 052fa63a3c..c81fb80f71 100644 --- a/src/plugins/displayLayout/components/LayoutFrame.vue +++ b/src/plugins/displayLayout/components/LayoutFrame.vue @@ -25,8 +25,7 @@ class="l-layout__frame c-frame" :class="{ 'no-frame': !item.hasFrame, - 'u-inspectable': inspectable, - 'is-in-small-container': size.width < 600 || size.height < 600 + 'u-inspectable': inspectable }" :style="style" > diff --git a/src/plugins/displayLayout/components/layout-frame.scss b/src/plugins/displayLayout/components/layout-frame.scss index 63f2299ecb..d036814021 100644 --- a/src/plugins/displayLayout/components/layout-frame.scss +++ b/src/plugins/displayLayout/components/layout-frame.scss @@ -9,10 +9,6 @@ > *:first-child { flex: 1 1 auto; } - - &.is-in-small-container { - //background: rgba(blue, 0.1); - } } .c-frame__move-bar { diff --git a/src/plugins/imagery/components/FilterSettings.vue b/src/plugins/imagery/components/FilterSettings.vue new file mode 100644 index 0000000000..c88d215d55 --- /dev/null +++ b/src/plugins/imagery/components/FilterSettings.vue @@ -0,0 +1,74 @@ + + + diff --git a/src/plugins/imagery/components/ImageControls.vue b/src/plugins/imagery/components/ImageControls.vue index a14a402df5..b14c13f8b2 100644 --- a/src/plugins/imagery/components/ImageControls.vue +++ b/src/plugins/imagery/components/ImageControls.vue @@ -21,75 +21,62 @@ *****************************************************************************/ diff --git a/src/plugins/imagery/components/LayerSettings.vue b/src/plugins/imagery/components/LayerSettings.vue new file mode 100644 index 0000000000..1e99a0aee6 --- /dev/null +++ b/src/plugins/imagery/components/LayerSettings.vue @@ -0,0 +1,59 @@ + + + diff --git a/src/plugins/imagery/components/ZoomSettings.vue b/src/plugins/imagery/components/ZoomSettings.vue new file mode 100644 index 0000000000..e53d6289ed --- /dev/null +++ b/src/plugins/imagery/components/ZoomSettings.vue @@ -0,0 +1,89 @@ + + + diff --git a/src/plugins/imagery/components/imagery-view.scss b/src/plugins/imagery/components/imagery-view.scss index 8cdae861db..e781fdce9a 100644 --- a/src/plugins/imagery/components/imagery-view.scss +++ b/src/plugins/imagery/components/imagery-view.scss @@ -28,6 +28,27 @@ display: flex; flex-direction: column; flex: 1 1 auto; + + &.unnsynced{ + @include sUnsynced(); + } + + &.cursor-zoom-in { + cursor: zoom-in; + } + + &.cursor-zoom-out { + cursor: zoom-out; + } + + &.pannable { + @include cursorGrab(); + } + } + + .image-wrapper { + overflow: visible clip; + background-image: repeating-linear-gradient(45deg, transparent, transparent 4px, rgba(125, 125, 125, 0.2) 4px, rgba(125, 125, 125, 0.2) 8px); } .image-wrapper { @@ -45,19 +66,6 @@ flex: 1 1 auto; height: 0; overflow: hidden; - &.unnsynced{ - @include sUnsynced(); - } - &.cursor-zoom-in { - cursor: zoom-in; - } - &.cursor-zoom-out { - cursor: zoom-out; - } - &.pannable { - @include cursorGrab(); - - } } &__background-image { background-position: center; @@ -77,6 +85,7 @@ background: rgba(black, 0.2); border-radius: $smallCr; padding: 2px $interiorMargin; + pointer-events: none; position: absolute; right: $m; top: $m; @@ -146,6 +155,11 @@ } + &__layer-image { + pointer-events: none; + z-index: 1; + } + &__thumbs-wrapper { display: flex; // Uses row layout justify-content: flex-end; @@ -179,6 +193,50 @@ font-size: 0.8em; margin: $interiorMarginSm; } + + .c-control-menu { + // Controls on left of flex column layout, close btn on right + @include menuOuter(); + + border-radius: $controlCr; + display: flex; + align-items: flex-start; + justify-content: space-between; + padding: $interiorMargin; + width: min-content; + + > * + * { + margin-left: $interiorMargin; + } + } + + .c-switcher-menu { + display: contents; + + &__content { + // Menu panel + top: 28px; + position: absolute; + + .c-so-view & { + top: 25px; + } + } + } +} + +.--width-less-than-220 .--show-if-less-than-220.c-switcher-menu { + display: contents !important; +} + +.s-image-layer { + position: absolute; + height: 100%; + width: 100%; + opacity: 0.5; + background-size: contain; + background-repeat: no-repeat; + background-position: center; } /*************************************** THUMBS */ @@ -229,70 +287,36 @@ /*************************************** IMAGERY LOCAL CONTROLS*/ .c-imagery { .h-local-controls--overlay-content { + display: flex; + flex-direction: row; position: absolute; left: $interiorMargin; top: $interiorMargin; z-index: 70; background: $colorLocalControlOvrBg; border-radius: $basicCr; - max-width: 250px; - min-width: 170px; - width: 35%; align-items: center; - padding: $interiorMargin $interiorMarginLg; - - input[type="range"] { - display: block; - width: 100%; - &:not(:first-child) { - margin-top: $interiorMarginLg; - } - - &:before { - margin-right: $interiorMarginSm; - } - } + padding: $interiorMargin $interiorMargin; .s-status-taking-snapshot & { display: none; } } - - &__lc { - &__reset-btn { - // Span that holds bracket graphics and button - $bc: $scrollbarTrackColorBg; - - &:before, - &:after { - border-right: 1px solid $bc; - content:''; - display: block; - width: 5px; - height: 4px; - } - - &:before { - border-top: 1px solid $bc; - margin-bottom: 2px; - } - - &:after { - border-bottom: 1px solid $bc; - margin-top: 2px; - } - - .c-icon-link { - color: $colorBtnFg; - } + [class*='--menus-aligned'] { + > * + * { + button { margin-left: $interiorMarginSm; } } } } .c-image-controls { + &__controls-wrapper { + // Wraps __controls and __close-btn + display: flex; + } + &__controls { display: flex; align-items: stretch; - flex-direction: column; > * + * { margin-top: $interiorMargin; @@ -314,31 +338,67 @@ } - &__input { - // A wrapper is needed to add the type icon to left of each control - - input[type='range'] { - //width: 100%; // Do we need this? - } - } - &__zoom { - > * + * { margin-left: $interiorMargin; } + > * + * { margin-left: $interiorMargin; } // Is this used? } - &__sliders { - display: flex; - flex: 1 1 auto; - flex-direction: column; + &--filters { + // Styles specific to the brightness and contrast controls - > * + * { - margin-top: 11px; + .c-image-controls { + &__sliders { + display: flex; + flex: 1 1 auto; + flex-direction: column; + min-width: 80px; + + > * + * { + margin-top: 11px; + } + + input[type="range"] { + display: block; + width: 100%; + } + } + + &__slider-wrapper { + display: flex; + align-items: center; + + &:before { margin-right: $interiorMargin; } + } + + &__reset-btn { + // Span that holds bracket graphics and button + $bc: $scrollbarTrackColorBg; + flex: 0 0 auto; + + &:before, + &:after { + border-right: 1px solid $bc; + content:''; + display: block; + width: 5px; + height: 4px; + } + + &:before { + border-top: 1px solid $bc; + margin-bottom: 2px; + } + + &:after { + border-bottom: 1px solid $bc; + margin-top: 2px; + } + + .c-icon-link { + color: $colorBtnFg; + } + } } } - - &__btn-reset { - flex: 0 0 auto; - } } /*************************************** BUTTONS */ @@ -383,7 +443,7 @@ @include cArrowButtonSizing($dimOuter: 48px); border-radius: $controlCr; - .is-in-small-container & { + .--width-less-than-600 & { @include cArrowButtonSizing($dimOuter: 32px); } } @@ -409,10 +469,6 @@ background-color: $colorBodyFg; } - //[class*='__image-placeholder'] { - // display: none; - //} - img { display: block !important; } diff --git a/src/plugins/imagery/layers/example-imagery-layer-16x9.png b/src/plugins/imagery/layers/example-imagery-layer-16x9.png new file mode 100644 index 0000000000000000000000000000000000000000..877a0e6038b220964e2d232ab10c7a37f6eaf055 GIT binary patch literal 8554 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 { location: "parentId", modified: 0, persisted: 0, + configuration: { + layers: [{ + name: '16:9', + visible: true + }] + }, telemetry: { values: [ { "name": "Image", "key": "url", "format": "image", + "layers": [ + { + source: location.host + '/images/bg-splash.jpg', + name: '16:9' + } + ], "hints": { "image": 1, "priority": 3 @@ -366,6 +378,18 @@ describe("The Imagery View Layouts", () => { }); }); + it("on mount should show the any image layers", (done) => { + //Looks like we need Vue.nextTick here so that computed properties settle down + Vue.nextTick().then(() => { + Vue.nextTick(() => { + const layerEls = parent.querySelectorAll('.js-layer-image'); + console.log(layerEls); + expect(layerEls.length).toEqual(1); + done(); + }); + }); + }); + it("should show the clicked thumbnail as the main image", (done) => { //Looks like we need Vue.nextTick here so that computed properties settle down Vue.nextTick(() => { diff --git a/src/plugins/telemetryTable/components/table.scss b/src/plugins/telemetryTable/components/table.scss index 512af8c3a1..03d54c0f72 100644 --- a/src/plugins/telemetryTable/components/table.scss +++ b/src/plugins/telemetryTable/components/table.scss @@ -63,8 +63,9 @@ padding-top: 0; padding-bottom: 0; } - .is-in-small-container & { - display: none; + + .--width-less-than-600 & { + display: none !important; } } } diff --git a/src/styles/_controls.scss b/src/styles/_controls.scss index ac11686977..3e356036d6 100644 --- a/src/styles/_controls.scss +++ b/src/styles/_controls.scss @@ -42,6 +42,17 @@ } } +@mixin menuPositioning() { + display: flex; + flex-direction: column; + position: absolute; + z-index: 100; + + > * { + flex: 0 0 auto; + } +} + @mixin menuInner() { li { @include cControl(); @@ -479,6 +490,10 @@ select { &__row { > * + * { margin-left: $interiorMargin; } } + + li { + white-space: nowrap; + } } /******************************************************** TABS */ @@ -567,6 +582,7 @@ select { /******************************************************** MENUS */ .c-menu { @include menuOuter(); + @include menuPositioning(); @include menuInner(); &__section-hint { @@ -590,6 +606,7 @@ select { .c-super-menu { // Two column layout, menu items on left with detail of hover element on right @include menuOuter(); + @include menuPositioning(); display: flex; padding: $interiorMarginLg; flex-direction: row; @@ -1035,6 +1052,14 @@ input[type="range"] { display: inline-flex; align-items: center; } + + [class*='--menus-aligned'] { + // Contains top level elements that hold dropdown menus + // Top level elements use display: contents to allow their menus to compactly align + // 03-18-22: used in ImageControls.vue + display: flex; + flex-direction: row; + } } .c-local-controls { diff --git a/src/styles/_global.scss b/src/styles/_global.scss index 5b2efb8efd..46ab0ad66b 100644 --- a/src/styles/_global.scss +++ b/src/styles/_global.scss @@ -349,3 +349,22 @@ body.desktop .has-local-controls { pointer-events: none !important; cursor: default !important; } + +/******************************************************** RESPONSIVE CONTAINERS */ +@mixin responsiveContainerWidths($dimension) { + // 3/21/22: `--width-less-than*` classes set in ObjectView.vue + .--show-if-less-than-#{$dimension} { + // Hide anything that displays within a given width by default. + // `display` property must be set within a more specific class + // for the particular item to be displayed. + display: none !important + } + + .--width-less-than-#{$dimension} { + .--hide-if-less-than-#{$dimension} { display: none; } + } +} + +//.--hide-by-default { display: none !important; } +@include responsiveContainerWidths('220'); +@include responsiveContainerWidths('600'); diff --git a/src/styles/_legacy-plots.scss b/src/styles/_legacy-plots.scss index 4ec0529e0f..b9ae1b6d9b 100644 --- a/src/styles/_legacy-plots.scss +++ b/src/styles/_legacy-plots.scss @@ -118,7 +118,7 @@ mct-plot { } } - .is-in-small-container & { + .--width-less-than-600 & { .c-control-bar { display: none; } @@ -498,7 +498,7 @@ mct-plot { margin-bottom: $interiorMarginSm; } - .is-in-small-container & { + .--width-less-than-600 & { &.is-legend-hidden { display: none; } diff --git a/src/styles/_table.scss b/src/styles/_table.scss index 12540ae933..d6c85206d0 100644 --- a/src/styles/_table.scss +++ b/src/styles/_table.scss @@ -90,7 +90,7 @@ div.c-table { flex: 1 1 auto; } - .is-in-small-container & { + .--width-less-than-600 & { &:not(.is-paused) { .c-table-control-bar { display: none; diff --git a/src/ui/components/ObjectFrame.vue b/src/ui/components/ObjectFrame.vue index cef8931873..1254cc3cbb 100644 --- a/src/ui/components/ObjectFrame.vue +++ b/src/ui/components/ObjectFrame.vue @@ -21,9 +21,11 @@ *****************************************************************************/