Compare commits
	
		
			27 Commits
		
	
	
		
			fix-stacke
			...
			playwright
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | b02d063b8b | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 93a796353d | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 18ff16052a | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | f1c7fa337d | ||
|   | 557f29f9bb | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 255ebc9a37 | ||
|   | ca7fbe58e3 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | b347f35892 | ||
|   | 28d5d72834 | ||
|   | 0df33730f7 | ||
|   | 7b2ff8fa15 | ||
|   | d80b692354 | ||
|   | 4205abdc80 | ||
|   | 492ff2fa64 | ||
|   | 93a81a1369 | ||
|   | 482d8f392c | ||
|   | 67234c70a4 | ||
|   | e9680e975f | ||
|   | e691a89682 | ||
|   | 079956d7ae | ||
|   | c81c5f7c25 | ||
|   | 986083f3c7 | ||
|   | cb7c9fd4f9 | ||
|   | 8b8f5c4df4 | ||
|   | 80fc393b54 | ||
|   | 58138e8554 | ||
|   | 54bed23267 | 
| @@ -21,7 +21,7 @@ commands: | ||||
|       - restore_cache_cmd: | ||||
|           node-version: << parameters.node-version >> | ||||
|       - node/install: | ||||
|           install-npm: true | ||||
|           install-npm: false | ||||
|           node-version: << parameters.node-version >> | ||||
|       - run: npm install | ||||
|   restore_cache_cmd: | ||||
| @@ -47,6 +47,7 @@ commands: | ||||
|           paths: | ||||
|             - ~/.npm | ||||
|             - node_modules | ||||
|             - ~/.cache/ms-playwright | ||||
|   generate_and_store_version_and_filesystem_artifacts: | ||||
|     description: "Track important packages and files" | ||||
|     steps: | ||||
| @@ -64,7 +65,6 @@ commands: | ||||
|         - 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.2.3 | ||||
| jobs: | ||||
|   npm-audit: | ||||
|     parameters: | ||||
| @@ -96,26 +96,9 @@ jobs: | ||||
|     steps: | ||||
|       - build_and_install: | ||||
|           node-version: <<parameters.node-version>> | ||||
|       - when: | ||||
|           condition: | ||||
|             equal: [ "FirefoxESR", <<parameters.browser>> ] | ||||
|           steps: | ||||
|             - browser-tools/install-firefox: | ||||
|                 version: "91.4.0esr" #https://archive.mozilla.org/pub/firefox/releases/           | ||||
|       - when: | ||||
|           condition: | ||||
|             equal: [ "FirefoxHeadless", <<parameters.browser>> ] | ||||
|           steps: | ||||
|             - browser-tools/install-firefox | ||||
|       - when: | ||||
|           condition: | ||||
|             equal: [ "ChromeHeadless", <<parameters.browser>> ] | ||||
|           steps: | ||||
|             - browser-tools/install-chrome: | ||||
|                 replace-existing: false | ||||
|       - run: npm run test:coverage -- --browsers=<<parameters.browser>> | ||||
|       - save_cache_cmd: | ||||
|           node-version: <<parameters.node-version>> | ||||
|       - run: npm run test:coverage -- --browsers=<<parameters.browser>> | ||||
|       - store_test_results: | ||||
|           path: dist/reports/tests/ | ||||
|       - store_artifacts: | ||||
| @@ -146,11 +129,11 @@ workflows: | ||||
|       - unit-test: | ||||
|           name: node12-chrome | ||||
|           node-version: lts/erbium | ||||
|           browser: ChromeHeadless | ||||
|           browser: PlaywrightChrome | ||||
|       - unit-test:  | ||||
|           name: node14-chrome | ||||
|           node-version: lts/fermium | ||||
|           browser: ChromeHeadless | ||||
|           browser: PlaywrightChrome | ||||
|           post-steps: | ||||
|             - upload_code_covio   | ||||
|       - unit-test: | ||||
| @@ -161,24 +144,24 @@ workflows: | ||||
|           name: e2e-ci | ||||
|           node-version: lts/gallium | ||||
|           suite: ci | ||||
|   the-nightly: #These jobs do not run on PRs, but against master at night | ||||
|   the-nightly: #These jobs do not run on PRs, but against master each night | ||||
|     jobs: | ||||
|       - unit-test: | ||||
|           name: node12-firefoxESR-nightly | ||||
|           node-version: lts/erbium | ||||
|           browser: FirefoxESR | ||||
|       - unit-test: | ||||
|           name: node12-chrome-nightly | ||||
|           node-version: lts/erbium | ||||
|           browser: ChromeHeadless | ||||
|           browser: PlaywrightChrome | ||||
|       - unit-test: | ||||
|           name: node14-firefox-nightly | ||||
|           node-version: lts/fermium | ||||
|           browser: FirefoxHeadless | ||||
|           browser: PlaywrightFirefox | ||||
|       - unit-test: | ||||
|           name: node14-chrome-nightly | ||||
|           name: node14-chrome-canary-nightly | ||||
|           node-version: lts/fermium | ||||
|           browser: ChromeHeadless | ||||
|           browser: PlaywrightChromeCanary | ||||
|       - unit-test: | ||||
|           name: node14-safari-nightly | ||||
|           node-version: lts/fermium | ||||
|           browser: PlaywrightSafari | ||||
|       - unit-test: | ||||
|           name: node16-chrome-nightly | ||||
|           node-version: lts/gallium | ||||
|   | ||||
							
								
								
									
										12
									
								
								.eslintrc.js
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								.eslintrc.js
									
									
									
									
									
								
							| @@ -11,12 +11,14 @@ module.exports = { | ||||
|     }, | ||||
|     "extends": [ | ||||
|         "eslint:recommended", | ||||
|         "plugin:compat/recommended", | ||||
|         "plugin:vue/recommended", | ||||
|         "plugin:you-dont-need-lodash-underscore/compatible" | ||||
|     ], | ||||
|     "parser": "vue-eslint-parser", | ||||
|     "parserOptions": { | ||||
|         "parser": "babel-eslint", | ||||
|         "parser": "@babel/eslint-parser", | ||||
|         "requireConfigFile": false, | ||||
|         "allowImportExportEverywhere": true, | ||||
|         "ecmaVersion": 2015, | ||||
|         "ecmaFeatures": { | ||||
| @@ -35,7 +37,6 @@ module.exports = { | ||||
|         "no-inner-declarations": "off", | ||||
|         "no-use-before-define": ["error", "nofunc"], | ||||
|         "no-caller": "error", | ||||
|         "no-sequences": "error", | ||||
|         "no-irregular-whitespace": "error", | ||||
|         "no-new": "error", | ||||
|         "no-shadow": "error", | ||||
| @@ -239,13 +240,12 @@ module.exports = { | ||||
|         ], | ||||
|         "vue/max-attributes-per-line": ["error", { | ||||
|             "singleline": 1, | ||||
|             "multiline": { | ||||
|                 "max": 1, | ||||
|                 "allowFirstLine": true | ||||
|             } | ||||
|             "multiline": 1, | ||||
|         }], | ||||
|         "vue/first-attribute-linebreak": "error", | ||||
|         "vue/multiline-html-element-content-newline": "off", | ||||
|         "vue/singleline-html-element-content-newline": "off", | ||||
|         "vue/multi-word-component-names": "off", // TODO enable, align with conventions | ||||
|         "vue/no-mutating-props": "off" | ||||
|  | ||||
|     }, | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/e2e-pr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/e2e-pr.yml
									
									
									
									
										vendored
									
									
								
							| @@ -30,7 +30,7 @@ jobs: | ||||
|       - uses: actions/setup-node@v3 | ||||
|         with: | ||||
|           node-version: '16' | ||||
|       - run: npx playwright install-deps | ||||
|       - run: npx playwright@1.19.2 install | ||||
|       - run: npm install | ||||
|       - run: npm run test:e2e:full | ||||
|       - name: Archive test results | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/e2e-visual.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/e2e-visual.yml
									
									
									
									
										vendored
									
									
								
							| @@ -17,7 +17,7 @@ jobs: | ||||
|       - uses: actions/setup-node@v3 | ||||
|         with: | ||||
|           node-version: '16' | ||||
|       - run: npx playwright install-deps | ||||
|       - run: npx playwright@1.19.2 install | ||||
|       - run: npm install | ||||
|       - name: Run the e2e visual tests | ||||
|         run: npm run test:e2e:visual | ||||
|   | ||||
							
								
								
									
										5
									
								
								.npmrc
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								.npmrc
									
									
									
									
									
								
							| @@ -1,9 +1,4 @@ | ||||
| loglevel=warn | ||||
|  | ||||
| # Temporary: istanbul-instrumenter-loader is working with webpack 5, but states | ||||
| # webpack 4 being the latest version it supports, so this legacy-peer-deps | ||||
| # allows us to install it anyway. | ||||
| legacy-peer-deps=true | ||||
|  | ||||
| #Prevent folks from ignoring an important error when building from source | ||||
| engine-strict=true | ||||
| @@ -65,6 +65,12 @@ Open MCT is built using [`npm`](http://npmjs.com/) and [`webpack`](https://webpa | ||||
|  | ||||
| See our documentation for a guide on [building Applications with Open MCT](https://github.com/nasa/openmct/blob/master/API.md#starting-an-open-mct-application). | ||||
|  | ||||
| ## Compatibility | ||||
|  | ||||
| This is a fast moving project and we do our best to test and support the widest possible range of browsers, operating systems, and nodejs APIs. We have a published list of support available in our package.json's `browserslist` key. | ||||
|  | ||||
| If you encounter an issue with a particular browser, OS, or nodejs API, please file a [GitHub issue](https://github.com/nasa/openmct/issues/new/choose) | ||||
|  | ||||
| ## Plugins | ||||
|  | ||||
| Open MCT can be extended via plugins that make calls to the Open MCT API. A plugin is a group  | ||||
|   | ||||
							
								
								
									
										9
									
								
								babel.coverage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								babel.coverage.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| // This is a Babel config that webpack.coverage.js uses in order to instrument | ||||
| // code with coverage instrumentation. | ||||
| const babelConfig = { | ||||
|     plugins: [['babel-plugin-istanbul', { | ||||
|         extension: ['.js', '.vue'] | ||||
|     }]] | ||||
| }; | ||||
|  | ||||
| module.exports = babelConfig; | ||||
| @@ -26,7 +26,6 @@ const config = { | ||||
|     reporter: [ | ||||
|         ['list'], | ||||
|         ['junit', { outputFile: 'test-results/results.xml' }], | ||||
|         ['allure-playwright'] | ||||
|     ] | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										62
									
								
								e2e/tests/branding.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								e2e/tests/branding.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| /* | ||||
| This test suite is dedicated to tests which verify branding related components. | ||||
| */ | ||||
|  | ||||
| const { test, expect } = require('@playwright/test'); | ||||
|  | ||||
| test.describe('Branding tests', () => { | ||||
|     test('About Modal launches with basic branding properties', async ({ page }) => { | ||||
|         // Go to baseURL | ||||
|         await page.goto('/', { waitUntil: 'networkidle' }); | ||||
|  | ||||
|         // Click About button | ||||
|         await page.click('.l-shell__app-logo'); | ||||
|  | ||||
|         // Verify that the NASA Logo Appears | ||||
|         await expect(await page.locator('.c-about__image')).toBeVisible(); | ||||
|  | ||||
|         // Modify the Build information in 'about' Modal | ||||
|         const versionInformationLocator = page.locator('ul.t-info.l-info.s-info'); | ||||
|         await expect(versionInformationLocator).toBeEnabled(); | ||||
|         await expect.soft(versionInformationLocator).toContainText(/Version: \d/); | ||||
|         await expect.soft(versionInformationLocator).toContainText(/Build Date: ((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun))/); | ||||
|         await expect.soft(versionInformationLocator).toContainText(/Revision: \b[0-9a-f]{5,40}\b/); | ||||
|         await expect.soft(versionInformationLocator).toContainText(/Branch: ./); | ||||
|     }); | ||||
|     test('Verify Links in About Modal', async ({ page }) => { | ||||
|         // Go to baseURL | ||||
|         await page.goto('/', { waitUntil: 'networkidle' }); | ||||
|  | ||||
|         // Click About button | ||||
|         await page.click('.l-shell__app-logo'); | ||||
|  | ||||
|         // Verify that clicking on the third party licenses information opens up another tab on licenses url | ||||
|         const [page2] = await Promise.all([ | ||||
|             page.waitForEvent('popup'), | ||||
|             page.locator('text=click here for third party licensing information').click() | ||||
|         ]); | ||||
|         expect(page2.waitForURL('**\/licenses**')).toBeTruthy(); | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										62
									
								
								e2e/tests/example/eventGenerator.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								e2e/tests/example/eventGenerator.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| /* | ||||
| This test suite is dedicated to tests which verify the basic operations surrounding the example event generator. | ||||
| */ | ||||
|  | ||||
| const { test, expect } = require('@playwright/test'); | ||||
|  | ||||
| test.describe('Example Event Generator Operations', () => { | ||||
|     test('Can create example event generator with a name', async ({ page }) => { | ||||
|         //Go to baseURL | ||||
|         await page.goto('/', { waitUntil: 'networkidle' }); | ||||
|         // let's make an event generator | ||||
|         await page.locator('button:has-text("Create")').click(); | ||||
|         // Click li:has-text("Event Message Generator") | ||||
|         await page.locator('li:has-text("Event Message Generator")').click(); | ||||
|         // Click text=Properties Title Notes >> input[type="text"] | ||||
|         await page.locator('text=Properties Title Notes >> input[type="text"]').click(); | ||||
|         // Fill text=Properties Title Notes >> input[type="text"] | ||||
|         await page.locator('text=Properties Title Notes >> input[type="text"]').fill('Test Event Generator'); | ||||
|         // Press Enter | ||||
|         await page.locator('text=Properties Title Notes >> input[type="text"]').press('Enter'); | ||||
|         // Click text=OK | ||||
|         await Promise.all([ | ||||
|             page.waitForNavigation({ url: /.*&view=table/ }), | ||||
|             page.locator('text=OK').click() | ||||
|         ]); | ||||
|  | ||||
|         await expect(page.locator('.l-browse-bar__object-name')).toContainText('Test Event Generator'); | ||||
|         // Click button:has-text("Fixed Timespan") | ||||
|         await page.locator('button:has-text("Fixed Timespan")').click(); | ||||
|     }); | ||||
|  | ||||
|     test.fixme('telemetry is coming in for test event', async ({ page }) => { | ||||
|         // Go to object created in step one | ||||
|         // Verify the telemetry table is filled with > 1 row | ||||
|     }); | ||||
|     test.fixme('telemetry is sorted by time ascending', async ({ page }) => { | ||||
|         // Go to object created in step one | ||||
|         // Verify the telemetry table has a class with "is-sorting asc" | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										161
									
								
								e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| /* | ||||
| This test suite is dedicated to tests which verify the basic operations surrounding conditionSets. | ||||
| */ | ||||
|  | ||||
| const { test, expect } = require('@playwright/test'); | ||||
|  | ||||
| test.describe('Sine Wave Generator', () => { | ||||
|     test('Create new Sine Wave Generator Object and validate create Form Logic', async ({ page }) => { | ||||
|         //Go to baseURL | ||||
|         await page.goto('/', { waitUntil: 'networkidle' }); | ||||
|  | ||||
|         //Click the Create button | ||||
|         await page.click('button:has-text("Create")'); | ||||
|  | ||||
|         // Click Sine Wave Generator | ||||
|         await page.click('text=Sine Wave Generator'); | ||||
|  | ||||
|         // Verify that the each required field has required indicator | ||||
|         // Title | ||||
|         await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(['c-form-row__state-indicator  req']); | ||||
|  | ||||
|         // Verify that the Notes row does not have a required indicator | ||||
|         await expect(page.locator('.c-form__section div:nth-child(3) .form-row .c-form-row__state-indicator')).not.toContain('.req'); | ||||
|  | ||||
|         // Period | ||||
|         await expect(page.locator('.c-form__section div:nth-child(4) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']); | ||||
|  | ||||
|         // Amplitude | ||||
|         await expect(page.locator('.c-form__section div:nth-child(5) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']); | ||||
|  | ||||
|         // Offset | ||||
|         await expect(page.locator('.c-form__section div:nth-child(6) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']); | ||||
|  | ||||
|         // Data Rate | ||||
|         await expect(page.locator('.c-form__section div:nth-child(7) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']); | ||||
|  | ||||
|         // Phase | ||||
|         await expect(page.locator('.c-form__section div:nth-child(8) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']); | ||||
|  | ||||
|         // Randomness | ||||
|         await expect(page.locator('.c-form__section div:nth-child(9) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']); | ||||
|  | ||||
|         // Verify that by removing value from required text field shows invalid indicator | ||||
|         await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill(''); | ||||
|         await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(['c-form-row__state-indicator  req invalid']); | ||||
|  | ||||
|         // Verify that by adding value to empty required text field changes invalid to valid indicator | ||||
|         await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill('non empty'); | ||||
|         await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(['c-form-row__state-indicator  req valid']); | ||||
|  | ||||
|         // Verify that by removing value from required number field shows invalid indicator | ||||
|         await page.locator('.field.control.l-input-sm input').first().fill(''); | ||||
|         await expect(page.locator('.c-form__section div:nth-child(4) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req invalid']); | ||||
|  | ||||
|         // Verify that by adding value to empty required number field changes invalid to valid indicator | ||||
|         await page.locator('.field.control.l-input-sm input').first().fill('3'); | ||||
|         await expect(page.locator('.c-form__section div:nth-child(4) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req valid']); | ||||
|  | ||||
|         // Verify that can change value of number field by up/down arrows keys | ||||
|         // Click .field.control.l-input-sm input >> nth=0 | ||||
|         await page.locator('.field.control.l-input-sm input').first().click(); | ||||
|         // Press ArrowUp 3 times to change value from 3 to 6 | ||||
|         await page.locator('.field.control.l-input-sm input').first().press('ArrowUp'); | ||||
|         await page.locator('.field.control.l-input-sm input').first().press('ArrowUp'); | ||||
|         await page.locator('.field.control.l-input-sm input').first().press('ArrowUp'); | ||||
|  | ||||
|         const value = await page.locator('.field.control.l-input-sm input').first().inputValue(); | ||||
|         await expect(value).toBe('6'); | ||||
|  | ||||
|         // Click .c-form-row__state-indicator.grows | ||||
|         await page.locator('.c-form-row__state-indicator.grows').click(); | ||||
|  | ||||
|         // Click text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"] | ||||
|         await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').click(); | ||||
|  | ||||
|         // Click .c-form-row__state-indicator >> nth=0 | ||||
|         await page.locator('.c-form-row__state-indicator').first().click(); | ||||
|  | ||||
|         // Fill text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"] | ||||
|         await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill('New Sine Wave Generator'); | ||||
|  | ||||
|         // Double click div:nth-child(4) .form-row .c-form-row__controls | ||||
|         await page.locator('div:nth-child(4) .form-row .c-form-row__controls').dblclick(); | ||||
|  | ||||
|         // Click .field.control.l-input-sm input >> nth=0 | ||||
|         await page.locator('.field.control.l-input-sm input').first().click(); | ||||
|  | ||||
|         // Click div:nth-child(4) .form-row .c-form-row__state-indicator | ||||
|         await page.locator('div:nth-child(4) .form-row .c-form-row__state-indicator').click(); | ||||
|  | ||||
|         // Click .field.control.l-input-sm input >> nth=0 | ||||
|         await page.locator('.field.control.l-input-sm input').first().click(); | ||||
|  | ||||
|         // Click .field.control.l-input-sm input >> nth=0 | ||||
|         await page.locator('.field.control.l-input-sm input').first().click(); | ||||
|  | ||||
|         // Click div:nth-child(5) .form-row .c-form-row__controls .form-control .field input | ||||
|         await page.locator('div:nth-child(5) .form-row .c-form-row__controls .form-control .field input').click(); | ||||
|  | ||||
|         // Click div:nth-child(5) .form-row .c-form-row__controls .form-control .field input | ||||
|         await page.locator('div:nth-child(5) .form-row .c-form-row__controls .form-control .field input').click(); | ||||
|  | ||||
|         // Click div:nth-child(5) .form-row .c-form-row__controls .form-control .field input | ||||
|         await page.locator('div:nth-child(5) .form-row .c-form-row__controls .form-control .field input').click(); | ||||
|  | ||||
|         // Click div:nth-child(6) .form-row .c-form-row__controls .form-control .field input | ||||
|         await page.locator('div:nth-child(6) .form-row .c-form-row__controls .form-control .field input').click(); | ||||
|  | ||||
|         // Double click div:nth-child(7) .form-row .c-form-row__controls .form-control .field input | ||||
|         await page.locator('div:nth-child(7) .form-row .c-form-row__controls .form-control .field input').dblclick(); | ||||
|  | ||||
|         // Click div:nth-child(7) .form-row .c-form-row__state-indicator | ||||
|         await page.locator('div:nth-child(7) .form-row .c-form-row__state-indicator').click(); | ||||
|  | ||||
|         // Click div:nth-child(7) .form-row .c-form-row__controls .form-control .field input | ||||
|         await page.locator('div:nth-child(7) .form-row .c-form-row__controls .form-control .field input').click(); | ||||
|  | ||||
|         // Fill div:nth-child(7) .form-row .c-form-row__controls .form-control .field input | ||||
|         await page.locator('div:nth-child(7) .form-row .c-form-row__controls .form-control .field input').fill('3'); | ||||
|  | ||||
|         //Click text=OK | ||||
|         await Promise.all([ | ||||
|             page.waitForNavigation(), | ||||
|             page.click('text=OK') | ||||
|         ]); | ||||
|  | ||||
|         // Verify that the Sine Wave Generator is displayed and correct | ||||
|         // Verify object properties | ||||
|         await expect(page.locator('.l-browse-bar__object-name')).toContainText('New Sine Wave Generator'); | ||||
|  | ||||
|         // Verify canvas rendered | ||||
|         await page.locator('canvas').nth(1).click({ | ||||
|             position: { | ||||
|                 x: 341, | ||||
|                 y: 28 | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -19,32 +19,24 @@ | ||||
|  * 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'; | ||||
| 
 | ||||
| describe("the plugin", () => { | ||||
|     const NON_EDITABLE_FOLDER_KEY = 'noneditable.folder'; | ||||
|     let openmct; | ||||
| /* | ||||
| This test suite is dedicated to tests which verify the basic operations surrounding moving objects. | ||||
| */ | ||||
| 
 | ||||
|     beforeEach((done) => { | ||||
|         openmct = createOpenMct(); | ||||
|         openmct.install(openmct.plugins.NonEditableFolder()); | ||||
| const { test, expect } = require('@playwright/test'); | ||||
| 
 | ||||
|         openmct.on('start', done); | ||||
|         openmct.startHeadless(); | ||||
| test.describe('Move item tests', () => { | ||||
|     test.fixme('Create a basic object and verify that it can be moved to another Folder', async ({ page }) => { | ||||
|         //Create and save Folder
 | ||||
|         //Create and save Domain Object
 | ||||
|         //Verify that the newly created domain object can be moved to Folder from Step 1.
 | ||||
|         //Verify that newly moved object appears in the correct point in Tree
 | ||||
|         //Verify that newly moved object appears correctly in Inspector panel
 | ||||
|     }); | ||||
| 
 | ||||
|     afterEach(() => { | ||||
|         return resetApplicationState(openmct); | ||||
|     test.fixme('Create a basic object and verify that it cannot be moved to object without Composition Provider', async ({ page }) => { | ||||
|         //Create and save Telemetry Object
 | ||||
|         //Create and save Domain Object
 | ||||
|         //Verify that the newly created domain object cannot be moved to Telemetry Object from step 1.
 | ||||
|     }); | ||||
| 
 | ||||
|     it('adds the new non-editable folder type', () => { | ||||
|         const type = openmct.types.get(NON_EDITABLE_FOLDER_KEY); | ||||
| 
 | ||||
|         expect(type).toBeDefined(); | ||||
|         expect(type.definition.creatable).toBeFalse(); | ||||
|     }); | ||||
| 
 | ||||
| }); | ||||
							
								
								
									
										27
									
								
								e2e/tests/persistence/addNoneditableObject.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								e2e/tests/persistence/addNoneditableObject.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| (function () { | ||||
|     document.addEventListener('DOMContentLoaded', () => { | ||||
|         const PERSISTENCE_KEY = 'persistence-tests'; | ||||
|         const openmct = window.openmct; | ||||
|  | ||||
|         openmct.objects.addRoot({ | ||||
|             namespace: PERSISTENCE_KEY, | ||||
|             key: PERSISTENCE_KEY | ||||
|         }); | ||||
|  | ||||
|         openmct.objects.addProvider(PERSISTENCE_KEY, { | ||||
|             get(identifier) { | ||||
|                 if (identifier.key !== PERSISTENCE_KEY) { | ||||
|                     return undefined; | ||||
|                 } else { | ||||
|                     return Promise.resolve({ | ||||
|                         identifier, | ||||
|                         type: 'folder', | ||||
|                         name: 'Persistence Testing', | ||||
|                         location: 'ROOT', | ||||
|                         composition: [] | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| }()); | ||||
							
								
								
									
										77
									
								
								e2e/tests/persistence/persistability.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								e2e/tests/persistence/persistability.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| /* | ||||
| This test suite is dedicated to tests which verify the basic operations surrounding conditionSets. | ||||
| */ | ||||
|  | ||||
| const { test, expect } = require('@playwright/test'); | ||||
| const path = require('path'); | ||||
|  | ||||
| // https://github.com/nasa/openmct/issues/4323#issuecomment-1067282651 | ||||
|  | ||||
| test.describe('Persistence operations', () => { | ||||
|     // add non persistable root item | ||||
|     test.beforeEach(async ({ page }) => { | ||||
|         // eslint-disable-next-line no-undef | ||||
|         await page.addInitScript({ path: path.join(__dirname, 'addNoneditableObject.js') }); | ||||
|     }); | ||||
|  | ||||
|     test('Persistability should be respected in the create form location field', async ({ page }) => { | ||||
|         // Go to baseURL | ||||
|         await page.goto('/', { waitUntil: 'networkidle' }); | ||||
|  | ||||
|         // Click the Create button | ||||
|         await page.click('button:has-text("Create")'); | ||||
|  | ||||
|         // Click text=Condition Set | ||||
|         await page.click('text=Condition Set'); | ||||
|  | ||||
|         // Click form[name="mctForm"] >> text=Persistence Testing | ||||
|         await page.locator('form[name="mctForm"] >> text=Persistence Testing').click(); | ||||
|  | ||||
|         // Check that "OK" button is disabled | ||||
|         const okButton = page.locator('button:has-text("OK")'); | ||||
|         await expect(okButton).toBeDisabled(); | ||||
|     }); | ||||
|     test('Non-persistable objects should not show persistence related actions', async ({ page }) => { | ||||
|         // Go to baseURL | ||||
|         await page.goto('/', { waitUntil: 'networkidle' }); | ||||
|  | ||||
|         // Click text=Persistence Testing >> nth=0 | ||||
|         await page.locator('text=Persistence Testing').first().click({ | ||||
|             button: 'right' | ||||
|         }); | ||||
|  | ||||
|         const menuOptions = page.locator('.c-menu ul'); | ||||
|  | ||||
|         await expect.soft(menuOptions).toContainText(['Open In New Tab', 'View', 'Create Link']); | ||||
|         await expect(menuOptions).not.toContainText(['Move', 'Duplicate', 'Remove', 'Add New Folder', 'Edit Properties...', 'Export as JSON', 'Import from JSON']); | ||||
|     }); | ||||
|     test.fixme('Cannot move a previously created domain object to non-peristable boject in Move Modal', async ({ page }) => { | ||||
|         //Create a domain object | ||||
|         //Save Domain object | ||||
|         //Move Object and verify that cannot select non-persistable object | ||||
|         //Move Object to My Items | ||||
|         //Verify successful move | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										48
									
								
								e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								e2e/tests/plugins/ExportAsJSON/exportAsJson.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| /* | ||||
| This test suite is dedicated to tests which verify the basic operations surrounding exportAsJSON. | ||||
| */ | ||||
|  | ||||
| const { test, 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 }) => { | ||||
|         //Create domain object | ||||
|         //Save Domain Object | ||||
|         //Verify that the newly created domain object can be exported as JSON from the Tree | ||||
|     }); | ||||
|     test.fixme('Create a basic object and verify that it can be exported as JSON from 3 dot menu', async ({ page }) => { | ||||
|         //Create domain object | ||||
|         //Save Domain Object | ||||
|         //Verify that the newly created domain object can be exported as JSON from the 3 dot menu | ||||
|     }); | ||||
|     test.fixme('Verify that a nested Object can be exported as JSON', async ({ page }) => { | ||||
|         // Create 2 objects with hierarchy | ||||
|         // Export as JSON | ||||
|         // Verify Hiearchy | ||||
|     }); | ||||
|     test.fixme('Verify that the ExportAsJSON dropdown does not appear for the item X', async ({ page }) => { | ||||
|         // Other than non-persistible objects | ||||
|     }); | ||||
| }); | ||||
| @@ -20,14 +20,27 @@ | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
| 
 | ||||
| export default function () { | ||||
|     return function (openmct) { | ||||
|         openmct.types.addType("noneditable.folder", { | ||||
|             name: "Non-Editable Folder", | ||||
|             key: "noneditable.folder", | ||||
|             description: "Create folders to organize other objects or links to objects without the ability to edit it's properties.", | ||||
|             cssClass: "icon-folder", | ||||
|             creatable: false | ||||
|         }); | ||||
|     }; | ||||
| } | ||||
| /* | ||||
| This test suite is dedicated to tests which verify the basic operations surrounding importAsJSON. | ||||
| */ | ||||
| 
 | ||||
| const { test, expect } = require('@playwright/test'); | ||||
| 
 | ||||
| test.describe('ExportAsJSON', () => { | ||||
|     test.fixme('Verify that domain object can be importAsJSON from Tree', async ({ page }) => { | ||||
|         //Verify that an testdata JSON file can be imported from Tree
 | ||||
|         //Verify correctness of imported domain object
 | ||||
|     }); | ||||
|     test.fixme('Verify that domain object can be importAsJSON from 3 dot menu on folder', async ({ page }) => { | ||||
|         //Verify that an testdata JSON file can be imported from 3 dot menu on folder domain object
 | ||||
|         //Verify correctness of imported domain object
 | ||||
|     }); | ||||
|     test.fixme('Verify that a nested Objects can be importAsJSON', async ({ page }) => { | ||||
|         // Testdata with hierarchy
 | ||||
|         // ImportAsJSON on Tree
 | ||||
|         // Verify Hierarchy
 | ||||
|     }); | ||||
|     test.fixme('Verify that the ImportAsJSON dropdown does not appear for the item X', async ({ page }) => { | ||||
|         // Other than non-persistible objects
 | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										69
									
								
								e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| /***************************************************************************** | ||||
|  * 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| const { test, expect } = require('@playwright/test'); | ||||
|  | ||||
| test.describe('Time counductor operations', () => { | ||||
|     test('validate start time does not exceeds end time', async ({ page }) => { | ||||
|         //Go to baseURL | ||||
|         await page.goto('/', { waitUntil: 'networkidle' }); | ||||
|         const year = new Date().getFullYear(); | ||||
|  | ||||
|         let startDate = 'xxxx-01-01 01:00:00.000Z'; | ||||
|         startDate = year + startDate.substring(4); | ||||
|  | ||||
|         let endDate = 'xxxx-01-01 02:00:00.000Z'; | ||||
|         endDate = year + endDate.substring(4); | ||||
|  | ||||
|         const startTimeLocator = page.locator('input[type="text"]').first(); | ||||
|         const endTimeLocator = page.locator('input[type="text"]').nth(1); | ||||
|  | ||||
|         // Click start time | ||||
|         await startTimeLocator.click(); | ||||
|  | ||||
|         // Click end time | ||||
|         await endTimeLocator.click(); | ||||
|  | ||||
|         await endTimeLocator.fill(endDate.toString()); | ||||
|         await startTimeLocator.fill(startDate.toString()); | ||||
|  | ||||
|         // invalid start date | ||||
|         startDate = (year + 1) + startDate.substring(4); | ||||
|         await startTimeLocator.fill(startDate.toString()); | ||||
|         await endTimeLocator.click(); | ||||
|  | ||||
|         const startDateValidityStatus = await startTimeLocator.evaluate((element) => element.checkValidity()); | ||||
|         expect(startDateValidityStatus).not.toBeTruthy(); | ||||
|  | ||||
|         // fix to valid start date | ||||
|         startDate = (year - 1) + startDate.substring(4); | ||||
|         await startTimeLocator.fill(startDate.toString()); | ||||
|  | ||||
|         // invalid end date | ||||
|         endDate = (year - 2) + endDate.substring(4); | ||||
|         await endTimeLocator.fill(endDate.toString()); | ||||
|         await startTimeLocator.click(); | ||||
|  | ||||
|         const endDateValidityStatus = await endTimeLocator.evaluate((element) => element.checkValidity()); | ||||
|         expect(endDateValidityStatus).not.toBeTruthy(); | ||||
|     }); | ||||
| }); | ||||
| @@ -111,3 +111,63 @@ test('Visual - Default Condition Widget', async ({ page }) => { | ||||
|     await page.waitForTimeout(VISUAL_GRACE_PERIOD); | ||||
|     await percySnapshot(page, 'Default Condition Widget'); | ||||
| }); | ||||
|  | ||||
| test('Visual - Time Conductor start time is less than end time', async ({ page }) => { | ||||
|     //Go to baseURL | ||||
|     await page.goto('/', { waitUntil: 'networkidle' }); | ||||
|     const year = new Date().getFullYear(); | ||||
|  | ||||
|     let startDate = 'xxxx-01-01 01:00:00.000Z'; | ||||
|     startDate = year + startDate.substring(4); | ||||
|  | ||||
|     let endDate = 'xxxx-01-01 02:00:00.000Z'; | ||||
|     endDate = year + endDate.substring(4); | ||||
|  | ||||
|     await page.locator('input[type="text"]').nth(1).fill(endDate.toString()); | ||||
|     await page.locator('input[type="text"]').first().fill(startDate.toString()); | ||||
|  | ||||
|     //  verify no error msg | ||||
|     await page.waitForTimeout(VISUAL_GRACE_PERIOD); | ||||
|     await percySnapshot(page, 'Default Time conductor'); | ||||
|  | ||||
|     startDate = (year + 1) + startDate.substring(4); | ||||
|     await page.locator('input[type="text"]').first().fill(startDate.toString()); | ||||
|     await page.locator('input[type="text"]').nth(1).click(); | ||||
|  | ||||
|     //  verify error msg for start time (unable to capture snapshot of popup) | ||||
|     await page.waitForTimeout(VISUAL_GRACE_PERIOD); | ||||
|     await percySnapshot(page, 'Start time error'); | ||||
|  | ||||
|     startDate = (year - 1) + startDate.substring(4); | ||||
|     await page.locator('input[type="text"]').first().fill(startDate.toString()); | ||||
|  | ||||
|     endDate = (year - 2) + endDate.substring(4); | ||||
|     await page.locator('input[type="text"]').nth(1).fill(endDate.toString()); | ||||
|  | ||||
|     await page.locator('input[type="text"]').first().click(); | ||||
|  | ||||
|     //  verify error msg for end time (unable to capture snapshot of popup) | ||||
|     await page.waitForTimeout(VISUAL_GRACE_PERIOD); | ||||
|     await percySnapshot(page, 'End time error'); | ||||
| }); | ||||
|  | ||||
| test('Visual - Sine Wave Generator Form', async ({ page }) => { | ||||
|     //Go to baseURL | ||||
|     await page.goto('/', { waitUntil: 'networkidle' }); | ||||
|  | ||||
|     //Click the Create button | ||||
|     await page.click('button:has-text("Create")'); | ||||
|  | ||||
|     // Click text=Sine Wave Generator | ||||
|     await page.click('text=Sine Wave Generator'); | ||||
|  | ||||
|     await page.waitForTimeout(VISUAL_GRACE_PERIOD); | ||||
|     await percySnapshot(page, 'Default Sine Wave Generator Form'); | ||||
|  | ||||
|     await page.locator('.field.control.l-input-sm input').first().click(); | ||||
|     await page.locator('.field.control.l-input-sm input').first().fill(''); | ||||
|  | ||||
|     // Validate red x mark | ||||
|     await page.waitForTimeout(VISUAL_GRACE_PERIOD); | ||||
|     await percySnapshot(page, 'removed amplitude property value'); | ||||
| }); | ||||
|   | ||||
| @@ -33,7 +33,7 @@ class EventTelemetryProvider { | ||||
|  | ||||
|     generateData(firstObservedTime, count, startTime, duration, name) { | ||||
|         const millisecondsSinceStart = startTime - firstObservedTime; | ||||
|         const utc = Math.floor(startTime / duration) * duration; | ||||
|         const utc = startTime + (count * duration); | ||||
|         const ind = count % messages.length; | ||||
|         const message = messages[ind] + " - [" + millisecondsSinceStart + "]"; | ||||
|  | ||||
| @@ -75,7 +75,7 @@ class EventTelemetryProvider { | ||||
|         const duration = domainObject.telemetry.duration * 1000; | ||||
|         const size = options.size ? options.size : this.defaultSize; | ||||
|         const data = []; | ||||
|         const firstObservedTime = Date.now(); | ||||
|         const firstObservedTime = options.start; | ||||
|         let count = 0; | ||||
|  | ||||
|         if (options.strategy === 'latest' || options.size === 1) { | ||||
| @@ -83,7 +83,7 @@ class EventTelemetryProvider { | ||||
|         } | ||||
|  | ||||
|         while (start <= end && data.length < size) { | ||||
|             const startTime = Date.now() + count; | ||||
|             const startTime = options.start + count; | ||||
|             data.push(this.generateData(firstObservedTime, count, startTime, duration, domainObject.name)); | ||||
|             start += duration; | ||||
|             count += 1; | ||||
|   | ||||
| @@ -35,6 +35,7 @@ describe('the plugin', () => { | ||||
|         telemetry: { | ||||
|             duration: 0 | ||||
|         }, | ||||
|         options: {}, | ||||
|         type: 'eventGenerator' | ||||
|     }; | ||||
|  | ||||
| @@ -61,7 +62,13 @@ describe('the plugin', () => { | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         it("supports requests", async () => { | ||||
|         it("supports requests without start/end defined", async () => { | ||||
|             const telemetry = await openmct.telemetry.request(mockDomainObject); | ||||
|             expect(telemetry[0].message).toContain('CC: Eagle, Houston'); | ||||
|         }); | ||||
|  | ||||
|         it("supports requests with arbitrary start time in the past", async () => { | ||||
|             mockDomainObject.options.start = 100000000000; // Mar 03 1973 | ||||
|             const telemetry = await openmct.telemetry.request(mockDomainObject); | ||||
|             expect(telemetry[0].message).toContain('CC: Eagle, Houston'); | ||||
|         }); | ||||
|   | ||||
| @@ -26,7 +26,7 @@ import { | ||||
| } from '../../src/utils/testing'; | ||||
| import ExampleUserProvider from './ExampleUserProvider'; | ||||
|  | ||||
| describe("The Example User Plugin", () => { | ||||
| xdescribe("The Example User Plugin", () => { | ||||
|     let openmct; | ||||
|  | ||||
|     beforeEach(() => { | ||||
|   | ||||
| @@ -1,3 +1,2 @@ | ||||
| const testsContext = require.context('.', true, /\/(src|platform|\.\/example)\/.*Spec.js$/); | ||||
|  | ||||
| const testsContext = require.context('.', true, /^\.\/(src|example)\/.*Spec.js$/); | ||||
| testsContext.keys().forEach(testsContext); | ||||
|   | ||||
| @@ -22,29 +22,9 @@ | ||||
|  | ||||
| /*global module,process*/ | ||||
|  | ||||
| const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless']; | ||||
| const coverageEnabled = process.env.COVERAGE === 'true'; | ||||
| const reporters = ['spec', 'junit']; | ||||
|  | ||||
| if (coverageEnabled) { | ||||
|     reporters.push('coverage-istanbul'); | ||||
| } | ||||
|  | ||||
| module.exports = (config) => { | ||||
|     const webpackConfig = require('./webpack.dev.js'); | ||||
|     const webpackConfig = require('./webpack.coverage.js'); | ||||
|     delete webpackConfig.output; | ||||
|     if (coverageEnabled) { | ||||
|         webpackConfig.module.rules.push({ | ||||
|             test: /\.js$/, | ||||
|             exclude: /node_modules|e2e|example|lib|dist|\.*.*Spec\.js/, | ||||
|             use: { | ||||
|                 loader: 'istanbul-instrumenter-loader', | ||||
|                 options: { | ||||
|                     esModules: true | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     config.set({ | ||||
|         basePath: '', | ||||
| @@ -61,8 +41,8 @@ module.exports = (config) => { | ||||
|             } | ||||
|         ], | ||||
|         port: 9876, | ||||
|         reporters: reporters, | ||||
|         browsers: browsers, | ||||
|         reporters: ['spec', 'junit', 'coverage-istanbul'], | ||||
|         browsers: [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless'], | ||||
|         client: { | ||||
|             jasmine: { | ||||
|                 random: false, | ||||
| @@ -78,17 +58,27 @@ module.exports = (config) => { | ||||
|             FirefoxESR: { | ||||
|                 base: 'FirefoxHeadless', | ||||
|                 name: 'FirefoxESR' | ||||
|             }, | ||||
|             PlaywrightChrome: { | ||||
|                 base: 'ChromiumHeadless' | ||||
|             }, | ||||
|             PlaywrightSafari: { | ||||
|                 base: 'WebKitHeadless' | ||||
|             }, | ||||
|             PlaywrightChromeCanary: { | ||||
|                 base: 'ChromiumHeadless', | ||||
|                 launchOptions: { | ||||
|                     channel: 'chrome-canary' | ||||
|                 } | ||||
|             }, | ||||
|             PlaywrightFirefox: { | ||||
|                 base: 'FirefoxHeadless', | ||||
|                 debug: true | ||||
|             } | ||||
|         }, | ||||
|         colors: true, | ||||
|         logLevel: config.LOG_INFO, | ||||
|         autoWatch: true, | ||||
|         // HTML test reporting. | ||||
|         // htmlReporter: { | ||||
|         //    outputDir: "dist/reports/tests", | ||||
|         //    preserveDescribeNesting: true, | ||||
|         //    foldAll: false | ||||
|         // }, | ||||
|         junitReporter: { | ||||
|             outputDir: "dist/reports/tests", | ||||
|             outputFile: "test-results.xml", | ||||
| @@ -96,9 +86,7 @@ module.exports = (config) => { | ||||
|         }, | ||||
|         coverageIstanbulReporter: { | ||||
|             fixWebpackSourcePaths: true, | ||||
|             dir: process.env.CIRCLE_ARTIFACTS | ||||
|                 ? process.env.CIRCLE_ARTIFACTS + '/coverage' | ||||
|                 : "dist/reports/coverage", | ||||
|             dir: "dist/reports/coverage", | ||||
|             reports: ['lcovonly', 'text-summary'], | ||||
|             thresholds: { | ||||
|                 global: { | ||||
| @@ -115,6 +103,10 @@ module.exports = (config) => { | ||||
|             showSpecTiming: true, | ||||
|             failFast: false | ||||
|         }, | ||||
|         plugins: [ | ||||
|             'karma-*', | ||||
|             '@onslip/karma-playwright-launcher' | ||||
|         ], | ||||
|         preprocessors: { | ||||
|             'indexTest.js': ['webpack', 'sourcemap'] | ||||
|         }, | ||||
|   | ||||
							
								
								
									
										67
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								package.json
									
									
									
									
									
								
							| @@ -3,35 +3,38 @@ | ||||
|   "version": "2.0.1-SNAPSHOT", | ||||
|   "description": "The Open MCT core platform", | ||||
|   "devDependencies": { | ||||
|     "@babel/eslint-parser": "7.16.3", | ||||
|     "@braintree/sanitize-url": "6.0.0", | ||||
|     "@onslip/karma-playwright-launcher": "0.2.1", | ||||
|     "@percy/cli": "1.0.0-beta.75", | ||||
|     "@percy/playwright": "1.0.1", | ||||
|     "@playwright/test": "1.19.2", | ||||
|     "allure-playwright": "2.0.0-beta.15", | ||||
|     "babel-eslint": "10.1.0", | ||||
|     "babel-loader": "8.2.3", | ||||
|     "babel-plugin-istanbul": "6.1.1", | ||||
|     "comma-separated-values": "3.6.4", | ||||
|     "copy-webpack-plugin": "10.2.0", | ||||
|     "core-js": "3.20.3", | ||||
|     "core-js": "3.21.1", | ||||
|     "cross-env": "7.0.3", | ||||
|     "css-loader": "4.0.0", | ||||
|     "d3-axis": "1.0.x", | ||||
|     "d3-scale": "1.0.x", | ||||
|     "d3-selection": "1.3.x", | ||||
|     "eslint": "7.0.0", | ||||
|     "eslint": "8.11.0", | ||||
|     "eslint-plugin-compat": "4.0.2", | ||||
|     "eslint-plugin-playwright": "0.8.0", | ||||
|     "eslint-plugin-vue": "7.5.0", | ||||
|     "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-loader": "6.1.0", | ||||
|     "file-loader": "6.2.0", | ||||
|     "file-saver": "2.0.5", | ||||
|     "git-rev-sync": "1.4.0", | ||||
|     "git-rev-sync": "3.0.2", | ||||
|     "html-loader": "0.5.5", | ||||
|     "html2canvas": "1.4.1", | ||||
|     "imports-loader": "0.8.0", | ||||
|     "istanbul-instrumenter-loader": "^3.0.1", | ||||
|     "jasmine-core": "4.0.0", | ||||
|     "jasmine-core": "4.0.1", | ||||
|     "jsdoc": "3.5.5", | ||||
|     "karma": "6.3.15", | ||||
|     "karma-chrome-launcher": "3.1.0", | ||||
| @@ -43,36 +46,36 @@ | ||||
|     "karma-junit-reporter": "2.0.1", | ||||
|     "karma-sourcemap-loader": "0.3.8", | ||||
|     "karma-spec-reporter": "0.0.33", | ||||
|     "karma-webpack": "^5.0.0", | ||||
|     "location-bar": "^3.0.1", | ||||
|     "lodash": "^4.17.12", | ||||
|     "karma-webpack": "5.0.0", | ||||
|     "location-bar": "3.0.1", | ||||
|     "lodash": "4.17.12", | ||||
|     "mini-css-extract-plugin": "2.4.5", | ||||
|     "moment": "2.29.1", | ||||
|     "moment-duration-format": "^2.2.2", | ||||
|     "moment-duration-format": "2.2.2", | ||||
|     "moment-timezone": "0.5.28", | ||||
|     "node-bourbon": "^4.2.3", | ||||
|     "painterro": "^1.2.56", | ||||
|     "plotly.js-basic-dist": "^2.5.0", | ||||
|     "plotly.js-gl2d-dist": "^2.5.0", | ||||
|     "printj": "^1.2.1", | ||||
|     "raw-loader": "^0.5.1", | ||||
|     "request": "^2.69.0", | ||||
|     "node-bourbon": "4.2.3", | ||||
|     "painterro": "1.2.56", | ||||
|     "plotly.js-basic-dist": "2.5.0", | ||||
|     "plotly.js-gl2d-dist": "2.5.0", | ||||
|     "printj": "1.3.1", | ||||
|     "raw-loader": "4.0.2", | ||||
|     "request": "2.69.0", | ||||
|     "resolve-url-loader": "4.0.0", | ||||
|     "sass": "1.49.0", | ||||
|     "sass-loader": "12.4.0", | ||||
|     "sinon": "13.0.1", | ||||
|     "style-loader": "^1.0.1", | ||||
|     "uuid": "^3.3.3", | ||||
|     "uuid": "3.3.3", | ||||
|     "vue": "2.6.14", | ||||
|     "vue-eslint-parser": "8.2.0", | ||||
|     "vue-loader": "15.9.8", | ||||
|     "vue-template-compiler": "2.6.14", | ||||
|     "webpack": "5.68.0", | ||||
|     "webpack-cli": "4.9.2", | ||||
|     "webpack-dev-middleware": "^3.1.3", | ||||
|     "webpack-hot-middleware": "^2.22.3", | ||||
|     "webpack-dev-middleware": "3.7.3", | ||||
|     "webpack-hot-middleware": "2.22.3", | ||||
|     "webpack-merge": "5.8.0", | ||||
|     "zepto": "^1.2.0" | ||||
|     "zepto": "1.2.0" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "clean": "rm -rf ./dist ./node_modules; rm package-lock.json", | ||||
| @@ -82,14 +85,19 @@ | ||||
|     "lint:fix": "eslint example src --ext .js,.vue openmct.js --fix", | ||||
|     "build:prod": "cross-env webpack --config webpack.prod.js", | ||||
|     "build:dev": "webpack --config webpack.dev.js", | ||||
|     "build:coverage": "webpack --config webpack.coverage.js", | ||||
|     "build:watch": "webpack --config webpack.dev.js --watch", | ||||
|     "info": "npx envinfo --system --browsers --npmPackages --binaries --languages --markdown", | ||||
|     "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:coverage": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" COVERAGE=true karma start --single-run", | ||||
|     "test:coverage:firefox": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=FirefoxHeadless", | ||||
|     "test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke default condition.e2e", | ||||
|     "test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js", | ||||
|     "test:coverage:pw": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" COVERAGE=true karma start --single-run --browsers=PlaywrightChrome", | ||||
|     "test:coverage:pwsafari": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" COVERAGE=true karma start --single-run --browsers=PlaywrightSafari", | ||||
|     "test:coverage:pwcanary": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" COVERAGE=true karma start --single-run --browsers=PlaywrightChromeCanary", | ||||
|     "test:coverage:pwfirefox": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=PlaywrightFirefox", | ||||
|     "test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke default condition timeConductor", | ||||
|     "test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome", | ||||
|     "test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js default", | ||||
|     "test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js", | ||||
|     "test:watch": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --no-single-run", | ||||
| @@ -107,6 +115,13 @@ | ||||
|   "engines": { | ||||
|     "node": ">=12.22.0" | ||||
|   }, | ||||
|   "browserslist": [ | ||||
|     "Firefox ESR", | ||||
|     "not IE 11", | ||||
|     "last 2 Chrome versions", | ||||
|     "unreleased Chrome versions", | ||||
|     "ios_saf > 15" | ||||
|   ], | ||||
|   "author": "", | ||||
|   "license": "Apache-2.0", | ||||
|   "private": true | ||||
|   | ||||
| @@ -269,7 +269,6 @@ define([ | ||||
|         this.install(this.plugins.ViewDatumAction()); | ||||
|         this.install(this.plugins.ViewLargeAction()); | ||||
|         this.install(this.plugins.ObjectInterceptors()); | ||||
|         this.install(this.plugins.NonEditableFolder()); | ||||
|         this.install(this.plugins.DeviceClassifier()); | ||||
|         this.install(this.plugins.UserIndicator()); | ||||
|     } | ||||
|   | ||||
| @@ -26,45 +26,52 @@ | ||||
|         <div class="c-overlay__dialog-title">{{ model.title }}</div> | ||||
|         <div class="c-overlay__dialog-hint hint">All fields marked <span class="req icon-asterisk"></span> are required.</div> | ||||
|     </div> | ||||
|     <form name="mctForm" | ||||
|           class="c-form__contents" | ||||
|           autocomplete="off" | ||||
|           @submit.prevent | ||||
|     <form | ||||
|         name="mctForm" | ||||
|         class="c-form__contents" | ||||
|         autocomplete="off" | ||||
|         @submit.prevent | ||||
|     > | ||||
|         <div v-for="section in formSections" | ||||
|              :key="section.id" | ||||
|              class="c-form__section" | ||||
|              :class="section.cssClass" | ||||
|         <div | ||||
|             v-for="section in formSections" | ||||
|             :key="section.id" | ||||
|             class="c-form__section" | ||||
|             :class="section.cssClass" | ||||
|         > | ||||
|             <h2 v-if="section.name" | ||||
|             <h2 | ||||
|                 v-if="section.name" | ||||
|                 class="c-form__section-header" | ||||
|             > | ||||
|                 {{ section.name }} | ||||
|             </h2> | ||||
|             <div v-for="(row, index) in section.rows" | ||||
|                  :key="row.id" | ||||
|                  class="u-contents" | ||||
|             <div | ||||
|                 v-for="(row, index) in section.rows" | ||||
|                 :key="row.id" | ||||
|                 class="u-contents" | ||||
|             > | ||||
|                 <FormRow :css-class="section.cssClass" | ||||
|                          :first="index < 1" | ||||
|                          :row="row" | ||||
|                          @onChange="onChange" | ||||
|                 <FormRow | ||||
|                     :css-class="section.cssClass" | ||||
|                     :first="index < 1" | ||||
|                     :row="row" | ||||
|                     @onChange="onChange" | ||||
|                 /> | ||||
|             </div> | ||||
|         </div> | ||||
|     </form> | ||||
|  | ||||
|     <div class="mct-form__controls c-overlay__button-bar c-form__bottom-bar"> | ||||
|         <button tabindex="0" | ||||
|                 :disabled="isInvalid" | ||||
|                 class="c-button c-button--major" | ||||
|                 @click="onSave" | ||||
|         <button | ||||
|             tabindex="0" | ||||
|             :disabled="isInvalid" | ||||
|             class="c-button c-button--major" | ||||
|             @click="onSave" | ||||
|         > | ||||
|             {{ submitLabel }} | ||||
|         </button> | ||||
|         <button tabindex="0" | ||||
|                 class="c-button" | ||||
|                 @click="onDismiss" | ||||
|         <button | ||||
|             tabindex="0" | ||||
|             class="c-button" | ||||
|             @click="onDismiss" | ||||
|         > | ||||
|             {{ cancelLabel }} | ||||
|         </button> | ||||
|   | ||||
| @@ -21,21 +21,25 @@ | ||||
| *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <div class="form-row c-form__row" | ||||
|      :class="[{ 'first': first }]" | ||||
|      @onChange="onChange" | ||||
| <div | ||||
|     class="form-row c-form__row" | ||||
|     :class="[{ 'first': first }]" | ||||
|     @onChange="onChange" | ||||
| > | ||||
|     <div class="c-form-row__label" | ||||
|          :title="row.description" | ||||
|     <div | ||||
|         class="c-form-row__label" | ||||
|         :title="row.description" | ||||
|     > | ||||
|         {{ row.name }} | ||||
|     </div> | ||||
|     <div class="c-form-row__state-indicator" | ||||
|          :class="rowClass" | ||||
|     <div | ||||
|         class="c-form-row__state-indicator" | ||||
|         :class="rowClass" | ||||
|     > | ||||
|     </div> | ||||
|     <div v-if="row.control" | ||||
|          class="c-form-row__controls" | ||||
|     <div | ||||
|         v-if="row.control" | ||||
|         class="c-form-row__controls" | ||||
|     > | ||||
|         <div ref="rowElement"></div> | ||||
|     </div> | ||||
|   | ||||
| @@ -22,20 +22,24 @@ | ||||
|  | ||||
| <template> | ||||
| <div class="form-control autocomplete"> | ||||
|     <input v-model="field" | ||||
|            class="autocompleteInput" | ||||
|            type="text" | ||||
|            @click="inputClicked()" | ||||
|            @keydown="keyDown($event)" | ||||
|     <input | ||||
|         v-model="field" | ||||
|         class="autocompleteInput" | ||||
|         type="text" | ||||
|         @click="inputClicked()" | ||||
|         @keydown="keyDown($event)" | ||||
|     > | ||||
|     <span class="icon-arrow-down" | ||||
|           @click="arrowClicked()" | ||||
|     <span | ||||
|         class="icon-arrow-down" | ||||
|         @click="arrowClicked()" | ||||
|     ></span> | ||||
|     <div class="autocompleteOptions" | ||||
|          @blur="hideOptions = true" | ||||
|     <div | ||||
|         class="autocompleteOptions" | ||||
|         @blur="hideOptions = true" | ||||
|     > | ||||
|         <ul v-if="!hideOptions"> | ||||
|             <li v-for="opt in filteredOptions" | ||||
|             <li | ||||
|                 v-for="opt in filteredOptions" | ||||
|                 :key="opt.optionId" | ||||
|                 :class="{'optionPreSelected': optionIndex === opt.optionId}" | ||||
|                 @click="fillInputWithString(opt.name)" | ||||
|   | ||||
| @@ -22,10 +22,11 @@ | ||||
|  | ||||
| <template> | ||||
| <div class="c-form-control--clock-display-format-fields"> | ||||
|     <SelectField v-for="item in items" | ||||
|                  :key="item.key" | ||||
|                  :model="item" | ||||
|                  @onChange="onChange" | ||||
|     <SelectField | ||||
|         v-for="item in items" | ||||
|         :key="item.key" | ||||
|         :model="item" | ||||
|         @onChange="onChange" | ||||
|     /> | ||||
| </div> | ||||
| </template> | ||||
|   | ||||
| @@ -22,12 +22,13 @@ | ||||
|  | ||||
| <template> | ||||
| <span> | ||||
|     <CompositeItem v-for="(item, index) in model.items" | ||||
|                    :key="item.name" | ||||
|                    :first="index < 1" | ||||
|                    :value="JSON.stringify(model.value[index])" | ||||
|                    :item="item" | ||||
|                    @onChange="onChange" | ||||
|     <CompositeItem | ||||
|         v-for="(item, index) in model.items" | ||||
|         :key="item.name" | ||||
|         :first="index < 1" | ||||
|         :value="JSON.stringify(model.value[index])" | ||||
|         :item="item" | ||||
|         @onChange="onChange" | ||||
|     /> | ||||
| </span> | ||||
| </template> | ||||
|   | ||||
| @@ -22,10 +22,11 @@ | ||||
|  | ||||
| <template> | ||||
| <div :class="compositeCssClass"> | ||||
|     <FormRow :css-class="item.cssClass" | ||||
|              :first="first" | ||||
|              :row="row" | ||||
|              @onChange="onChange" | ||||
|     <FormRow | ||||
|         :css-class="item.cssClass" | ||||
|         :first="first" | ||||
|         :row="row" | ||||
|         @onChange="onChange" | ||||
|     /> | ||||
|     <span class="composite-control-label"> | ||||
|         {{ item.name }} | ||||
|   | ||||
| @@ -27,50 +27,55 @@ | ||||
|     <div class="hint time sm">Min</div> | ||||
|     <div class="hint time sm">Sec</div> | ||||
|     <div class="hint timezone">Timezone</div> | ||||
|     <form ref="dateTimeForm" | ||||
|           prevent | ||||
|           class="u-contents" | ||||
|     <form | ||||
|         ref="dateTimeForm" | ||||
|         prevent | ||||
|         class="u-contents" | ||||
|     > | ||||
|         <div class="field control date"> | ||||
|             <input v-model="date" | ||||
|                    :pattern="/\d{4}-\d{2}-\d{2}/" | ||||
|                    :placeholder="format" | ||||
|                    type="date" | ||||
|                    name="date" | ||||
|                    @change="onChange" | ||||
|             <input | ||||
|                 v-model="date" | ||||
|                 :pattern="/\d{4}-\d{2}-\d{2}/" | ||||
|                 :placeholder="format" | ||||
|                 type="date" | ||||
|                 name="date" | ||||
|                 @change="onChange" | ||||
|             > | ||||
|         </div> | ||||
|         <div class="field control hour sm"> | ||||
|             <input v-model="hour" | ||||
|                    :pattern="/\d+/" | ||||
|                    type="number" | ||||
|                    name="hour" | ||||
|                    maxlength="10" | ||||
|                    min="0" | ||||
|                    max="23" | ||||
|                    @change="onChange" | ||||
|             <input | ||||
|                 v-model="hour" | ||||
|                 :pattern="/\d+/" | ||||
|                 type="number" | ||||
|                 name="hour" | ||||
|                 maxlength="10" | ||||
|                 min="0" | ||||
|                 max="23" | ||||
|                 @change="onChange" | ||||
|             > | ||||
|         </div> | ||||
|         <div class="field control min sm"> | ||||
|             <input v-model="min" | ||||
|                    :pattern="/\d+/" | ||||
|                    type="number" | ||||
|                    name="min" | ||||
|                    maxlength="2" | ||||
|                    min="0" | ||||
|                    max="59" | ||||
|                    @change="onChange" | ||||
|             <input | ||||
|                 v-model="min" | ||||
|                 :pattern="/\d+/" | ||||
|                 type="number" | ||||
|                 name="min" | ||||
|                 maxlength="2" | ||||
|                 min="0" | ||||
|                 max="59" | ||||
|                 @change="onChange" | ||||
|             > | ||||
|         </div> | ||||
|         <div class="field control sec sm"> | ||||
|             <input v-model="sec" | ||||
|                    :pattern="/\d+/" | ||||
|                    type="number" | ||||
|                    name="sec" | ||||
|                    maxlength="2" | ||||
|                    min="0" | ||||
|                    max="59" | ||||
|                    @change="onChange" | ||||
|             <input | ||||
|                 v-model="sec" | ||||
|                 :pattern="/\d+/" | ||||
|                 type="number" | ||||
|                 name="sec" | ||||
|                 maxlength="2" | ||||
|                 min="0" | ||||
|                 max="59" | ||||
|                 @change="onChange" | ||||
|             > | ||||
|         </div> | ||||
|         <div class="field control timezone"> | ||||
|   | ||||
| @@ -22,18 +22,21 @@ | ||||
|  | ||||
| <template> | ||||
| <span class="form-control shell"> | ||||
|     <span class="field control" | ||||
|           :class="model.cssClass" | ||||
|     <span | ||||
|         class="field control" | ||||
|         :class="model.cssClass" | ||||
|     > | ||||
|         <input id="fileElem" | ||||
|                ref="fileInput" | ||||
|                type="file" | ||||
|                accept=".json" | ||||
|                style="display:none" | ||||
|         <input | ||||
|             id="fileElem" | ||||
|             ref="fileInput" | ||||
|             type="file" | ||||
|             accept=".json" | ||||
|             style="display:none" | ||||
|         > | ||||
|         <button id="fileSelect" | ||||
|                 class="c-button" | ||||
|                 @click="selectFile" | ||||
|         <button | ||||
|             id="fileSelect" | ||||
|             class="c-button" | ||||
|             @click="selectFile" | ||||
|         > | ||||
|             {{ name }} | ||||
|         </button> | ||||
|   | ||||
| @@ -22,21 +22,25 @@ | ||||
|  | ||||
| <template> | ||||
| <span class="form-control shell"> | ||||
|     <span class="field control" | ||||
|           :class="model.cssClass" | ||||
|     <span | ||||
|         class="field control" | ||||
|         :class="model.cssClass" | ||||
|     > | ||||
|         <input v-model="field" | ||||
|                type="number" | ||||
|                :min="model.min" | ||||
|                :max="model.max" | ||||
|                :step="model.step" | ||||
|                @blur="blur()" | ||||
|         <input | ||||
|             v-model="field" | ||||
|             type="number" | ||||
|             :min="model.min" | ||||
|             :max="model.max" | ||||
|             :step="model.step" | ||||
|             @input="updateText()" | ||||
|         > | ||||
|     </span> | ||||
| </span> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { throttle } from 'lodash'; | ||||
|  | ||||
| export default { | ||||
|     props: { | ||||
|         model: { | ||||
| @@ -49,8 +53,12 @@ export default { | ||||
|             field: this.model.value | ||||
|         }; | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.updateText = throttle(this.updateText.bind(this), 200); | ||||
|     }, | ||||
|     methods: { | ||||
|         blur() { | ||||
|         updateText() { | ||||
|             console.log('updateText', this.field); | ||||
|             const data = { | ||||
|                 model: this.model, | ||||
|                 value: this.field | ||||
|   | ||||
| @@ -22,14 +22,16 @@ | ||||
|  | ||||
| <template> | ||||
| <div class="form-control select-field"> | ||||
|     <select v-model="selected" | ||||
|             required="model.required" | ||||
|             name="mctControl" | ||||
|             @change="onChange($event)" | ||||
|     <select | ||||
|         v-model="selected" | ||||
|         required="model.required" | ||||
|         name="mctControl" | ||||
|         @change="onChange($event)" | ||||
|     > | ||||
|         <option v-for="option in model.options" | ||||
|                 :key="option.name" | ||||
|                 :value="option.value" | ||||
|         <option | ||||
|             v-for="option in model.options" | ||||
|             :key="option.name" | ||||
|             :value="option.value" | ||||
|         > | ||||
|             {{ option.name }} | ||||
|         </option> | ||||
|   | ||||
| @@ -22,13 +22,15 @@ | ||||
|  | ||||
| <template> | ||||
| <span class="form-control shell"> | ||||
|     <span class="field control" | ||||
|           :class="model.cssClass" | ||||
|     <span | ||||
|         class="field control" | ||||
|         :class="model.cssClass" | ||||
|     > | ||||
|         <textarea v-model="field" | ||||
|                   type="text" | ||||
|                   :size="model.size" | ||||
|                   @blur="blur()" | ||||
|         <textarea | ||||
|             v-model="field" | ||||
|             type="text" | ||||
|             :size="model.size" | ||||
|             @input="updateText()" | ||||
|         > | ||||
|         </textarea> | ||||
|     </span> | ||||
| @@ -36,6 +38,8 @@ | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { throttle } from 'lodash'; | ||||
|  | ||||
| export default { | ||||
|     props: { | ||||
|         model: { | ||||
| @@ -48,8 +52,11 @@ export default { | ||||
|             field: this.model.value | ||||
|         }; | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.updateText = throttle(this.updateText.bind(this), 500); | ||||
|     }, | ||||
|     methods: { | ||||
|         blur() { | ||||
|         updateText() { | ||||
|             const data = { | ||||
|                 model: this.model, | ||||
|                 value: this.field | ||||
|   | ||||
| @@ -22,19 +22,23 @@ | ||||
|  | ||||
| <template> | ||||
| <span class="form-control shell"> | ||||
|     <span class="field control" | ||||
|           :class="model.cssClass" | ||||
|     <span | ||||
|         class="field control" | ||||
|         :class="model.cssClass" | ||||
|     > | ||||
|         <input v-model="field" | ||||
|                type="text" | ||||
|                :size="model.size" | ||||
|                @blur="blur()" | ||||
|         <input | ||||
|             v-model="field" | ||||
|             type="text" | ||||
|             :size="model.size" | ||||
|             @input="updateText()" | ||||
|         > | ||||
|     </span> | ||||
| </span> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { throttle } from 'lodash'; | ||||
|  | ||||
| export default { | ||||
|     props: { | ||||
|         model: { | ||||
| @@ -47,8 +51,11 @@ export default { | ||||
|             field: this.model.value | ||||
|         }; | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.updateText = throttle(this.updateText.bind(this), 500); | ||||
|     }, | ||||
|     methods: { | ||||
|         blur() { | ||||
|         updateText() { | ||||
|             const data = { | ||||
|                 model: this.model, | ||||
|                 value: this.field | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| <template> | ||||
| <div class="c-menu" | ||||
|      :class="options.menuClass" | ||||
| <div | ||||
|     class="c-menu" | ||||
|     :class="options.menuClass" | ||||
| > | ||||
|     <ul v-if="options.actions.length && options.actions[0].length"> | ||||
|         <template | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| <template> | ||||
| <div class="c-menu" | ||||
|      :class="[options.menuClass, 'c-super-menu']" | ||||
| <div | ||||
|     class="c-menu" | ||||
|     :class="[options.menuClass, 'c-super-menu']" | ||||
| > | ||||
|     <ul v-if="options.actions.length && options.actions[0].length" | ||||
|     <ul | ||||
|         v-if="options.actions.length && options.actions[0].length" | ||||
|         class="c-super-menu__menu" | ||||
|     > | ||||
|         <template | ||||
| @@ -34,7 +36,8 @@ | ||||
|         </template> | ||||
|     </ul> | ||||
|  | ||||
|     <ul v-else | ||||
|     <ul | ||||
|         v-else | ||||
|         class="c-super-menu__menu" | ||||
|     > | ||||
|         <li | ||||
|   | ||||
| @@ -1,28 +1,34 @@ | ||||
| <template> | ||||
| <div ref="plotWrapper" | ||||
|      class="has-local-controls" | ||||
|      :class="{ 's-unsynced' : isZoomed }" | ||||
| <div | ||||
|     ref="plotWrapper" | ||||
|     class="has-local-controls" | ||||
|     :class="{ 's-unsynced' : isZoomed }" | ||||
| > | ||||
|     <div v-if="isZoomed" | ||||
|          class="l-state-indicators" | ||||
|     <div | ||||
|         v-if="isZoomed" | ||||
|         class="l-state-indicators" | ||||
|     > | ||||
|         <span class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle" | ||||
|               title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data." | ||||
|         <span | ||||
|             class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle" | ||||
|             title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data." | ||||
|         ></span> | ||||
|     </div> | ||||
|     <div ref="plot" | ||||
|          class="c-bar-chart" | ||||
|          @plotly_relayout="zoom" | ||||
|     <div | ||||
|         ref="plot" | ||||
|         class="c-bar-chart" | ||||
|         @plotly_relayout="zoom" | ||||
|     ></div> | ||||
|     <div v-if="false" | ||||
|          ref="localControl" | ||||
|          class="gl-plot__local-controls h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover" | ||||
|     <div | ||||
|         v-if="false" | ||||
|         ref="localControl" | ||||
|         class="gl-plot__local-controls h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover" | ||||
|     > | ||||
|         <button v-if="data.length" | ||||
|                 class="c-button icon-reset" | ||||
|                 :disabled="!isZoomed" | ||||
|                 title="Reset pan/zoom" | ||||
|                 @click="reset()" | ||||
|         <button | ||||
|             v-if="data.length" | ||||
|             class="c-button icon-reset" | ||||
|             :disabled="!isZoomed" | ||||
|             title="Reset pan/zoom" | ||||
|             @click="reset()" | ||||
|         > | ||||
|         </button> | ||||
|     </div> | ||||
|   | ||||
| @@ -21,12 +21,13 @@ | ||||
| --> | ||||
|  | ||||
| <template> | ||||
| <BarGraph ref="barGraph" | ||||
|           class="c-plot c-bar-chart-view" | ||||
|           :data="trace" | ||||
|           :plot-axis-title="plotAxisTitle" | ||||
|           @subscribe="subscribeToAll" | ||||
|           @unsubscribe="removeAllSubscriptions" | ||||
| <BarGraph | ||||
|     ref="barGraph" | ||||
|     class="c-plot c-bar-chart-view" | ||||
|     :data="trace" | ||||
|     :plot-axis-title="plotAxisTitle" | ||||
|     @subscribe="subscribeToAll" | ||||
|     @unsubscribe="removeAllSubscriptions" | ||||
| /> | ||||
| </template> | ||||
|  | ||||
|   | ||||
| @@ -22,11 +22,13 @@ | ||||
| <template> | ||||
| <ul class="c-tree c-bar-graph-options"> | ||||
|     <h2 title="Display properties for this object">Bar Graph Series</h2> | ||||
|     <li v-for="series in domainObject.composition" | ||||
|     <li | ||||
|         v-for="series in domainObject.composition" | ||||
|         :key="series.key" | ||||
|     > | ||||
|         <series-options :item="series" | ||||
|                         :color-palette="colorPalette" | ||||
|         <series-options | ||||
|             :item="series" | ||||
|             :color-palette="colorPalette" | ||||
|         /> | ||||
|     </li> | ||||
| </ul> | ||||
|   | ||||
| @@ -21,12 +21,14 @@ | ||||
| --> | ||||
| <template> | ||||
| <ul> | ||||
|     <li class="c-tree__item menus-to-left" | ||||
|     <li | ||||
|         class="c-tree__item menus-to-left" | ||||
|         :class="aliasCss" | ||||
|     > | ||||
|         <span class="c-disclosure-triangle is-enabled flex-elem" | ||||
|               :class="expandedCssClass" | ||||
|               @click="expanded = !expanded" | ||||
|         <span | ||||
|             class="c-disclosure-triangle is-enabled flex-elem" | ||||
|             :class="expandedCssClass" | ||||
|             @click="expanded = !expanded" | ||||
|         > | ||||
|         </span> | ||||
|  | ||||
| @@ -36,14 +38,15 @@ | ||||
|             <div class="c-object-label__name">{{ name }}</div> | ||||
|         </div> | ||||
|     </li> | ||||
|     <ColorSwatch v-if="expanded" | ||||
|                  :current-color="currentColor" | ||||
|                  title="Manually set the color for this bar graph series." | ||||
|                  edit-title="Manually set the color for this bar graph series" | ||||
|                  view-title="The color for this bar graph series." | ||||
|                  short-label="Color" | ||||
|                  class="grid-properties" | ||||
|                  @colorSet="setColor" | ||||
|     <ColorSwatch | ||||
|         v-if="expanded" | ||||
|         :current-color="currentColor" | ||||
|         title="Manually set the color for this bar graph series." | ||||
|         edit-title="Manually set the color for this bar graph series" | ||||
|         view-title="The color for this bar graph series." | ||||
|         short-label="Color" | ||||
|         class="grid-properties" | ||||
|         @colorSet="setColor" | ||||
|     /> | ||||
| </ul> | ||||
| </template> | ||||
|   | ||||
| @@ -21,31 +21,35 @@ | ||||
| *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <div class="c-condition-h" | ||||
|      :class="{ 'is-drag-target': draggingOver }" | ||||
|      @dragover.prevent | ||||
|      @drop.prevent="dropCondition($event, conditionIndex)" | ||||
|      @dragenter="dragEnter($event, conditionIndex)" | ||||
|      @dragleave="dragLeave($event, conditionIndex)" | ||||
| <div | ||||
|     class="c-condition-h" | ||||
|     :class="{ 'is-drag-target': draggingOver }" | ||||
|     @dragover.prevent | ||||
|     @drop.prevent="dropCondition($event, conditionIndex)" | ||||
|     @dragenter="dragEnter($event, conditionIndex)" | ||||
|     @dragleave="dragLeave($event, conditionIndex)" | ||||
| > | ||||
|     <div class="c-condition-h__drop-target"></div> | ||||
|     <div v-if="isEditing" | ||||
|          :class="{'is-current': condition.id === currentConditionId}" | ||||
|          class="c-condition c-condition--edit" | ||||
|     <div | ||||
|         v-if="isEditing" | ||||
|         :class="{'is-current': condition.id === currentConditionId}" | ||||
|         class="c-condition c-condition--edit" | ||||
|     > | ||||
|         <!-- Edit view --> | ||||
|         <div class="c-condition__header"> | ||||
|             <span class="c-condition__drag-grippy c-grippy c-grippy--vertical-drag" | ||||
|                   title="Drag to reorder conditions" | ||||
|                   :class="[{ 'is-enabled': !condition.isDefault }, { 'hide-nice': condition.isDefault }]" | ||||
|                   :draggable="!condition.isDefault" | ||||
|                   @dragstart="dragStart" | ||||
|                   @dragend="dragEnd" | ||||
|             <span | ||||
|                 class="c-condition__drag-grippy c-grippy c-grippy--vertical-drag" | ||||
|                 title="Drag to reorder conditions" | ||||
|                 :class="[{ 'is-enabled': !condition.isDefault }, { 'hide-nice': condition.isDefault }]" | ||||
|                 :draggable="!condition.isDefault" | ||||
|                 @dragstart="dragStart" | ||||
|                 @dragend="dragEnd" | ||||
|             ></span> | ||||
|  | ||||
|             <span class="c-condition__disclosure c-disclosure-triangle c-tree__item__view-control is-enabled" | ||||
|                   :class="{ 'c-disclosure-triangle--expanded': expanded }" | ||||
|                   @click="expanded = !expanded" | ||||
|             <span | ||||
|                 class="c-condition__disclosure c-disclosure-triangle c-tree__item__view-control is-enabled" | ||||
|                 :class="{ 'c-disclosure-triangle--expanded': expanded }" | ||||
|                 @click="expanded = !expanded" | ||||
|             ></span> | ||||
|  | ||||
|             <span class="c-condition__name">{{ condition.configuration.name }}</span> | ||||
| @@ -54,107 +58,123 @@ | ||||
|                     Define criteria | ||||
|                 </template> | ||||
|                 <span v-else> | ||||
|                     <condition-description :show-label="false" | ||||
|                                            :condition="condition" | ||||
|                     <condition-description | ||||
|                         :show-label="false" | ||||
|                         :condition="condition" | ||||
|                     /> | ||||
|                 </span> | ||||
|             </span> | ||||
|  | ||||
|             <div class="c-condition__buttons"> | ||||
|                 <button v-if="!condition.isDefault" | ||||
|                         class="c-click-icon c-condition__duplicate-button icon-duplicate" | ||||
|                         title="Duplicate this condition" | ||||
|                         @click="cloneCondition" | ||||
|                 <button | ||||
|                     v-if="!condition.isDefault" | ||||
|                     class="c-click-icon c-condition__duplicate-button icon-duplicate" | ||||
|                     title="Duplicate this condition" | ||||
|                     @click="cloneCondition" | ||||
|                 ></button> | ||||
|  | ||||
|                 <button v-if="!condition.isDefault" | ||||
|                         class="c-click-icon c-condition__delete-button icon-trash" | ||||
|                         title="Delete this condition" | ||||
|                         @click="removeCondition" | ||||
|                 <button | ||||
|                     v-if="!condition.isDefault" | ||||
|                     class="c-click-icon c-condition__delete-button icon-trash" | ||||
|                     title="Delete this condition" | ||||
|                     @click="removeCondition" | ||||
|                 ></button> | ||||
|             </div> | ||||
|         </div> | ||||
|         <div v-if="expanded" | ||||
|              class="c-condition__definition c-cdef" | ||||
|         <div | ||||
|             v-if="expanded" | ||||
|             class="c-condition__definition c-cdef" | ||||
|         > | ||||
|             <span class="c-cdef__separator c-row-separator"></span> | ||||
|             <span class="c-cdef__label">Condition Name</span> | ||||
|             <span class="c-cdef__controls"> | ||||
|                 <input v-model="condition.configuration.name" | ||||
|                        class="t-condition-input__name" | ||||
|                        type="text" | ||||
|                        @change="persist" | ||||
|                 <input | ||||
|                     v-model="condition.configuration.name" | ||||
|                     class="t-condition-input__name" | ||||
|                     type="text" | ||||
|                     @change="persist" | ||||
|                 > | ||||
|             </span> | ||||
|  | ||||
|             <span class="c-cdef__label">Output</span> | ||||
|             <span class="c-cdef__controls"> | ||||
|                 <span class="c-cdef__control"> | ||||
|                     <select v-model="selectedOutputSelection" | ||||
|                             @change="setOutputValue" | ||||
|                     <select | ||||
|                         v-model="selectedOutputSelection" | ||||
|                         @change="setOutputValue" | ||||
|                     > | ||||
|                         <option v-for="option in outputOptions" | ||||
|                                 :key="option" | ||||
|                                 :value="option" | ||||
|                         <option | ||||
|                             v-for="option in outputOptions" | ||||
|                             :key="option" | ||||
|                             :value="option" | ||||
|                         > | ||||
|                             {{ initCap(option) }} | ||||
|                         </option> | ||||
|                     </select> | ||||
|                 </span> | ||||
|                 <span class="c-cdef__control"> | ||||
|                     <input v-if="selectedOutputSelection === outputOptions[2]" | ||||
|                            v-model="condition.configuration.output" | ||||
|                            class="t-condition-name-input" | ||||
|                            type="text" | ||||
|                            @change="persist" | ||||
|                     <input | ||||
|                         v-if="selectedOutputSelection === outputOptions[2]" | ||||
|                         v-model="condition.configuration.output" | ||||
|                         class="t-condition-name-input" | ||||
|                         type="text" | ||||
|                         @change="persist" | ||||
|                     > | ||||
|                 </span> | ||||
|             </span> | ||||
|  | ||||
|             <div v-if="!condition.isDefault" | ||||
|                  class="c-cdef__match-and-criteria" | ||||
|             <div | ||||
|                 v-if="!condition.isDefault" | ||||
|                 class="c-cdef__match-and-criteria" | ||||
|             > | ||||
|                 <span class="c-cdef__separator c-row-separator"></span> | ||||
|                 <span class="c-cdef__label">Match</span> | ||||
|                 <span class="c-cdef__controls"> | ||||
|                     <select v-model="condition.configuration.trigger" | ||||
|                             @change="persist" | ||||
|                     <select | ||||
|                         v-model="condition.configuration.trigger" | ||||
|                         @change="persist" | ||||
|                     > | ||||
|                         <option v-for="option in triggers" | ||||
|                                 :key="option.value" | ||||
|                                 :value="option.value" | ||||
|                         <option | ||||
|                             v-for="option in triggers" | ||||
|                             :key="option.value" | ||||
|                             :value="option.value" | ||||
|                         > {{ option.label }}</option> | ||||
|                     </select> | ||||
|                 </span> | ||||
|  | ||||
|                 <template v-if="telemetry.length || condition.configuration.criteria.length"> | ||||
|                     <div v-for="(criterion, index) in condition.configuration.criteria" | ||||
|                          :key="criterion.id" | ||||
|                          class="c-cdef__criteria" | ||||
|                     <div | ||||
|                         v-for="(criterion, index) in condition.configuration.criteria" | ||||
|                         :key="criterion.id" | ||||
|                         class="c-cdef__criteria" | ||||
|                     > | ||||
|                         <Criterion :telemetry="telemetry" | ||||
|                                    :criterion="criterion" | ||||
|                                    :index="index" | ||||
|                                    :trigger="condition.configuration.trigger" | ||||
|                                    :is-default="condition.configuration.criteria.length === 1" | ||||
|                                    @persist="persist" | ||||
|                         <Criterion | ||||
|                             :telemetry="telemetry" | ||||
|                             :criterion="criterion" | ||||
|                             :index="index" | ||||
|                             :trigger="condition.configuration.trigger" | ||||
|                             :is-default="condition.configuration.criteria.length === 1" | ||||
|                             @persist="persist" | ||||
|                         /> | ||||
|                         <div class="c-cdef__criteria__buttons"> | ||||
|                             <button class="c-click-icon c-cdef__criteria-duplicate-button icon-duplicate" | ||||
|                                     title="Duplicate this criteria" | ||||
|                                     @click="cloneCriterion(index)" | ||||
|                             <button | ||||
|                                 class="c-click-icon c-cdef__criteria-duplicate-button icon-duplicate" | ||||
|                                 title="Duplicate this criteria" | ||||
|                                 @click="cloneCriterion(index)" | ||||
|                             ></button> | ||||
|                             <button v-if="!(condition.configuration.criteria.length === 1)" | ||||
|                                     class="c-click-icon c-cdef__criteria-duplicate-button icon-trash" | ||||
|                                     title="Delete this criteria" | ||||
|                                     @click="removeCriterion(index)" | ||||
|                             <button | ||||
|                                 v-if="!(condition.configuration.criteria.length === 1)" | ||||
|                                 class="c-click-icon c-cdef__criteria-duplicate-button icon-trash" | ||||
|                                 title="Delete this criteria" | ||||
|                                 @click="removeCriterion(index)" | ||||
|                             ></button> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </template> | ||||
|                 <div class="c-cdef__separator c-row-separator"></div> | ||||
|                 <div class="c-cdef__controls" | ||||
|                      :disabled="!telemetry.length" | ||||
|                 <div | ||||
|                     class="c-cdef__controls" | ||||
|                     :disabled="!telemetry.length" | ||||
|                 > | ||||
|                     <button | ||||
|                         class="c-cdef__add-criteria-button c-button c-button--labeled icon-plus" | ||||
| @@ -166,9 +186,10 @@ | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div v-else | ||||
|          class="c-condition c-condition--browse" | ||||
|          :class="{'is-current': condition.id === currentConditionId}" | ||||
|     <div | ||||
|         v-else | ||||
|         class="c-condition c-condition--browse" | ||||
|         :class="{'is-current': condition.id === currentConditionId}" | ||||
|     > | ||||
|         <!-- Browse view --> | ||||
|         <div class="c-condition__header"> | ||||
| @@ -180,8 +201,9 @@ | ||||
|             </span> | ||||
|         </div> | ||||
|         <div class="c-condition__summary"> | ||||
|             <condition-description :show-label="false" | ||||
|                                    :condition="condition" | ||||
|             <condition-description | ||||
|                 :show-label="false" | ||||
|                 :condition="condition" | ||||
|             /> | ||||
|         </div> | ||||
|     </div> | ||||
|   | ||||
| @@ -21,8 +21,9 @@ | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <section id="conditionCollection" | ||||
|          :class="{ 'is-expanded': expanded }" | ||||
| <section | ||||
|     id="conditionCollection" | ||||
|     :class="{ 'is-expanded': expanded }" | ||||
| > | ||||
|     <div class="c-cs__header c-section__header"> | ||||
|         <span | ||||
| @@ -32,12 +33,14 @@ | ||||
|         ></span> | ||||
|         <div class="c-cs__header-label c-section__label">Conditions</div> | ||||
|     </div> | ||||
|     <div v-if="expanded" | ||||
|          class="c-cs__content" | ||||
|     <div | ||||
|         v-if="expanded" | ||||
|         class="c-cs__content" | ||||
|     > | ||||
|         <div v-show="isEditing" | ||||
|              class="hint" | ||||
|              :class="{ 's-status-icon-warning-lo': !telemetryObjs.length }" | ||||
|         <div | ||||
|             v-show="isEditing" | ||||
|             class="hint" | ||||
|             :class="{ 's-status-icon-warning-lo': !telemetryObjs.length }" | ||||
|         > | ||||
|             <template v-if="!telemetryObjs.length">Drag telemetry into this Condition Set to configure Conditions and add criteria.</template> | ||||
|             <template v-else>The first condition to match is the one that is applied. Drag conditions to reorder.</template> | ||||
| @@ -52,24 +55,26 @@ | ||||
|             <span class="c-cs-button__label">Add Condition</span> | ||||
|         </button> | ||||
|  | ||||
|         <div class="c-cs__conditions-h" | ||||
|              :class="{ 'is-active-dragging': isDragging }" | ||||
|         <div | ||||
|             class="c-cs__conditions-h" | ||||
|             :class="{ 'is-active-dragging': isDragging }" | ||||
|         > | ||||
|             <Condition v-for="(condition, index) in conditionCollection" | ||||
|                        :key="condition.id" | ||||
|                        :condition="condition" | ||||
|                        :current-condition-id="currentConditionId" | ||||
|                        :condition-index="index" | ||||
|                        :telemetry="telemetryObjs" | ||||
|                        :is-editing="isEditing" | ||||
|                        :move-index="moveIndex" | ||||
|                        :is-dragging="isDragging" | ||||
|                        @updateCondition="updateCondition" | ||||
|                        @removeCondition="removeCondition" | ||||
|                        @cloneCondition="cloneCondition" | ||||
|                        @setMoveIndex="setMoveIndex" | ||||
|                        @dragComplete="dragComplete" | ||||
|                        @dropCondition="dropCondition" | ||||
|             <Condition | ||||
|                 v-for="(condition, index) in conditionCollection" | ||||
|                 :key="condition.id" | ||||
|                 :condition="condition" | ||||
|                 :current-condition-id="currentConditionId" | ||||
|                 :condition-index="index" | ||||
|                 :telemetry="telemetryObjs" | ||||
|                 :is-editing="isEditing" | ||||
|                 :move-index="moveIndex" | ||||
|                 :is-dragging="isDragging" | ||||
|                 @updateCondition="updateCondition" | ||||
|                 @removeCondition="removeCondition" | ||||
|                 @cloneCondition="cloneCondition" | ||||
|                 @setMoveIndex="setMoveIndex" | ||||
|                 @dragComplete="dragComplete" | ||||
|                 @dropCondition="dropCondition" | ||||
|             /> | ||||
|         </div> | ||||
|     </div> | ||||
|   | ||||
| @@ -22,18 +22,21 @@ | ||||
|  | ||||
| <template> | ||||
| <div class="c-style__condition-desc"> | ||||
|     <span v-if="showLabel && condition" | ||||
|           class="c-style__condition-desc__name c-condition__name" | ||||
|     <span | ||||
|         v-if="showLabel && condition" | ||||
|         class="c-style__condition-desc__name c-condition__name" | ||||
|     > | ||||
|         {{ condition.configuration.name }} | ||||
|     </span> | ||||
|     <span v-if="!condition.isDefault" | ||||
|           class="c-style__condition-desc__text" | ||||
|     <span | ||||
|         v-if="!condition.isDefault" | ||||
|         class="c-style__condition-desc__text" | ||||
|     > | ||||
|         {{ description }} | ||||
|     </span> | ||||
|     <span v-else | ||||
|           class="c-style__condition-desc__text" | ||||
|     <span | ||||
|         v-else | ||||
|         class="c-style__condition-desc__text" | ||||
|     > | ||||
|         Match if no other condition is matched | ||||
|     </span> | ||||
|   | ||||
| @@ -21,12 +21,14 @@ | ||||
| *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <div v-if="conditionErrors.length" | ||||
|      class="c-condition__errors" | ||||
| <div | ||||
|     v-if="conditionErrors.length" | ||||
|     class="c-condition__errors" | ||||
| > | ||||
|     <div v-for="(error, index) in conditionErrors" | ||||
|          :key="index" | ||||
|          class="u-alert u-alert--block u-alert--with-icon" | ||||
|     <div | ||||
|         v-for="(error, index) in conditionErrors" | ||||
|         :key="index" | ||||
|         class="u-alert u-alert--block u-alert--with-icon" | ||||
|     >{{ error.message.errorText }} {{ error.additionalInfo }} | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -36,18 +36,20 @@ | ||||
|         </div> | ||||
|     </section> | ||||
|     <div class="c-cs__test-data-and-conditions-w"> | ||||
|         <TestData class="c-cs__test-data" | ||||
|                   :is-editing="isEditing" | ||||
|                   :test-data="testData" | ||||
|                   :telemetry="telemetryObjs" | ||||
|                   @updateTestData="updateTestData" | ||||
|         <TestData | ||||
|             class="c-cs__test-data" | ||||
|             :is-editing="isEditing" | ||||
|             :test-data="testData" | ||||
|             :telemetry="telemetryObjs" | ||||
|             @updateTestData="updateTestData" | ||||
|         /> | ||||
|         <ConditionCollection class="c-cs__conditions" | ||||
|                              :is-editing="isEditing" | ||||
|                              :test-data="testData" | ||||
|                              @conditionSetResultUpdated="updateCurrentOutput" | ||||
|                              @updateDefaultOutput="updateDefaultOutput" | ||||
|                              @telemetryUpdated="updateTelemetry" | ||||
|         <ConditionCollection | ||||
|             class="c-cs__conditions" | ||||
|             :is-editing="isEditing" | ||||
|             :test-data="testData" | ||||
|             @conditionSetResultUpdated="updateCurrentOutput" | ||||
|             @updateDefaultOutput="updateDefaultOutput" | ||||
|             @telemetryUpdated="updateTelemetry" | ||||
|         /> | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -26,76 +26,89 @@ | ||||
|     <span class="c-cdef__label">{{ setRowLabel }}</span> | ||||
|     <span class="c-cdef__controls"> | ||||
|         <span class="c-cdef__control"> | ||||
|             <select ref="telemetrySelect" | ||||
|                     v-model="criterion.telemetry" | ||||
|                     @change="updateMetadataOptions" | ||||
|             <select | ||||
|                 ref="telemetrySelect" | ||||
|                 v-model="criterion.telemetry" | ||||
|                 @change="updateMetadataOptions" | ||||
|             > | ||||
|                 <option value="">- Select Telemetry -</option> | ||||
|                 <option value="all">all telemetry</option> | ||||
|                 <option value="any">any telemetry</option> | ||||
|                 <option v-for="telemetryOption in telemetry" | ||||
|                         :key="telemetryOption.identifier.key" | ||||
|                         :value="telemetryOption.identifier" | ||||
|                 <option | ||||
|                     v-for="telemetryOption in telemetry" | ||||
|                     :key="telemetryOption.identifier.key" | ||||
|                     :value="telemetryOption.identifier" | ||||
|                 > | ||||
|                     {{ telemetryOption.name }} | ||||
|                 </option> | ||||
|             </select> | ||||
|         </span> | ||||
|         <span v-if="criterion.telemetry" | ||||
|               class="c-cdef__control" | ||||
|         <span | ||||
|             v-if="criterion.telemetry" | ||||
|             class="c-cdef__control" | ||||
|         > | ||||
|             <select ref="metadataSelect" | ||||
|                     v-model="criterion.metadata" | ||||
|                     @change="updateOperations" | ||||
|             <select | ||||
|                 ref="metadataSelect" | ||||
|                 v-model="criterion.metadata" | ||||
|                 @change="updateOperations" | ||||
|             > | ||||
|                 <option value="">- Select Field -</option> | ||||
|                 <option v-for="option in telemetryMetadataOptions" | ||||
|                         :key="option.key" | ||||
|                         :value="option.key" | ||||
|                 <option | ||||
|                     v-for="option in telemetryMetadataOptions" | ||||
|                     :key="option.key" | ||||
|                     :value="option.key" | ||||
|                 > | ||||
|                     {{ option.name }} | ||||
|                 </option> | ||||
|                 <option value="dataReceived">any data received</option> | ||||
|             </select> | ||||
|         </span> | ||||
|         <span v-if="criterion.telemetry && criterion.metadata" | ||||
|               class="c-cdef__control" | ||||
|         <span | ||||
|             v-if="criterion.telemetry && criterion.metadata" | ||||
|             class="c-cdef__control" | ||||
|         > | ||||
|             <select v-model="criterion.operation" | ||||
|                     @change="updateInputVisibilityAndValues" | ||||
|             <select | ||||
|                 v-model="criterion.operation" | ||||
|                 @change="updateInputVisibilityAndValues" | ||||
|             > | ||||
|                 <option value="">- Select Comparison -</option> | ||||
|                 <option v-for="option in filteredOps" | ||||
|                         :key="option.name" | ||||
|                         :value="option.name" | ||||
|                 <option | ||||
|                     v-for="option in filteredOps" | ||||
|                     :key="option.name" | ||||
|                     :value="option.name" | ||||
|                 > | ||||
|                     {{ option.text }} | ||||
|                 </option> | ||||
|             </select> | ||||
|             <template v-if="!enumerations.length"> | ||||
|                 <span v-for="(item, inputIndex) in inputCount" | ||||
|                       :key="inputIndex" | ||||
|                       class="c-cdef__control__inputs" | ||||
|                 <span | ||||
|                     v-for="(item, inputIndex) in inputCount" | ||||
|                     :key="inputIndex" | ||||
|                     class="c-cdef__control__inputs" | ||||
|                 > | ||||
|                     <input v-model="criterion.input[inputIndex]" | ||||
|                            class="c-cdef__control__input" | ||||
|                            :type="setInputType" | ||||
|                            @change="persist" | ||||
|                     <input | ||||
|                         v-model="criterion.input[inputIndex]" | ||||
|                         class="c-cdef__control__input" | ||||
|                         :type="setInputType" | ||||
|                         @change="persist" | ||||
|                     > | ||||
|                     <span v-if="inputIndex < inputCount-1">and</span> | ||||
|                 </span> | ||||
|                 <span v-if="criterion.metadata === 'dataReceived'">seconds</span> | ||||
|             </template> | ||||
|             <span v-else> | ||||
|                 <span v-if="inputCount && criterion.operation" | ||||
|                       class="c-cdef__control" | ||||
|                 <span | ||||
|                     v-if="inputCount && criterion.operation" | ||||
|                     class="c-cdef__control" | ||||
|                 > | ||||
|                     <select v-model="criterion.input[0]" | ||||
|                             @change="persist" | ||||
|                     <select | ||||
|                         v-model="criterion.input[0]" | ||||
|                         @change="persist" | ||||
|                     > | ||||
|                         <option v-for="option in enumerations" | ||||
|                                 :key="option.string" | ||||
|                                 :value="option.value.toString()" | ||||
|                         <option | ||||
|                             v-for="option in enumerations" | ||||
|                             :key="option.string" | ||||
|                             :value="option.value.toString()" | ||||
|                         > | ||||
|                             {{ option.string }} | ||||
|                         </option> | ||||
|   | ||||
| @@ -21,9 +21,10 @@ | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <section v-show="isEditing" | ||||
|          id="test-data" | ||||
|          :class="{ 'is-expanded': expanded }" | ||||
| <section | ||||
|     v-show="isEditing" | ||||
|     id="test-data" | ||||
|     :class="{ 'is-expanded': expanded }" | ||||
| > | ||||
|     <div class="c-cs__header c-section__header"> | ||||
|         <span | ||||
| @@ -33,11 +34,13 @@ | ||||
|         ></span> | ||||
|         <div class="c-cs__header-label c-section__label">Test Data</div> | ||||
|     </div> | ||||
|     <div v-if="expanded" | ||||
|          class="c-cs__content" | ||||
|     <div | ||||
|         v-if="expanded" | ||||
|         class="c-cs__content" | ||||
|     > | ||||
|         <div class="c-cs__test-data__controls c-cdef__controls" | ||||
|              :disabled="!telemetry.length" | ||||
|         <div | ||||
|             class="c-cs__test-data__controls c-cdef__controls" | ||||
|             :disabled="!telemetry.length" | ||||
|         > | ||||
|             <label class="c-toggle-switch"> | ||||
|                 <input | ||||
| @@ -50,59 +53,69 @@ | ||||
|             </label> | ||||
|         </div> | ||||
|         <div class="c-cs-tests"> | ||||
|             <span v-for="(testInput, tIndex) in testInputs" | ||||
|                   :key="tIndex" | ||||
|                   class="c-test-datum c-cs-test" | ||||
|             <span | ||||
|                 v-for="(testInput, tIndex) in testInputs" | ||||
|                 :key="tIndex" | ||||
|                 class="c-test-datum c-cs-test" | ||||
|             > | ||||
|                 <span class="c-cs-test__label">Set</span> | ||||
|                 <span class="c-cs-test__controls"> | ||||
|                     <span class="c-cdef__control"> | ||||
|                         <select v-model="testInput.telemetry" | ||||
|                                 @change="updateMetadata(testInput)" | ||||
|                         <select | ||||
|                             v-model="testInput.telemetry" | ||||
|                             @change="updateMetadata(testInput)" | ||||
|                         > | ||||
|                             <option value="">- Select Telemetry -</option> | ||||
|                             <option v-for="(telemetryOption, index) in telemetry" | ||||
|                                     :key="index" | ||||
|                                     :value="telemetryOption.identifier" | ||||
|                             <option | ||||
|                                 v-for="(telemetryOption, index) in telemetry" | ||||
|                                 :key="index" | ||||
|                                 :value="telemetryOption.identifier" | ||||
|                             > | ||||
|                                 {{ telemetryOption.name }} | ||||
|                             </option> | ||||
|                         </select> | ||||
|                     </span> | ||||
|                     <span v-if="testInput.telemetry" | ||||
|                           class="c-cdef__control" | ||||
|                     <span | ||||
|                         v-if="testInput.telemetry" | ||||
|                         class="c-cdef__control" | ||||
|                     > | ||||
|                         <select v-model="testInput.metadata" | ||||
|                                 @change="updateTestData" | ||||
|                         <select | ||||
|                             v-model="testInput.metadata" | ||||
|                             @change="updateTestData" | ||||
|                         > | ||||
|                             <option value="">- Select Field -</option> | ||||
|                             <option v-for="(option, index) in telemetryMetadataOptions[getId(testInput.telemetry)]" | ||||
|                                     :key="index" | ||||
|                                     :value="option.key" | ||||
|                             <option | ||||
|                                 v-for="(option, index) in telemetryMetadataOptions[getId(testInput.telemetry)]" | ||||
|                                 :key="index" | ||||
|                                 :value="option.key" | ||||
|                             > | ||||
|                                 {{ option.name }} | ||||
|                             </option> | ||||
|                         </select> | ||||
|                     </span> | ||||
|                     <span v-if="testInput.metadata" | ||||
|                           class="c-cdef__control__inputs" | ||||
|                     <span | ||||
|                         v-if="testInput.metadata" | ||||
|                         class="c-cdef__control__inputs" | ||||
|                     > | ||||
|                         <input v-model="testInput.value" | ||||
|                                placeholder="Enter test input" | ||||
|                                type="text" | ||||
|                                class="c-cdef__control__input" | ||||
|                                @change="updateTestData" | ||||
|                         <input | ||||
|                             v-model="testInput.value" | ||||
|                             placeholder="Enter test input" | ||||
|                             type="text" | ||||
|                             class="c-cdef__control__input" | ||||
|                             @change="updateTestData" | ||||
|                         > | ||||
|                     </span> | ||||
|                 </span> | ||||
|                 <div class="c-cs-test__buttons"> | ||||
|                     <button class="c-click-icon c-test-data__duplicate-button icon-duplicate" | ||||
|                             title="Duplicate this test datum" | ||||
|                             @click="addTestInput(testInput)" | ||||
|                     <button | ||||
|                         class="c-click-icon c-test-data__duplicate-button icon-duplicate" | ||||
|                         title="Duplicate this test datum" | ||||
|                         @click="addTestInput(testInput)" | ||||
|                     ></button> | ||||
|                     <button class="c-click-icon c-test-data__delete-button icon-trash" | ||||
|                             title="Delete this test datum" | ||||
|                             @click="removeTestInput(tIndex)" | ||||
|                     <button | ||||
|                         class="c-click-icon c-test-data__delete-button icon-trash" | ||||
|                         title="Delete this test datum" | ||||
|                         @click="removeTestInput(tIndex)" | ||||
|                     ></button> | ||||
|                 </div> | ||||
|             </span> | ||||
|   | ||||
| @@ -23,52 +23,60 @@ | ||||
| <template> | ||||
| <div class="c-style has-local-controls c-toolbar"> | ||||
|     <div class="c-style__controls"> | ||||
|         <div :class="[ | ||||
|                  { 'is-style-invisible': styleItem.style && styleItem.style.isStyleInvisible }, | ||||
|                  { 'c-style-thumb--mixed': mixedStyles.indexOf('backgroundColor') > -1 } | ||||
|              ]" | ||||
|              :style="[styleItem.style.imageUrl ? { backgroundImage:'url(' + styleItem.style.imageUrl + ')'} : itemStyle ]" | ||||
|              class="c-style-thumb" | ||||
|         <div | ||||
|             :class="[ | ||||
|                 { 'is-style-invisible': styleItem.style && styleItem.style.isStyleInvisible }, | ||||
|                 { 'c-style-thumb--mixed': mixedStyles.indexOf('backgroundColor') > -1 } | ||||
|             ]" | ||||
|             :style="[styleItem.style.imageUrl ? { backgroundImage:'url(' + styleItem.style.imageUrl + ')'} : itemStyle ]" | ||||
|             class="c-style-thumb" | ||||
|         > | ||||
|             <span class="c-style-thumb__text" | ||||
|                   :class="{ 'hide-nice': !hasProperty(styleItem.style.color) }" | ||||
|             <span | ||||
|                 class="c-style-thumb__text" | ||||
|                 :class="{ 'hide-nice': !hasProperty(styleItem.style.color) }" | ||||
|             > | ||||
|                 ABC | ||||
|             </span> | ||||
|         </div> | ||||
|  | ||||
|         <toolbar-color-picker v-if="hasProperty(styleItem.style.border)" | ||||
|                               class="c-style__toolbar-button--border-color u-menu-to--center" | ||||
|                               :options="borderColorOption" | ||||
|                               @change="updateStyleValue" | ||||
|         <toolbar-color-picker | ||||
|             v-if="hasProperty(styleItem.style.border)" | ||||
|             class="c-style__toolbar-button--border-color u-menu-to--center" | ||||
|             :options="borderColorOption" | ||||
|             @change="updateStyleValue" | ||||
|         /> | ||||
|         <toolbar-color-picker v-if="hasProperty(styleItem.style.backgroundColor)" | ||||
|                               class="c-style__toolbar-button--background-color u-menu-to--center" | ||||
|                               :options="backgroundColorOption" | ||||
|                               @change="updateStyleValue" | ||||
|         <toolbar-color-picker | ||||
|             v-if="hasProperty(styleItem.style.backgroundColor)" | ||||
|             class="c-style__toolbar-button--background-color u-menu-to--center" | ||||
|             :options="backgroundColorOption" | ||||
|             @change="updateStyleValue" | ||||
|         /> | ||||
|         <toolbar-color-picker v-if="hasProperty(styleItem.style.color)" | ||||
|                               class="c-style__toolbar-button--color u-menu-to--center" | ||||
|                               :options="colorOption" | ||||
|                               @change="updateStyleValue" | ||||
|         <toolbar-color-picker | ||||
|             v-if="hasProperty(styleItem.style.color)" | ||||
|             class="c-style__toolbar-button--color u-menu-to--center" | ||||
|             :options="colorOption" | ||||
|             @change="updateStyleValue" | ||||
|         /> | ||||
|         <toolbar-button v-if="hasProperty(styleItem.style.imageUrl)" | ||||
|                         class="c-style__toolbar-button--image-url" | ||||
|                         :options="imageUrlOption" | ||||
|                         @change="updateStyleValue" | ||||
|         <toolbar-button | ||||
|             v-if="hasProperty(styleItem.style.imageUrl)" | ||||
|             class="c-style__toolbar-button--image-url" | ||||
|             :options="imageUrlOption" | ||||
|             @change="updateStyleValue" | ||||
|         /> | ||||
|         <toolbar-toggle-button v-if="hasProperty(styleItem.style.isStyleInvisible)" | ||||
|                                class="c-style__toolbar-button--toggle-visible" | ||||
|                                :options="isStyleInvisibleOption" | ||||
|                                @change="updateStyleValue" | ||||
|         <toolbar-toggle-button | ||||
|             v-if="hasProperty(styleItem.style.isStyleInvisible)" | ||||
|             class="c-style__toolbar-button--toggle-visible" | ||||
|             :options="isStyleInvisibleOption" | ||||
|             @change="updateStyleValue" | ||||
|         /> | ||||
|     </div> | ||||
|  | ||||
|     <!-- Save Styles --> | ||||
|     <toolbar-button v-if="canSaveStyle" | ||||
|                     class="c-style__toolbar-button--save c-local-controls--show-on-hover c-icon-button c-icon-button--major" | ||||
|                     :options="saveOptions" | ||||
|                     @click="saveItemStyle()" | ||||
|     <toolbar-button | ||||
|         v-if="canSaveStyle" | ||||
|         class="c-style__toolbar-button--save c-local-controls--show-on-hover c-icon-button c-icon-button--major" | ||||
|         :options="saveOptions" | ||||
|         @click="saveItemStyle()" | ||||
|     /> | ||||
| </div> | ||||
| </template> | ||||
|   | ||||
| @@ -22,8 +22,9 @@ | ||||
|  | ||||
| <template> | ||||
| <div class="c-inspector__styles c-inspect-styles"> | ||||
|     <div v-if="isStaticAndConditionalStyles" | ||||
|          class="c-inspect-styles__mixed-static-and-conditional u-alert u-alert--block u-alert--with-icon" | ||||
|     <div | ||||
|         v-if="isStaticAndConditionalStyles" | ||||
|         class="c-inspect-styles__mixed-static-and-conditional u-alert u-alert--block u-alert--with-icon" | ||||
|     > | ||||
|         Your selection includes one or more items that use Conditional Styling. Applying a static style below will replace any Conditional Styling with the new choice. | ||||
|     </div> | ||||
| @@ -37,16 +38,18 @@ | ||||
|             @set-font-property="setFontProperty" | ||||
|         /> | ||||
|         <div class="c-inspect-styles__content"> | ||||
|             <div v-if="staticStyle" | ||||
|                  class="c-inspect-styles__style" | ||||
|             <div | ||||
|                 v-if="staticStyle" | ||||
|                 class="c-inspect-styles__style" | ||||
|             > | ||||
|                 <StyleEditor class="c-inspect-styles__editor" | ||||
|                              :style-item="staticStyle" | ||||
|                              :is-editing="allowEditing" | ||||
|                              :mixed-styles="mixedStyles" | ||||
|                              :non-specific-font-properties="nonSpecificFontProperties" | ||||
|                              @persist="updateStaticStyle" | ||||
|                              @save-style="saveStyle" | ||||
|                 <StyleEditor | ||||
|                     class="c-inspect-styles__editor" | ||||
|                     :style-item="staticStyle" | ||||
|                     :is-editing="allowEditing" | ||||
|                     :mixed-styles="mixedStyles" | ||||
|                     :non-specific-font-properties="nonSpecificFontProperties" | ||||
|                     @persist="updateStaticStyle" | ||||
|                     @save-style="saveStyle" | ||||
|                 /> | ||||
|             </div> | ||||
|             <button | ||||
| @@ -64,9 +67,10 @@ | ||||
|             Conditional Object Styles | ||||
|         </div> | ||||
|         <div class="c-inspect-styles__content c-inspect-styles__condition-set c-inspect-styles__elem"> | ||||
|             <a v-if="conditionSetDomainObject" | ||||
|                class="c-object-label" | ||||
|                @click="navigateOrPreview" | ||||
|             <a | ||||
|                 v-if="conditionSetDomainObject" | ||||
|                 class="c-object-label" | ||||
|                 @click="navigateOrPreview" | ||||
|             > | ||||
|                 <span class="c-object-label__type-icon icon-conditional"></span> | ||||
|                 <span class="c-object-label__name">{{ conditionSetDomainObject.name }}</span> | ||||
| @@ -80,15 +84,17 @@ | ||||
|                     <span class="c-button__label">Change...</span> | ||||
|                 </button> | ||||
|  | ||||
|                 <button class="c-click-icon icon-x" | ||||
|                         title="Remove conditional styles" | ||||
|                         @click="removeConditionSet" | ||||
|                 <button | ||||
|                     class="c-click-icon icon-x" | ||||
|                     title="Remove conditional styles" | ||||
|                     @click="removeConditionSet" | ||||
|                 ></button> | ||||
|             </template> | ||||
|         </div> | ||||
|  | ||||
|         <div v-if="isConditionWidget && allowEditing" | ||||
|              class="c-inspect-styles__elem c-inspect-styles__output-label-toggle" | ||||
|         <div | ||||
|             v-if="isConditionWidget && allowEditing" | ||||
|             class="c-inspect-styles__elem c-inspect-styles__output-label-toggle" | ||||
|         > | ||||
|             <label class="c-toggle-switch"> | ||||
|                 <input | ||||
| @@ -100,8 +106,9 @@ | ||||
|                 <span class="c-toggle-switch__label">Use Condition Set output as label</span> | ||||
|             </label> | ||||
|         </div> | ||||
|         <div v-if="isConditionWidget && !allowEditing" | ||||
|              class="c-inspect-styles__elem" | ||||
|         <div | ||||
|             v-if="isConditionWidget && !allowEditing" | ||||
|             class="c-inspect-styles__elem" | ||||
|         > | ||||
|             <span class="c-toggle-switch__label">Condition Set output as label: | ||||
|                 <span v-if="useConditionSetOutputAsLabel"> Yes</span><span v-else> No</span> | ||||
| @@ -114,27 +121,32 @@ | ||||
|             @set-font-property="setFontProperty" | ||||
|         /> | ||||
|  | ||||
|         <div v-if="conditionsLoaded" | ||||
|              class="c-inspect-styles__conditions" | ||||
|         <div | ||||
|             v-if="conditionsLoaded" | ||||
|             class="c-inspect-styles__conditions" | ||||
|         > | ||||
|             <div v-for="(conditionStyle, index) in conditionalStyles" | ||||
|                  :key="index" | ||||
|                  class="c-inspect-styles__condition" | ||||
|                  :class="{'is-current': conditionStyle.conditionId === selectedConditionId}" | ||||
|                  @click="applySelectedConditionStyle(conditionStyle.conditionId)" | ||||
|             <div | ||||
|                 v-for="(conditionStyle, index) in conditionalStyles" | ||||
|                 :key="index" | ||||
|                 class="c-inspect-styles__condition" | ||||
|                 :class="{'is-current': conditionStyle.conditionId === selectedConditionId}" | ||||
|                 @click="applySelectedConditionStyle(conditionStyle.conditionId)" | ||||
|             > | ||||
|                 <condition-error :show-label="true" | ||||
|                                  :condition="getCondition(conditionStyle.conditionId)" | ||||
|                 <condition-error | ||||
|                     :show-label="true" | ||||
|                     :condition="getCondition(conditionStyle.conditionId)" | ||||
|                 /> | ||||
|                 <condition-description :show-label="true" | ||||
|                                        :condition="getCondition(conditionStyle.conditionId)" | ||||
|                 <condition-description | ||||
|                     :show-label="true" | ||||
|                     :condition="getCondition(conditionStyle.conditionId)" | ||||
|                 /> | ||||
|                 <StyleEditor class="c-inspect-styles__editor" | ||||
|                              :style-item="conditionStyle" | ||||
|                              :non-specific-font-properties="nonSpecificFontProperties" | ||||
|                              :is-editing="allowEditing" | ||||
|                              @persist="updateConditionalStyle" | ||||
|                              @save-style="saveStyle" | ||||
|                 <StyleEditor | ||||
|                     class="c-inspect-styles__editor" | ||||
|                     :style-item="conditionStyle" | ||||
|                     :non-specific-font-properties="nonSpecificFontProperties" | ||||
|                     :is-editing="allowEditing" | ||||
|                     @persist="updateConditionalStyle" | ||||
|                     @save-style="saveStyle" | ||||
|                 /> | ||||
|             </div> | ||||
|         </div> | ||||
| @@ -325,16 +337,7 @@ export default { | ||||
|             return item && (item.type === type); | ||||
|         }, | ||||
|         canPersistObject(item) { | ||||
|             // for now the only way to tell if an object can be persisted is if it is creatable. | ||||
|             let creatable = false; | ||||
|             if (item) { | ||||
|                 const type = this.openmct.types.get(item.type); | ||||
|                 if (type && type.definition) { | ||||
|                     creatable = (type.definition.creatable !== undefined && (type.definition.creatable === 'true' || type.definition.creatable === true)); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return creatable; | ||||
|             return this.openmct.objects.isPersistable(item.identifier); | ||||
|         }, | ||||
|         hasConditionalStyle(domainObject, layoutItem) { | ||||
|             const id = layoutItem ? layoutItem.id : undefined; | ||||
|   | ||||
| @@ -21,9 +21,10 @@ | ||||
| *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <component :is="urlDefined ? 'a' : 'span'" | ||||
|            class="c-condition-widget u-style-receiver js-style-receiver" | ||||
|            :href="url" | ||||
| <component | ||||
|     :is="urlDefined ? 'a' : 'span'" | ||||
|     class="c-condition-widget u-style-receiver js-style-receiver" | ||||
|     :href="url" | ||||
| > | ||||
|     <div class="c-condition-widget__label"> | ||||
|         {{ internalDomainObject.conditionalLabel || internalDomainObject.label }} | ||||
|   | ||||
| @@ -37,8 +37,9 @@ | ||||
|         :data-font="item.font" | ||||
|         @contextmenu.prevent="showContextMenu" | ||||
|     > | ||||
|         <div class="is-status__indicator" | ||||
|              :title="`This item is ${status}`" | ||||
|         <div | ||||
|             class="is-status__indicator" | ||||
|             :title="`This item is ${status}`" | ||||
|         ></div> | ||||
|         <div | ||||
|             v-if="showLabel" | ||||
|   | ||||
| @@ -97,13 +97,16 @@ export default class DuplicateAction { | ||||
|  | ||||
|     validate(currentParent) { | ||||
|         return (data) => { | ||||
|             const parentCandidatePath = data.value; | ||||
|             const parentCandidate = parentCandidatePath[0]; | ||||
|             const parentCandidate = data.value[0]; | ||||
|  | ||||
|             let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier); | ||||
|             let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier); | ||||
|             let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier); | ||||
|  | ||||
|             if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             if (!parentCandidateKeystring || !currentParentKeystring) { | ||||
|                 return false; | ||||
|             } | ||||
| @@ -122,13 +125,14 @@ export default class DuplicateAction { | ||||
|     } | ||||
|  | ||||
|     appliesTo(objectPath) { | ||||
|         let parent = objectPath[1]; | ||||
|         let parentType = parent && this.openmct.types.get(parent.type); | ||||
|         let child = objectPath[0]; | ||||
|         let childType = child && this.openmct.types.get(child.type); | ||||
|         let locked = child.locked ? child.locked : parent && parent.locked; | ||||
|         const parent = objectPath[1]; | ||||
|         const parentType = parent && this.openmct.types.get(parent.type); | ||||
|         const child = objectPath[0]; | ||||
|         const childType = child && this.openmct.types.get(child.type); | ||||
|         const locked = child.locked ? child.locked : parent && parent.locked; | ||||
|         const isPersistable = this.openmct.objects.isPersistable(child.identifier); | ||||
|  | ||||
|         if (locked) { | ||||
|         if (locked || !isPersistable) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -52,7 +52,7 @@ export default class ExportAsJSONAction { | ||||
|     appliesTo(objectPath) { | ||||
|         let domainObject = objectPath[0]; | ||||
|  | ||||
|         return this._isCreatable(domainObject); | ||||
|         return this._isCreatableAndPersistable(domainObject); | ||||
|     } | ||||
|     /** | ||||
|      * | ||||
| @@ -80,10 +80,11 @@ export default class ExportAsJSONAction { | ||||
|      * @param {object} domainObject | ||||
|      * @returns {boolean} | ||||
|      */ | ||||
|     _isCreatable(domainObject) { | ||||
|     _isCreatableAndPersistable(domainObject) { | ||||
|         const type = this.openmct.types.get(domainObject.type); | ||||
|         const isPersistable = this.openmct.objects.isPersistable(domainObject.identifier); | ||||
|  | ||||
|         return type && type.definition.creatable; | ||||
|         return type && type.definition.creatable && isPersistable; | ||||
|     } | ||||
|     /** | ||||
|      * @private | ||||
| @@ -170,7 +171,7 @@ export default class ExportAsJSONAction { | ||||
|                 .then((children) => { | ||||
|                     children.forEach((child, index) => { | ||||
|                         // Only export if object is creatable | ||||
|                         if (this._isCreatable(child)) { | ||||
|                         if (this._isCreatableAndPersistable(child)) { | ||||
|                             // Prevents infinite export of self-contained objs | ||||
|                             if (!Object.prototype.hasOwnProperty.call(this.tree, this._getId(child))) { | ||||
|                                 // If object is a link to something absent from | ||||
|   | ||||
| @@ -27,6 +27,10 @@ describe('Export as JSON plugin', () => { | ||||
|  | ||||
|     it('ExportAsJSONAction applies to folder', () => { | ||||
|         domainObject = { | ||||
|             identifier: { | ||||
|                 key: 'export-testing', | ||||
|                 namespace: '' | ||||
|             }, | ||||
|             composition: [], | ||||
|             location: 'mine', | ||||
|             modified: 1640115501237, | ||||
| @@ -40,6 +44,10 @@ describe('Export as JSON plugin', () => { | ||||
|  | ||||
|     it('ExportAsJSONAction applies to telemetry.plot.overlay', () => { | ||||
|         domainObject = { | ||||
|             identifier: { | ||||
|                 key: 'export-testing', | ||||
|                 namespace: '' | ||||
|             }, | ||||
|             composition: [], | ||||
|             location: 'mine', | ||||
|             modified: 1640115501237, | ||||
| @@ -53,6 +61,10 @@ describe('Export as JSON plugin', () => { | ||||
|  | ||||
|     it('ExportAsJSONAction applies to telemetry.plot.stacked', () => { | ||||
|         domainObject = { | ||||
|             identifier: { | ||||
|                 key: 'export-testing', | ||||
|                 namespace: '' | ||||
|             }, | ||||
|             composition: [], | ||||
|             location: 'mine', | ||||
|             modified: 1640115501237, | ||||
| @@ -64,16 +76,24 @@ describe('Export as JSON plugin', () => { | ||||
|         expect(exportAsJSONAction.appliesTo([domainObject])).toEqual(true); | ||||
|     }); | ||||
|  | ||||
|     it('ExportAsJSONAction applies does not applies to non-creatable objects', () => { | ||||
|     it('ExportAsJSONAction does not applie to non-persistable objects', () => { | ||||
|         domainObject = { | ||||
|             identifier: { | ||||
|                 key: 'export-testing', | ||||
|                 namespace: '' | ||||
|             }, | ||||
|             composition: [], | ||||
|             location: 'mine', | ||||
|             modified: 1640115501237, | ||||
|             name: 'Non Editable Folder', | ||||
|             persisted: 1640115501237, | ||||
|             type: 'noneditable.folder' | ||||
|             type: 'folder' | ||||
|         }; | ||||
|  | ||||
|         spyOn(openmct.objects, 'getProvider').and.callFake(() => { | ||||
|             return { get: () => domainObject }; | ||||
|         }); | ||||
|  | ||||
|         expect(exportAsJSONAction.appliesTo([domainObject])).toEqual(false); | ||||
|     }); | ||||
|  | ||||
|   | ||||
| @@ -26,8 +26,9 @@ | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="c-grid-item__controls"> | ||||
|         <div class="is-status__indicator" | ||||
|              :title="`This item is ${status}`" | ||||
|         <div | ||||
|             class="is-status__indicator" | ||||
|             :title="`This item is ${status}`" | ||||
|         ></div> | ||||
|         <div | ||||
|             class="icon-people" | ||||
|   | ||||
| @@ -17,8 +17,9 @@ | ||||
|                 class="c-object-label__type-icon c-list-item__name__type-icon" | ||||
|                 :class="item.type.cssClass" | ||||
|             > | ||||
|                 <span class="is-status__indicator" | ||||
|                       :title="`This item is ${status}`" | ||||
|                 <span | ||||
|                     class="is-status__indicator" | ||||
|                     :title="`This item is ${status}`" | ||||
|                 ></span> | ||||
|             </div> | ||||
|             <div class="c-object-label__name c-list-item__name__name">{{ item.model.name }}</div> | ||||
|   | ||||
| @@ -101,7 +101,10 @@ export default class CreateWizard { | ||||
|         // Ensure there is always a 'save in' section | ||||
|         if (includeLocation) { | ||||
|             function validateLocation(data) { | ||||
|                 return self.openmct.composition.checkPolicy(data.value[0], domainObject); | ||||
|                 const policyCheck = self.openmct.composition.checkPolicy(data.value[0], domainObject); | ||||
|                 const parentIsPersistable = self.openmct.objects.isPersistable(data.value[0].identifier); | ||||
|  | ||||
|                 return policyCheck && parentIsPersistable; | ||||
|             } | ||||
|  | ||||
|             sections.push({ | ||||
|   | ||||
| @@ -22,12 +22,13 @@ | ||||
|  | ||||
| <template> | ||||
|  | ||||
| <a class="c-hyperlink" | ||||
|    :class="{ | ||||
|        'c-hyperlink--button' : isButton | ||||
|    }" | ||||
|    :target="domainObject.linkTarget" | ||||
|    :href="url" | ||||
| <a | ||||
|     class="c-hyperlink" | ||||
|     :class="{ | ||||
|         'c-hyperlink--button' : isButton | ||||
|     }" | ||||
|     :target="domainObject.linkTarget" | ||||
|     :href="url" | ||||
| > | ||||
|     <span class="c-hyperlink__label">{{ domainObject.displayText }}</span> | ||||
| </a> | ||||
|   | ||||
| @@ -21,124 +21,144 @@ | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <div ref="compassRoseWrapper" | ||||
|      class="w-direction-rose" | ||||
|      :class="compassRoseSizingClasses" | ||||
|      @click="toggleLockCompass" | ||||
| <div | ||||
|     ref="compassRoseWrapper" | ||||
|     class="w-direction-rose" | ||||
|     :class="compassRoseSizingClasses" | ||||
|     @click="toggleLockCompass" | ||||
| > | ||||
|     <svg ref="compassRoseSvg" | ||||
|          class="c-compass-rose-svg" | ||||
|          viewBox="0 0 100 100" | ||||
|     <svg | ||||
|         ref="compassRoseSvg" | ||||
|         class="c-compass-rose-svg" | ||||
|         viewBox="0 0 100 100" | ||||
|     > | ||||
|         <mask id="mask0" | ||||
|               mask-type="alpha" | ||||
|               maskUnits="userSpaceOnUse" | ||||
|               x="0" | ||||
|               y="0" | ||||
|               width="100" | ||||
|               height="100" | ||||
|         <mask | ||||
|             id="mask0" | ||||
|             mask-type="alpha" | ||||
|             maskUnits="userSpaceOnUse" | ||||
|             x="0" | ||||
|             y="0" | ||||
|             width="100" | ||||
|             height="100" | ||||
|         > | ||||
|             <circle cx="50" | ||||
|                     cy="50" | ||||
|                     r="50" | ||||
|                     fill="black" | ||||
|             <circle | ||||
|                 cx="50" | ||||
|                 cy="50" | ||||
|                 r="50" | ||||
|                 fill="black" | ||||
|             /> | ||||
|         </mask> | ||||
|         <g class="c-cr__compass-wrapper"> | ||||
|             <g class="c-cr__compass-main" | ||||
|                mask="url(#mask0)" | ||||
|             <g | ||||
|                 class="c-cr__compass-main" | ||||
|                 mask="url(#mask0)" | ||||
|             > | ||||
|                 <!-- Background and clipped elements --> | ||||
|                 <rect class="c-cr__bg" | ||||
|                       width="100" | ||||
|                       height="100" | ||||
|                       fill="black" | ||||
|                 <rect | ||||
|                     class="c-cr__bg" | ||||
|                     width="100" | ||||
|                     height="100" | ||||
|                     fill="black" | ||||
|                 /> | ||||
|                 <rect class="c-cr__edge" | ||||
|                       width="100" | ||||
|                       height="100" | ||||
|                       fill="url(#paint0_radial)" | ||||
|                 <rect | ||||
|                     class="c-cr__edge" | ||||
|                     width="100" | ||||
|                     height="100" | ||||
|                     fill="url(#paint0_radial)" | ||||
|                 /> | ||||
|                 <rect v-if="hasSunHeading" | ||||
|                       class="c-cr__sun" | ||||
|                       width="100" | ||||
|                       height="100" | ||||
|                       fill="url(#paint1_radial)" | ||||
|                       :style="sunHeadingStyle" | ||||
|                 <rect | ||||
|                     v-if="hasSunHeading" | ||||
|                     class="c-cr__sun" | ||||
|                     width="100" | ||||
|                     height="100" | ||||
|                     fill="url(#paint1_radial)" | ||||
|                     :style="sunHeadingStyle" | ||||
|                 /> | ||||
|  | ||||
|                 <!-- Camera FOV --> | ||||
|                 <mask id="mask2" | ||||
|                       class="c-cr__cam-fov-l-mask" | ||||
|                       mask-type="alpha" | ||||
|                       maskUnits="userSpaceOnUse" | ||||
|                       x="0" | ||||
|                       y="0" | ||||
|                       width="50" | ||||
|                       height="100" | ||||
|                 <mask | ||||
|                     id="mask2" | ||||
|                     class="c-cr__cam-fov-l-mask" | ||||
|                     mask-type="alpha" | ||||
|                     maskUnits="userSpaceOnUse" | ||||
|                     x="0" | ||||
|                     y="0" | ||||
|                     width="50" | ||||
|                     height="100" | ||||
|                 > | ||||
|                     <rect width="51" | ||||
|                           height="100" | ||||
|                     <rect | ||||
|                         width="51" | ||||
|                         height="100" | ||||
|                     /> | ||||
|                 </mask> | ||||
|                 <mask id="mask1" | ||||
|                       class="c-cr__cam-fov-r-mask" | ||||
|                       mask-type="alpha" | ||||
|                       maskUnits="userSpaceOnUse" | ||||
|                       x="50" | ||||
|                       y="0" | ||||
|                       width="50" | ||||
|                       height="100" | ||||
|                 <mask | ||||
|                     id="mask1" | ||||
|                     class="c-cr__cam-fov-r-mask" | ||||
|                     mask-type="alpha" | ||||
|                     maskUnits="userSpaceOnUse" | ||||
|                     x="50" | ||||
|                     y="0" | ||||
|                     width="50" | ||||
|                     height="100" | ||||
|                 > | ||||
|                     <rect x="49" | ||||
|                           width="51" | ||||
|                           height="100" | ||||
|                     <rect | ||||
|                         x="49" | ||||
|                         width="51" | ||||
|                         height="100" | ||||
|                     /> | ||||
|                 </mask> | ||||
|                 <g class="c-cr__cam-fov" | ||||
|                    :style="cameraPanStyle" | ||||
|                 <g | ||||
|                     class="c-cr__cam-fov" | ||||
|                     :style="cameraPanStyle" | ||||
|                 > | ||||
|                     <g mask="url(#mask2)"> | ||||
|                         <rect class="c-cr__cam-fov-r" | ||||
|                               x="49" | ||||
|                               width="51" | ||||
|                               height="100" | ||||
|                               :style="cameraFOVStyleRightHalf" | ||||
|                         <rect | ||||
|                             class="c-cr__cam-fov-r" | ||||
|                             x="49" | ||||
|                             width="51" | ||||
|                             height="100" | ||||
|                             :style="cameraFOVStyleRightHalf" | ||||
|                         /> | ||||
|                     </g> | ||||
|                     <g mask="url(#mask1)"> | ||||
|                         <rect class="c-cr__cam-fov-l" | ||||
|                               width="51" | ||||
|                               height="100" | ||||
|                               :style="cameraFOVStyleLeftHalf" | ||||
|                         <rect | ||||
|                             class="c-cr__cam-fov-l" | ||||
|                             width="51" | ||||
|                             height="100" | ||||
|                             :style="cameraFOVStyleLeftHalf" | ||||
|                         /> | ||||
|                     </g> | ||||
|                 </g> | ||||
|             </g> | ||||
|  | ||||
|             <!-- Spacecraft body --> | ||||
|             <path v-if="hasHeading" | ||||
|                   class="c-cr__spacecraft-body" | ||||
|                   fill-rule="evenodd" | ||||
|                   clip-rule="evenodd" | ||||
|                   d="M37 49C35.3431 49 34 50.3431 34 52V82C34 83.6569 35.3431 85 37 85H63C64.6569 85 66 83.6569 66 82V52C66 50.3431 64.6569 49 63 49H37ZM50 52L58 60H55V67H45V60H42L50 52Z" | ||||
|                   :style="headingStyle" | ||||
|             <path | ||||
|                 v-if="hasHeading" | ||||
|                 class="c-cr__spacecraft-body" | ||||
|                 fill-rule="evenodd" | ||||
|                 clip-rule="evenodd" | ||||
|                 d="M37 49C35.3431 49 34 50.3431 34 52V82C34 83.6569 35.3431 85 37 85H63C64.6569 85 66 83.6569 66 82V52C66 50.3431 64.6569 49 63 49H37ZM50 52L58 60H55V67H45V60H42L50 52Z" | ||||
|                 :style="headingStyle" | ||||
|             /> | ||||
|  | ||||
|             <!-- NSEW and ticks --> | ||||
|             <g class="c-cr__nsew" | ||||
|                :style="compassRoseStyle" | ||||
|             <g | ||||
|                 class="c-cr__nsew" | ||||
|                 :style="compassRoseStyle" | ||||
|             > | ||||
|                 <g class="c-cr__ticks-major"> | ||||
|                     <path d="M50 3L43 10H57L50 3Z" /> | ||||
|                     <path d="M4 51V49H10V51H4Z" | ||||
|                           class="--hide-min" | ||||
|                     <path | ||||
|                         d="M4 51V49H10V51H4Z" | ||||
|                         class="--hide-min" | ||||
|                     /> | ||||
|                     <path d="M49 96V90H51V96H49Z" | ||||
|                           class="--hide-min" | ||||
|                     <path | ||||
|                         d="M49 96V90H51V96H49Z" | ||||
|                         class="--hide-min" | ||||
|                     /> | ||||
|                     <path d="M90 49V51H96V49H90Z" | ||||
|                           class="--hide-min" | ||||
|                     <path | ||||
|                         d="M90 49V51H96V49H90Z" | ||||
|                         class="--hide-min" | ||||
|                     /> | ||||
|                 </g> | ||||
|                 <g class="c-cr__ticks-minor --hide-small"> | ||||
| @@ -148,53 +168,63 @@ | ||||
|                     <path d="M51 10L49 10V4L51 4V10Z" /> | ||||
|                 </g> | ||||
|                 <g class="c-cr__nsew-text"> | ||||
|                     <path :style="cardinalTextRotateW" | ||||
|                           class="c-cr__nsew-w --hide-small" | ||||
|                           d="M56.7418 45.004H54.1378L52.7238 52.312H52.6958L51.2258 45.004H48.7758L47.3058 52.312H47.2778L45.8638 45.004H43.2598L45.9618 55H48.6078L49.9798 48.112H50.0078L51.3798 55H53.9838L56.7418 45.004Z" | ||||
|                     <path | ||||
|                         :style="cardinalTextRotateW" | ||||
|                         class="c-cr__nsew-w --hide-small" | ||||
|                         d="M56.7418 45.004H54.1378L52.7238 52.312H52.6958L51.2258 45.004H48.7758L47.3058 52.312H47.2778L45.8638 45.004H43.2598L45.9618 55H48.6078L49.9798 48.112H50.0078L51.3798 55H53.9838L56.7418 45.004Z" | ||||
|                     /> | ||||
|                     <path :style="cardinalTextRotateE" | ||||
|                           class="c-cr__nsew-e --hide-small" | ||||
|                           d="M46.104 55H54.21V52.76H48.708V50.856H53.608V48.84H48.708V47.09H54.07V45.004H46.104V55Z" | ||||
|                     <path | ||||
|                         :style="cardinalTextRotateE" | ||||
|                         class="c-cr__nsew-e --hide-small" | ||||
|                         d="M46.104 55H54.21V52.76H48.708V50.856H53.608V48.84H48.708V47.09H54.07V45.004H46.104V55Z" | ||||
|                     /> | ||||
|                     <path :style="cardinalTextRotateS" | ||||
|                           class="c-cr__nsew-s --hide-small" | ||||
|                           d="M45.6531 51.64C45.6671 54.202 47.6971 55.21 49.9931 55.21C52.1911 55.21 54.3471 54.398 54.3471 51.864C54.3471 50.058 52.8911 49.386 51.4491 48.98C49.9931 48.574 48.5511 48.434 48.5511 47.664C48.5511 47.006 49.2511 46.81 49.8111 46.81C50.6091 46.81 51.4631 47.104 51.4211 48.014H54.0251C54.0111 45.76 52.0091 44.794 50.0211 44.794C48.1451 44.794 45.9471 45.648 45.9471 47.832C45.9471 49.666 47.4451 50.31 48.8731 50.716C50.3151 51.122 51.7431 51.29 51.7431 52.172C51.7431 52.914 50.9311 53.194 50.1471 53.194C49.0411 53.194 48.3131 52.816 48.2571 51.64H45.6531Z" | ||||
|                     <path | ||||
|                         :style="cardinalTextRotateS" | ||||
|                         class="c-cr__nsew-s --hide-small" | ||||
|                         d="M45.6531 51.64C45.6671 54.202 47.6971 55.21 49.9931 55.21C52.1911 55.21 54.3471 54.398 54.3471 51.864C54.3471 50.058 52.8911 49.386 51.4491 48.98C49.9931 48.574 48.5511 48.434 48.5511 47.664C48.5511 47.006 49.2511 46.81 49.8111 46.81C50.6091 46.81 51.4631 47.104 51.4211 48.014H54.0251C54.0111 45.76 52.0091 44.794 50.0211 44.794C48.1451 44.794 45.9471 45.648 45.9471 47.832C45.9471 49.666 47.4451 50.31 48.8731 50.716C50.3151 51.122 51.7431 51.29 51.7431 52.172C51.7431 52.914 50.9311 53.194 50.1471 53.194C49.0411 53.194 48.3131 52.816 48.2571 51.64H45.6531Z" | ||||
|                     /> | ||||
|                     <path :style="cardinalTextRotateN" | ||||
|                           class="c-cr__nsew-n" | ||||
|                           d="M42.5935 60H46.7935V49.32H46.8415L52.7935 60H57.3775V42.864H53.1775V53.424H53.1295L47.1775 42.864H42.5935V60Z" | ||||
|                     <path | ||||
|                         :style="cardinalTextRotateN" | ||||
|                         class="c-cr__nsew-n" | ||||
|                         d="M42.5935 60H46.7935V49.32H46.8415L52.7935 60H57.3775V42.864H53.1775V53.424H53.1295L47.1775 42.864H42.5935V60Z" | ||||
|                     /> | ||||
|                 </g> | ||||
|             </g> | ||||
|         </g> | ||||
|         <defs> | ||||
|             <radialGradient id="paint0_radial" | ||||
|                             cx="0" | ||||
|                             cy="0" | ||||
|                             r="1" | ||||
|                             gradientUnits="userSpaceOnUse" | ||||
|                             gradientTransform="translate(50 50) rotate(90) scale(50)" | ||||
|             <radialGradient | ||||
|                 id="paint0_radial" | ||||
|                 cx="0" | ||||
|                 cy="0" | ||||
|                 r="1" | ||||
|                 gradientUnits="userSpaceOnUse" | ||||
|                 gradientTransform="translate(50 50) rotate(90) scale(50)" | ||||
|             > | ||||
|                 <stop offset="0.751387" | ||||
|                       stop-opacity="0" | ||||
|                 <stop | ||||
|                     offset="0.751387" | ||||
|                     stop-opacity="0" | ||||
|                 /> | ||||
|                 <stop offset="1" | ||||
|                       stop-color="white" | ||||
|                 <stop | ||||
|                     offset="1" | ||||
|                     stop-color="white" | ||||
|                 /> | ||||
|             </radialGradient> | ||||
|             <radialGradient id="paint1_radial" | ||||
|                             cx="0" | ||||
|                             cy="0" | ||||
|                             r="1" | ||||
|                             gradientUnits="userSpaceOnUse" | ||||
|                             gradientTransform="translate(50 -7) rotate(-90) scale(18.5)" | ||||
|             <radialGradient | ||||
|                 id="paint1_radial" | ||||
|                 cx="0" | ||||
|                 cy="0" | ||||
|                 r="1" | ||||
|                 gradientUnits="userSpaceOnUse" | ||||
|                 gradientTransform="translate(50 -7) rotate(-90) scale(18.5)" | ||||
|             > | ||||
|                 <stop offset="0.716377" | ||||
|                       stop-color="#FFCC00" | ||||
|                 <stop | ||||
|                     offset="0.716377" | ||||
|                     stop-color="#FFCC00" | ||||
|                 /> | ||||
|                 <stop offset="1" | ||||
|                       stop-color="#FF9900" | ||||
|                       stop-opacity="0" | ||||
|                 <stop | ||||
|                     offset="1" | ||||
|                     stop-color="#FF9900" | ||||
|                     stop-opacity="0" | ||||
|                 /> | ||||
|             </radialGradient> | ||||
|         </defs> | ||||
|   | ||||
| @@ -21,11 +21,13 @@ | ||||
| --> | ||||
|  | ||||
| <template> | ||||
| <div ref="imagery" | ||||
|      class="c-imagery-tsv c-timeline-holder" | ||||
| <div | ||||
|     ref="imagery" | ||||
|     class="c-imagery-tsv c-timeline-holder" | ||||
| > | ||||
|     <div ref="imageryHolder" | ||||
|          class="c-imagery-tsv__contents u-contents" | ||||
|     <div | ||||
|         ref="imageryHolder" | ||||
|         class="c-imagery-tsv__contents u-contents" | ||||
|     > | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -30,50 +30,57 @@ | ||||
| > | ||||
|     <div class="c-imagery__main-image-wrapper has-local-controls"> | ||||
|         <div class="h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover c-image-controls__controls"> | ||||
|             <span class="c-image-controls__sliders" | ||||
|                   draggable="true" | ||||
|                   @dragstart="startDrag" | ||||
|             <span | ||||
|                 class="c-image-controls__sliders" | ||||
|                 draggable="true" | ||||
|                 @dragstart="startDrag" | ||||
|             > | ||||
|                 <div class="c-image-controls__slider-wrapper icon-brightness"> | ||||
|                     <input v-model="filters.brightness" | ||||
|                            type="range" | ||||
|                            min="0" | ||||
|                            max="500" | ||||
|                     <input | ||||
|                         v-model="filters.brightness" | ||||
|                         type="range" | ||||
|                         min="0" | ||||
|                         max="500" | ||||
|                     > | ||||
|                 </div> | ||||
|                 <div class="c-image-controls__slider-wrapper icon-contrast"> | ||||
|                     <input v-model="filters.contrast" | ||||
|                            type="range" | ||||
|                            min="0" | ||||
|                            max="500" | ||||
|                     <input | ||||
|                         v-model="filters.contrast" | ||||
|                         type="range" | ||||
|                         min="0" | ||||
|                         max="500" | ||||
|                     > | ||||
|                 </div> | ||||
|             </span> | ||||
|             <span class="t-reset-btn-holder c-imagery__lc__reset-btn c-image-controls__btn-reset"> | ||||
|                 <a class="s-icon-button icon-reset t-btn-reset" | ||||
|                    @click="filters={brightness: 100, contrast: 100}" | ||||
|                 <a | ||||
|                     class="s-icon-button icon-reset t-btn-reset" | ||||
|                     @click="filters={brightness: 100, contrast: 100}" | ||||
|                 ></a> | ||||
|             </span> | ||||
|         </div> | ||||
|         <div ref="imageBG" | ||||
|              class="c-imagery__main-image__bg" | ||||
|              :class="{'paused unnsynced': isPaused && !isFixed,'stale':false }" | ||||
|              @click="expand" | ||||
|         <div | ||||
|             ref="imageBG" | ||||
|             class="c-imagery__main-image__bg" | ||||
|             :class="{'paused unnsynced': isPaused && !isFixed,'stale':false }" | ||||
|             @click="expand" | ||||
|         > | ||||
|             <div class="image-wrapper" | ||||
|                  :style="{ | ||||
|                      'width': `${sizedImageDimensions.width}px`, | ||||
|                      'height': `${sizedImageDimensions.height}px` | ||||
|                  }" | ||||
|             <div | ||||
|                 class="image-wrapper" | ||||
|                 :style="{ | ||||
|                     'width': `${sizedImageDimensions.width}px`, | ||||
|                     'height': `${sizedImageDimensions.height}px` | ||||
|                 }" | ||||
|             > | ||||
|                 <img ref="focusedImage" | ||||
|                      class="c-imagery__main-image__image js-imageryView-image" | ||||
|                      :src="imageUrl" | ||||
|                      :style="{ | ||||
|                          'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)` | ||||
|                      }" | ||||
|                      :data-openmct-image-timestamp="time" | ||||
|                      :data-openmct-object-keystring="keyString" | ||||
|                 <img | ||||
|                     ref="focusedImage" | ||||
|                     class="c-imagery__main-image__image js-imageryView-image" | ||||
|                     :src="imageUrl" | ||||
|                     :style="{ | ||||
|                         'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)` | ||||
|                     }" | ||||
|                     :data-openmct-image-timestamp="time" | ||||
|                     :data-openmct-object-keystring="keyString" | ||||
|                 > | ||||
|                 <Compass | ||||
|                     v-if="shouldDisplayCompass" | ||||
| @@ -85,16 +92,18 @@ | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <button class="c-local-controls c-local-controls--show-on-hover c-imagery__prev-next-button c-nav c-nav--prev" | ||||
|                 title="Previous image" | ||||
|                 :disabled="isPrevDisabled" | ||||
|                 @click="prevImage()" | ||||
|         <button | ||||
|             class="c-local-controls c-local-controls--show-on-hover c-imagery__prev-next-button c-nav c-nav--prev" | ||||
|             title="Previous image" | ||||
|             :disabled="isPrevDisabled" | ||||
|             @click="prevImage()" | ||||
|         ></button> | ||||
|  | ||||
|         <button class="c-local-controls c-local-controls--show-on-hover c-imagery__prev-next-button c-nav c-nav--next" | ||||
|                 title="Next image" | ||||
|                 :disabled="isNextDisabled" | ||||
|                 @click="nextImage()" | ||||
|         <button | ||||
|             class="c-local-controls c-local-controls--show-on-hover c-imagery__prev-next-button c-nav c-nav--next" | ||||
|             title="Next image" | ||||
|             :disabled="isNextDisabled" | ||||
|             @click="nextImage()" | ||||
|         ></button> | ||||
|  | ||||
|         <div class="c-imagery__control-bar"> | ||||
| @@ -130,29 +139,33 @@ | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="c-imagery__thumbs-wrapper" | ||||
|          :class="[ | ||||
|              { 'is-paused': isPaused && !isFixed }, | ||||
|              { 'is-autoscroll-off': !resizingWindow && !autoScroll && !isPaused } | ||||
|          ]" | ||||
|     <div | ||||
|         class="c-imagery__thumbs-wrapper" | ||||
|         :class="[ | ||||
|             { 'is-paused': isPaused && !isFixed }, | ||||
|             { 'is-autoscroll-off': !resizingWindow && !autoScroll && !isPaused } | ||||
|         ]" | ||||
|     > | ||||
|         <div | ||||
|             ref="thumbsWrapper" | ||||
|             class="c-imagery__thumbs-scroll-area" | ||||
|             @scroll="handleScroll" | ||||
|         > | ||||
|             <div v-for="(image, index) in imageHistory" | ||||
|                  :key="image.url + image.time" | ||||
|                  class="c-imagery__thumb c-thumb" | ||||
|                  :class="{ selected: focusedImageIndex === index && isPaused }" | ||||
|                  @click="setFocusedImage(index, thumbnailClick)" | ||||
|             <div | ||||
|                 v-for="(image, index) in imageHistory" | ||||
|                 :key="image.url + image.time" | ||||
|                 class="c-imagery__thumb c-thumb" | ||||
|                 :class="{ selected: focusedImageIndex === index && isPaused }" | ||||
|                 @click="setFocusedImage(index, thumbnailClick)" | ||||
|             > | ||||
|                 <a href="" | ||||
|                    :download="image.imageDownloadName" | ||||
|                    @click.prevent | ||||
|                 <a | ||||
|                     href="" | ||||
|                     :download="image.imageDownloadName" | ||||
|                     @click.prevent | ||||
|                 > | ||||
|                     <img class="c-thumb__image" | ||||
|                          :src="image.url" | ||||
|                     <img | ||||
|                         class="c-thumb__image" | ||||
|                         :src="image.url" | ||||
|                     > | ||||
|                 </a> | ||||
|                 <div class="c-thumb__timestamp">{{ image.formattedTime }}</div> | ||||
|   | ||||
| @@ -33,10 +33,7 @@ export default class LinkAction { | ||||
|     } | ||||
|  | ||||
|     appliesTo(objectPath) { | ||||
|         let domainObject = objectPath[0]; | ||||
|         let type = domainObject && this.openmct.types.get(domainObject.type); | ||||
|  | ||||
|         return type && type.definition.creatable; | ||||
|         return true; // link away! | ||||
|     } | ||||
|  | ||||
|     invoke(objectPath) { | ||||
| @@ -77,6 +74,7 @@ export default class LinkAction { | ||||
|                         { | ||||
|                             name: "location", | ||||
|                             control: "locator", | ||||
|                             parent: parentDomainObject, | ||||
|                             required: true, | ||||
|                             validate: this.validate(parentDomainObject), | ||||
|                             key: 'location' | ||||
| @@ -97,6 +95,10 @@ export default class LinkAction { | ||||
|             const parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier); | ||||
|             const objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier); | ||||
|  | ||||
|             if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             if (!parentCandidateKeystring || !currentParentKeystring) { | ||||
|                 return false; | ||||
|             } | ||||
|   | ||||
| @@ -126,6 +126,7 @@ export default class MoveAction { | ||||
|                         { | ||||
|                             name: "Location", | ||||
|                             control: "locator", | ||||
|                             parent: parentDomainObject, | ||||
|                             required: true, | ||||
|                             validate: this.validate(parentDomainObject), | ||||
|                             key: 'location' | ||||
| @@ -144,6 +145,10 @@ export default class MoveAction { | ||||
|             const parentCandidatePath = data.value; | ||||
|             const parentCandidate = parentCandidatePath[0]; | ||||
|  | ||||
|             if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier); | ||||
|             let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier); | ||||
|             let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier); | ||||
| @@ -174,8 +179,9 @@ export default class MoveAction { | ||||
|         let parentType = parent && this.openmct.types.get(parent.type); | ||||
|         let child = objectPath[0]; | ||||
|         let childType = child && this.openmct.types.get(child.type); | ||||
|         let isPersistable = this.openmct.objects.isPersistable(child.identifier); | ||||
|  | ||||
|         if (child.locked || (parent && parent.locked)) { | ||||
|         if (child.locked || (parent && parent.locked) || !isPersistable) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -23,46 +23,51 @@ | ||||
| <template> | ||||
| <div class="c-notebook"> | ||||
|     <div class="c-notebook__head"> | ||||
|         <Search class="c-notebook__search" | ||||
|                 :value="search" | ||||
|                 @input="search = $event" | ||||
|                 @clear="resetSearch()" | ||||
|         <Search | ||||
|             class="c-notebook__search" | ||||
|             :value="search" | ||||
|             @input="search = $event" | ||||
|             @clear="resetSearch()" | ||||
|         /> | ||||
|     </div> | ||||
|     <SearchResults v-if="search.length" | ||||
|                    ref="searchResults" | ||||
|                    :domain-object="domainObject" | ||||
|                    :results="searchResults" | ||||
|                    @changeSectionPage="changeSelectedSection" | ||||
|                    @updateEntries="updateEntries" | ||||
|     <SearchResults | ||||
|         v-if="search.length" | ||||
|         ref="searchResults" | ||||
|         :domain-object="domainObject" | ||||
|         :results="searchResults" | ||||
|         @changeSectionPage="changeSelectedSection" | ||||
|         @updateEntries="updateEntries" | ||||
|     /> | ||||
|     <div v-if="!search.length" | ||||
|          class="c-notebook__body" | ||||
|     <div | ||||
|         v-if="!search.length" | ||||
|         class="c-notebook__body" | ||||
|     > | ||||
|         <Sidebar ref="sidebar" | ||||
|                  class="c-notebook__nav c-sidebar c-drawer c-drawer--align-left" | ||||
|                  :class="[{'is-expanded': showNav}, {'c-drawer--push': !sidebarCoversEntries}, {'c-drawer--overlays': sidebarCoversEntries}]" | ||||
|                  :default-page-id="defaultPageId" | ||||
|                  :selected-page-id="getSelectedPageId()" | ||||
|                  :default-section-id="defaultSectionId" | ||||
|                  :selected-section-id="getSelectedSectionId()" | ||||
|                  :domain-object="domainObject" | ||||
|                  :page-title="domainObject.configuration.pageTitle" | ||||
|                  :section-title="domainObject.configuration.sectionTitle" | ||||
|                  :sections="sections" | ||||
|                  :sidebar-covers-entries="sidebarCoversEntries" | ||||
|                  @defaultPageDeleted="cleanupDefaultNotebook" | ||||
|                  @defaultSectionDeleted="cleanupDefaultNotebook" | ||||
|                  @pagesChanged="pagesChanged" | ||||
|                  @selectPage="selectPage" | ||||
|                  @sectionsChanged="sectionsChanged" | ||||
|                  @selectSection="selectSection" | ||||
|                  @toggleNav="toggleNav" | ||||
|         <Sidebar | ||||
|             ref="sidebar" | ||||
|             class="c-notebook__nav c-sidebar c-drawer c-drawer--align-left" | ||||
|             :class="[{'is-expanded': showNav}, {'c-drawer--push': !sidebarCoversEntries}, {'c-drawer--overlays': sidebarCoversEntries}]" | ||||
|             :default-page-id="defaultPageId" | ||||
|             :selected-page-id="getSelectedPageId()" | ||||
|             :default-section-id="defaultSectionId" | ||||
|             :selected-section-id="getSelectedSectionId()" | ||||
|             :domain-object="domainObject" | ||||
|             :page-title="domainObject.configuration.pageTitle" | ||||
|             :section-title="domainObject.configuration.sectionTitle" | ||||
|             :sections="sections" | ||||
|             :sidebar-covers-entries="sidebarCoversEntries" | ||||
|             @defaultPageDeleted="cleanupDefaultNotebook" | ||||
|             @defaultSectionDeleted="cleanupDefaultNotebook" | ||||
|             @pagesChanged="pagesChanged" | ||||
|             @selectPage="selectPage" | ||||
|             @sectionsChanged="sectionsChanged" | ||||
|             @selectSection="selectSection" | ||||
|             @toggleNav="toggleNav" | ||||
|         /> | ||||
|         <div class="c-notebook__page-view"> | ||||
|             <div class="c-notebook__page-view__header"> | ||||
|                 <button class="c-notebook__toggle-nav-button c-icon-button c-icon-button--major icon-menu-hamburger" | ||||
|                         @click="toggleNav" | ||||
|                 <button | ||||
|                     class="c-notebook__toggle-nav-button c-icon-button c-icon-button--major icon-menu-hamburger" | ||||
|                     @click="toggleNav" | ||||
|                 ></button> | ||||
|                 <div class="c-notebook__page-view__path c-path"> | ||||
|                     <span class="c-notebook__path__section c-path__item"> | ||||
| @@ -73,59 +78,70 @@ | ||||
|                     </span> | ||||
|                 </div> | ||||
|                 <div class="c-notebook__page-view__controls"> | ||||
|                     <select v-model="showTime" | ||||
|                             class="c-notebook__controls__time" | ||||
|                     <select | ||||
|                         v-model="showTime" | ||||
|                         class="c-notebook__controls__time" | ||||
|                     > | ||||
|                         <option value="0" | ||||
|                                 :selected="showTime === 0" | ||||
|                         <option | ||||
|                             value="0" | ||||
|                             :selected="showTime === 0" | ||||
|                         > | ||||
|                             Show all | ||||
|                         </option> | ||||
|                         <option value="1" | ||||
|                                 :selected="showTime === 1" | ||||
|                         <option | ||||
|                             value="1" | ||||
|                             :selected="showTime === 1" | ||||
|                         >Last hour</option> | ||||
|                         <option value="8" | ||||
|                                 :selected="showTime === 8" | ||||
|                         <option | ||||
|                             value="8" | ||||
|                             :selected="showTime === 8" | ||||
|                         >Last 8 hours</option> | ||||
|                         <option value="24" | ||||
|                                 :selected="showTime === 24" | ||||
|                         <option | ||||
|                             value="24" | ||||
|                             :selected="showTime === 24" | ||||
|                         >Last 24 hours</option> | ||||
|                     </select> | ||||
|                     <select v-model="defaultSort" | ||||
|                             class="c-notebook__controls__time" | ||||
|                     <select | ||||
|                         v-model="defaultSort" | ||||
|                         class="c-notebook__controls__time" | ||||
|                     > | ||||
|                         <option value="newest" | ||||
|                                 :selected="defaultSort === 'newest'" | ||||
|                         <option | ||||
|                             value="newest" | ||||
|                             :selected="defaultSort === 'newest'" | ||||
|                         >Newest first</option> | ||||
|                         <option value="oldest" | ||||
|                                 :selected="defaultSort === 'oldest'" | ||||
|                         <option | ||||
|                             value="oldest" | ||||
|                             :selected="defaultSort === 'oldest'" | ||||
|                         >Oldest first</option> | ||||
|                     </select> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div class="c-notebook__drag-area icon-plus" | ||||
|                  @click="newEntry()" | ||||
|                  @dragover="dragOver" | ||||
|                  @drop.capture="dropCapture" | ||||
|                  @drop="dropOnEntry($event)" | ||||
|             <div | ||||
|                 class="c-notebook__drag-area icon-plus" | ||||
|                 @click="newEntry()" | ||||
|                 @dragover="dragOver" | ||||
|                 @drop.capture="dropCapture" | ||||
|                 @drop="dropOnEntry($event)" | ||||
|             > | ||||
|                 <span class="c-notebook__drag-area__label"> | ||||
|                     To start a new entry, click here or drag and drop any object | ||||
|                 </span> | ||||
|             </div> | ||||
|             <div v-if="selectedSection && selectedPage" | ||||
|                  ref="notebookEntries" | ||||
|                  class="c-notebook__entries" | ||||
|             <div | ||||
|                 v-if="selectedSection && selectedPage" | ||||
|                 ref="notebookEntries" | ||||
|                 class="c-notebook__entries" | ||||
|             > | ||||
|                 <NotebookEntry v-for="entry in filteredAndSortedEntries" | ||||
|                                :key="entry.id" | ||||
|                                :entry="entry" | ||||
|                                :domain-object="domainObject" | ||||
|                                :selected-page="selectedPage" | ||||
|                                :selected-section="selectedSection" | ||||
|                                :read-only="false" | ||||
|                                @deleteEntry="deleteEntry" | ||||
|                                @updateEntry="updateEntry" | ||||
|                 <NotebookEntry | ||||
|                     v-for="entry in filteredAndSortedEntries" | ||||
|                     :key="entry.id" | ||||
|                     :entry="entry" | ||||
|                     :domain-object="domainObject" | ||||
|                     :selected-page="selectedPage" | ||||
|                     :selected-section="selectedSection" | ||||
|                     :read-only="false" | ||||
|                     @deleteEntry="deleteEntry" | ||||
|                     @updateEntry="updateEntry" | ||||
|                 /> | ||||
|             </div> | ||||
|         </div> | ||||
| @@ -438,6 +454,8 @@ export default { | ||||
|             const classList = document.querySelector('body').classList; | ||||
|             const isPhone = Array.from(classList).includes('phone'); | ||||
|             const isTablet = Array.from(classList).includes('tablet'); | ||||
|             // address in https://github.com/nasa/openmct/issues/4875 | ||||
|             // eslint-disable-next-line compat/compat | ||||
|             const isPortrait = window.screen.orientation.type.includes('portrait'); | ||||
|             const isInLayout = Boolean(this.$el.closest('.c-so-view')); | ||||
|             const sidebarCoversEntries = (isPhone || (isTablet && isPortrait) || isInLayout); | ||||
|   | ||||
| @@ -1,21 +1,24 @@ | ||||
| <template> | ||||
| <div class="c-snapshot c-ne__embed"> | ||||
|     <div v-if="embed.snapshot" | ||||
|          class="c-ne__embed__snap-thumb" | ||||
|          @click="openSnapshot()" | ||||
|     <div | ||||
|         v-if="embed.snapshot" | ||||
|         class="c-ne__embed__snap-thumb" | ||||
|         @click="openSnapshot()" | ||||
|     > | ||||
|         <img :src="thumbnailImage"> | ||||
|     </div> | ||||
|     <div class="c-ne__embed__info"> | ||||
|         <div class="c-ne__embed__name"> | ||||
|             <a class="c-ne__embed__link" | ||||
|                :class="embed.cssClass" | ||||
|                @click="changeLocation" | ||||
|             <a | ||||
|                 class="c-ne__embed__link" | ||||
|                 :class="embed.cssClass" | ||||
|                 @click="changeLocation" | ||||
|             >{{ embed.name }}</a> | ||||
|             <PopupMenu :popup-menu-items="popupMenuItems" /> | ||||
|         </div> | ||||
|         <div v-if="embed.snapshot" | ||||
|              class="c-ne__embed__time" | ||||
|         <div | ||||
|             v-if="embed.snapshot" | ||||
|             class="c-ne__embed__time" | ||||
|         > | ||||
|             {{ createdOn }} | ||||
|         </div> | ||||
|   | ||||
| @@ -21,10 +21,11 @@ | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <div class="c-notebook__entry c-ne has-local-controls" | ||||
|      @dragover="changeCursor" | ||||
|      @drop.capture="cancelEditMode" | ||||
|      @drop.prevent="dropOnEntry" | ||||
| <div | ||||
|     class="c-notebook__entry c-ne has-local-controls" | ||||
|     @dragover="changeCursor" | ||||
|     @drop.capture="cancelEditMode" | ||||
|     @drop.prevent="dropOnEntry" | ||||
| > | ||||
|     <div class="c-ne__time-and-content"> | ||||
|         <div class="c-ne__time"> | ||||
| @@ -62,27 +63,31 @@ | ||||
|                 </div> | ||||
|             </template> | ||||
|             <div class="c-snapshots c-ne__embeds"> | ||||
|                 <NotebookEmbed v-for="embed in entry.embeds" | ||||
|                                :key="embed.id" | ||||
|                                :embed="embed" | ||||
|                                @removeEmbed="removeEmbed" | ||||
|                                @updateEmbed="updateEmbed" | ||||
|                 <NotebookEmbed | ||||
|                     v-for="embed in entry.embeds" | ||||
|                     :key="embed.id" | ||||
|                     :embed="embed" | ||||
|                     @removeEmbed="removeEmbed" | ||||
|                     @updateEmbed="updateEmbed" | ||||
|                 /> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div v-if="!readOnly" | ||||
|          class="c-ne__local-controls--hidden" | ||||
|     <div | ||||
|         v-if="!readOnly" | ||||
|         class="c-ne__local-controls--hidden" | ||||
|     > | ||||
|         <button class="c-icon-button c-icon-button--major icon-trash" | ||||
|                 title="Delete this entry" | ||||
|                 tabindex="-1" | ||||
|                 @click="deleteEntry" | ||||
|         <button | ||||
|             class="c-icon-button c-icon-button--major icon-trash" | ||||
|             title="Delete this entry" | ||||
|             tabindex="-1" | ||||
|             @click="deleteEntry" | ||||
|         > | ||||
|         </button> | ||||
|     </div> | ||||
|     <div v-if="readOnly" | ||||
|          class="c-ne__section-and-page" | ||||
|     <div | ||||
|         v-if="readOnly" | ||||
|         class="c-ne__section-and-page" | ||||
|     > | ||||
|         <a | ||||
|             class="c-click-link" | ||||
|   | ||||
| @@ -8,39 +8,45 @@ | ||||
|                     <div class="c-object-label__name"> | ||||
|                         Notebook Snapshots | ||||
|                     </div> | ||||
|                     <div v-if="snapshots.length" | ||||
|                          class="l-browse-bar__object-details" | ||||
|                     <div | ||||
|                         v-if="snapshots.length" | ||||
|                         class="l-browse-bar__object-details" | ||||
|                     >{{ snapshots.length }} of {{ getNotebookSnapshotMaxCount() }} | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <PopupMenu v-if="snapshots.length > 0" | ||||
|                            :popup-menu-items="popupMenuItems" | ||||
|                 <PopupMenu | ||||
|                     v-if="snapshots.length > 0" | ||||
|                     :popup-menu-items="popupMenuItems" | ||||
|                 /> | ||||
|             </div> | ||||
|  | ||||
|         </div> | ||||
|         <div class="l-browse-bar__end"> | ||||
|             <button class="c-click-icon c-click-icon--major icon-x" | ||||
|                     @click="close" | ||||
|             <button | ||||
|                 class="c-click-icon c-click-icon--major icon-x" | ||||
|                 @click="close" | ||||
|             ></button> | ||||
|         </div> | ||||
|     </div><!-- closes l-browse-bar --> | ||||
|     <div class="c-snapshots"> | ||||
|         <span v-for="snapshot in snapshots" | ||||
|               :key="snapshot.embedObject.id" | ||||
|               draggable="true" | ||||
|               @dragstart="startEmbedDrag(snapshot, $event)" | ||||
|         <span | ||||
|             v-for="snapshot in snapshots" | ||||
|             :key="snapshot.embedObject.id" | ||||
|             draggable="true" | ||||
|             @dragstart="startEmbedDrag(snapshot, $event)" | ||||
|         > | ||||
|             <NotebookEmbed ref="notebookEmbed" | ||||
|                            :key="snapshot.embedObject.id" | ||||
|                            :embed="snapshot.embedObject" | ||||
|                            :is-snapshot-container="true" | ||||
|                            :remove-action-string="'Delete Snapshot'" | ||||
|                            @removeEmbed="removeSnapshot" | ||||
|             <NotebookEmbed | ||||
|                 ref="notebookEmbed" | ||||
|                 :key="snapshot.embedObject.id" | ||||
|                 :embed="snapshot.embedObject" | ||||
|                 :is-snapshot-container="true" | ||||
|                 :remove-action-string="'Delete Snapshot'" | ||||
|                 @removeEmbed="removeSnapshot" | ||||
|             /> | ||||
|         </span> | ||||
|         <div v-if="!snapshots.length > 0" | ||||
|              class="hint" | ||||
|         <div | ||||
|             v-if="!snapshots.length > 0" | ||||
|             class="hint" | ||||
|         > | ||||
|             There are no Notebook Snapshots currently. | ||||
|         </div> | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| <template> | ||||
| <div class="c-indicator c-indicator--clickable icon-camera" | ||||
|      :class="[ | ||||
|          { 's-status-off': snapshotCount === 0 }, | ||||
|          { 's-status-on': snapshotCount > 0 }, | ||||
|          { 's-status-caution': snapshotCount === snapshotMaxCount }, | ||||
|          { 'has-new-snapshot': flashIndicator } | ||||
|      ]" | ||||
| <div | ||||
|     class="c-indicator c-indicator--clickable icon-camera" | ||||
|     :class="[ | ||||
|         { 's-status-off': snapshotCount === 0 }, | ||||
|         { 's-status-on': snapshotCount > 0 }, | ||||
|         { 's-status-caution': snapshotCount === snapshotMaxCount }, | ||||
|         { 'has-new-snapshot': flashIndicator } | ||||
|     ]" | ||||
| > | ||||
|     <span class="label c-indicator__label"> | ||||
|         {{ indicatorTitle }} | ||||
|   | ||||
| @@ -1,17 +1,19 @@ | ||||
| <template> | ||||
| <ul class="c-list"> | ||||
|     <li v-for="page in pages" | ||||
|     <li | ||||
|         v-for="page in pages" | ||||
|         :key="page.id" | ||||
|         class="c-list__item-h" | ||||
|     > | ||||
|         <Page ref="pageComponent" | ||||
|               :default-page-id="defaultPageId" | ||||
|               :selected-page-id="selectedPageId" | ||||
|               :page="page" | ||||
|               :page-title="pageTitle" | ||||
|               @deletePage="deletePage" | ||||
|               @renamePage="updatePage" | ||||
|               @selectPage="selectPage" | ||||
|         <Page | ||||
|             ref="pageComponent" | ||||
|             :default-page-id="defaultPageId" | ||||
|             :selected-page-id="selectedPageId" | ||||
|             :page="page" | ||||
|             :page-title="pageTitle" | ||||
|             @deletePage="deletePage" | ||||
|             @renamePage="updatePage" | ||||
|             @selectPage="selectPage" | ||||
|         /> | ||||
|     </li> | ||||
| </ul> | ||||
|   | ||||
| @@ -1,13 +1,15 @@ | ||||
| <template> | ||||
| <div class="c-list__item js-list__item" | ||||
|      :class="[{ 'is-selected': isSelected, 'is-notebook-default' : (defaultPageId === page.id) }]" | ||||
|      :data-id="page.id" | ||||
|      @click="selectPage" | ||||
| <div | ||||
|     class="c-list__item js-list__item" | ||||
|     :class="[{ 'is-selected': isSelected, 'is-notebook-default' : (defaultPageId === page.id) }]" | ||||
|     :data-id="page.id" | ||||
|     @click="selectPage" | ||||
| > | ||||
|     <span class="c-list__item__name js-list__item__name" | ||||
|           :data-id="page.id" | ||||
|           @keydown.enter="updateName" | ||||
|           @blur="updateName" | ||||
|     <span | ||||
|         class="c-list__item__name js-list__item__name" | ||||
|         :data-id="page.id" | ||||
|         @keydown.enter="updateName" | ||||
|         @blur="updateName" | ||||
|     >{{ page.name.length ? page.name : `Unnamed ${pageTitle}` }}</span> | ||||
|     <PopupMenu :popup-menu-items="popupMenuItems" /> | ||||
| </div> | ||||
|   | ||||
| @@ -24,16 +24,17 @@ | ||||
| <div class="c-notebook__search-results"> | ||||
|     <div class="c-notebook__search-results__header">Search Results ({{ results.length }})</div> | ||||
|     <div class="c-notebook__entries"> | ||||
|         <NotebookEntry v-for="(result, index) in results" | ||||
|                        :key="index" | ||||
|                        :domain-object="domainObject" | ||||
|                        :result="result" | ||||
|                        :entry="result.entry" | ||||
|                        :read-only="true" | ||||
|                        :selected-page="result.page" | ||||
|                        :selected-section="result.section" | ||||
|                        @changeSectionPage="changeSectionPage" | ||||
|                        @updateEntries="updateEntries" | ||||
|         <NotebookEntry | ||||
|             v-for="(result, index) in results" | ||||
|             :key="index" | ||||
|             :domain-object="domainObject" | ||||
|             :result="result" | ||||
|             :entry="result.entry" | ||||
|             :read-only="true" | ||||
|             :selected-page="result.page" | ||||
|             :selected-section="result.section" | ||||
|             @changeSectionPage="changeSectionPage" | ||||
|             @updateEntries="updateEntries" | ||||
|         /> | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -1,17 +1,19 @@ | ||||
| <template> | ||||
| <ul class="c-list"> | ||||
|     <li v-for="section in sections" | ||||
|     <li | ||||
|         v-for="section in sections" | ||||
|         :key="section.id" | ||||
|         class="c-list__item-h" | ||||
|     > | ||||
|         <NotebookSection ref="sectionComponent" | ||||
|                          :default-section-id="defaultSectionId" | ||||
|                          :selected-section-id="selectedSectionId" | ||||
|                          :section="section" | ||||
|                          :section-title="sectionTitle" | ||||
|                          @deleteSection="deleteSection" | ||||
|                          @renameSection="updateSection" | ||||
|                          @selectSection="selectSection" | ||||
|         <NotebookSection | ||||
|             ref="sectionComponent" | ||||
|             :default-section-id="defaultSectionId" | ||||
|             :selected-section-id="selectedSectionId" | ||||
|             :section="section" | ||||
|             :section-title="sectionTitle" | ||||
|             @deleteSection="deleteSection" | ||||
|             @renameSection="updateSection" | ||||
|             @selectSection="selectSection" | ||||
|         /> | ||||
|     </li> | ||||
| </ul> | ||||
|   | ||||
| @@ -1,13 +1,15 @@ | ||||
| <template> | ||||
| <div class="c-list__item js-list__item" | ||||
|      :class="[{ 'is-selected': isSelected, 'is-notebook-default' : (defaultSectionId === section.id) }]" | ||||
|      :data-id="section.id" | ||||
|      @click="selectSection" | ||||
| <div | ||||
|     class="c-list__item js-list__item" | ||||
|     :class="[{ 'is-selected': isSelected, 'is-notebook-default' : (defaultSectionId === section.id) }]" | ||||
|     :data-id="section.id" | ||||
|     @click="selectSection" | ||||
| > | ||||
|     <span class="c-list__item__name js-list__item__name" | ||||
|           :data-id="section.id" | ||||
|           @keydown.enter="updateName" | ||||
|           @blur="updateName" | ||||
|     <span | ||||
|         class="c-list__item__name js-list__item__name" | ||||
|         :data-id="section.id" | ||||
|         @keydown.enter="updateName" | ||||
|         @blur="updateName" | ||||
|     >{{ section.name.length ? section.name : `Unnamed ${sectionTitle}` }}</span> | ||||
|     <PopupMenu :popup-menu-items="popupMenuItems" /> | ||||
| </div> | ||||
|   | ||||
| @@ -7,21 +7,23 @@ | ||||
|             </div> | ||||
|         </div> | ||||
|         <div class="c-sidebar__contents-and-controls"> | ||||
|             <button class="c-list-button" | ||||
|                     @click="addSection" | ||||
|             <button | ||||
|                 class="c-list-button" | ||||
|                 @click="addSection" | ||||
|             > | ||||
|                 <span class="c-button c-list-button__button icon-plus"></span> | ||||
|                 <span class="c-list-button__label">Add {{ sectionTitle }}</span> | ||||
|             </button> | ||||
|             <SectionCollection class="c-sidebar__contents" | ||||
|                                :default-section-id="defaultSectionId" | ||||
|                                :selected-section-id="selectedSectionId" | ||||
|                                :domain-object="domainObject" | ||||
|                                :sections="sections" | ||||
|                                :section-title="sectionTitle" | ||||
|                                @defaultSectionDeleted="defaultSectionDeleted" | ||||
|                                @updateSection="sectionsChanged" | ||||
|                                @selectSection="selectSection" | ||||
|             <SectionCollection | ||||
|                 class="c-sidebar__contents" | ||||
|                 :default-section-id="defaultSectionId" | ||||
|                 :selected-section-id="selectedSectionId" | ||||
|                 :domain-object="domainObject" | ||||
|                 :sections="sections" | ||||
|                 :section-title="sectionTitle" | ||||
|                 @defaultSectionDeleted="defaultSectionDeleted" | ||||
|                 @updateSection="sectionsChanged" | ||||
|                 @selectSection="selectSection" | ||||
|             /> | ||||
|         </div> | ||||
|     </div> | ||||
| @@ -30,31 +32,34 @@ | ||||
|             <div class="c-sidebar__header"> | ||||
|                 <span class="c-sidebar__header-label">{{ pageTitle }}</span> | ||||
|             </div> | ||||
|             <button class="c-click-icon c-click-icon--major icon-x-in-circle" | ||||
|                     @click="toggleNav" | ||||
|             <button | ||||
|                 class="c-click-icon c-click-icon--major icon-x-in-circle" | ||||
|                 @click="toggleNav" | ||||
|             ></button> | ||||
|         </div> | ||||
|  | ||||
|         <div class="c-sidebar__contents-and-controls"> | ||||
|             <button class="c-list-button" | ||||
|                     @click="addPage" | ||||
|             <button | ||||
|                 class="c-list-button" | ||||
|                 @click="addPage" | ||||
|             > | ||||
|                 <span class="c-button c-list-button__button icon-plus"></span> | ||||
|                 <span class="c-list-button__label">Add {{ pageTitle }}</span> | ||||
|             </button> | ||||
|             <PageCollection ref="pageCollection" | ||||
|                             class="c-sidebar__contents" | ||||
|                             :default-page-id="defaultPageId" | ||||
|                             :selected-page-id="selectedPageId" | ||||
|                             :domain-object="domainObject" | ||||
|                             :pages="pages" | ||||
|                             :sections="sections" | ||||
|                             :sidebar-covers-entries="sidebarCoversEntries" | ||||
|                             :page-title="pageTitle" | ||||
|                             @defaultPageDeleted="defaultPageDeleted" | ||||
|                             @toggleNav="toggleNav" | ||||
|                             @updatePage="pagesChanged" | ||||
|                             @selectPage="selectPage" | ||||
|             <PageCollection | ||||
|                 ref="pageCollection" | ||||
|                 class="c-sidebar__contents" | ||||
|                 :default-page-id="defaultPageId" | ||||
|                 :selected-page-id="selectedPageId" | ||||
|                 :domain-object="domainObject" | ||||
|                 :pages="pages" | ||||
|                 :sections="sections" | ||||
|                 :sidebar-covers-entries="sidebarCoversEntries" | ||||
|                 :page-title="pageTitle" | ||||
|                 @defaultPageDeleted="defaultPageDeleted" | ||||
|                 @toggleNav="toggleNav" | ||||
|                 @updatePage="pagesChanged" | ||||
|                 @selectPage="selectPage" | ||||
|             /> | ||||
|         </div> | ||||
|     </div> | ||||
|   | ||||
| @@ -21,8 +21,9 @@ | ||||
| --> | ||||
|  | ||||
| <template> | ||||
| <div ref="plan" | ||||
|      class="c-plan c-timeline-holder" | ||||
| <div | ||||
|     ref="plan" | ||||
|     class="c-plan c-timeline-holder" | ||||
| > | ||||
|     <template v-if="viewBounds && !options.compact"> | ||||
|         <swim-lane> | ||||
| @@ -36,8 +37,9 @@ | ||||
|             /> | ||||
|         </swim-lane> | ||||
|     </template> | ||||
|     <div ref="planHolder" | ||||
|          class="c-plan__contents u-contents" | ||||
|     <div | ||||
|         ref="planHolder" | ||||
|         class="c-plan__contents u-contents" | ||||
|     > | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -21,10 +21,11 @@ | ||||
| --> | ||||
| <template> | ||||
| <div class="c-inspector__properties c-inspect-properties"> | ||||
|     <plan-activity-view v-for="activity in activities" | ||||
|                         :key="activity.id" | ||||
|                         :activity="activity" | ||||
|                         :heading="heading" | ||||
|     <plan-activity-view | ||||
|         v-for="activity in activities" | ||||
|         :key="activity.id" | ||||
|         :activity="activity" | ||||
|         :heading="heading" | ||||
|     /> | ||||
| </div> | ||||
| </template> | ||||
|   | ||||
| @@ -21,18 +21,21 @@ | ||||
| --> | ||||
|  | ||||
| <template> | ||||
| <div v-if="timeProperties.length" | ||||
|      class="u-contents" | ||||
| <div | ||||
|     v-if="timeProperties.length" | ||||
|     class="u-contents" | ||||
| > | ||||
|     <div class="c-inspect-properties__header"> | ||||
|         {{ heading }} | ||||
|     </div> | ||||
|     <ul v-for="timeProperty in timeProperties" | ||||
|     <ul | ||||
|         v-for="timeProperty in timeProperties" | ||||
|         :key="timeProperty.id" | ||||
|         class="c-inspect-properties__section" | ||||
|     > | ||||
|         <activity-property :label="timeProperty.label" | ||||
|                            :value="timeProperty.value" | ||||
|         <activity-property | ||||
|             :label="timeProperty.label" | ||||
|             :value="timeProperty.value" | ||||
|         /> | ||||
|     </ul> | ||||
| </div> | ||||
|   | ||||
| @@ -20,132 +20,155 @@ | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <template> | ||||
| <div v-if="loaded" | ||||
|      class="gl-plot" | ||||
|      :class="[plotLegendExpandedStateClass, plotLegendPositionClass]" | ||||
| <div | ||||
|     v-if="loaded" | ||||
|     class="gl-plot" | ||||
|     :class="[plotLegendExpandedStateClass, plotLegendPositionClass]" | ||||
| > | ||||
|     <plot-legend :cursor-locked="!!lockHighlightPoint" | ||||
|                  :series="seriesModels" | ||||
|                  :highlights="highlights" | ||||
|                  :legend="legend" | ||||
|                  @legendHoverChanged="legendHoverChanged" | ||||
|     <plot-legend | ||||
|         :cursor-locked="!!lockHighlightPoint" | ||||
|         :series="seriesModels" | ||||
|         :highlights="highlights" | ||||
|         :legend="legend" | ||||
|         @legendHoverChanged="legendHoverChanged" | ||||
|     /> | ||||
|     <div class="plot-wrapper-axis-and-display-area flex-elem grows"> | ||||
|         <y-axis v-if="seriesModels.length > 0" | ||||
|                 :tick-width="tickWidth" | ||||
|                 :single-series="seriesModels.length === 1" | ||||
|                 :series-model="seriesModels[0]" | ||||
|                 :style="{ | ||||
|                     left: (plotWidth - tickWidth) + 'px' | ||||
|                 }" | ||||
|                 @yKeyChanged="setYAxisKey" | ||||
|                 @tickWidthChanged="onTickWidthChange" | ||||
|         <y-axis | ||||
|             v-if="seriesModels.length > 0" | ||||
|             :tick-width="tickWidth" | ||||
|             :single-series="seriesModels.length === 1" | ||||
|             :series-model="seriesModels[0]" | ||||
|             :style="{ | ||||
|                 left: (plotWidth - tickWidth) + 'px' | ||||
|             }" | ||||
|             @yKeyChanged="setYAxisKey" | ||||
|             @tickWidthChanged="onTickWidthChange" | ||||
|         /> | ||||
|         <div class="gl-plot-wrapper-display-area-and-x-axis" | ||||
|              :style="{ | ||||
|                  left: (plotWidth + 20) + 'px' | ||||
|              }" | ||||
|         <div | ||||
|             class="gl-plot-wrapper-display-area-and-x-axis" | ||||
|             :style="{ | ||||
|                 left: (plotWidth + 20) + 'px' | ||||
|             }" | ||||
|         > | ||||
|  | ||||
|             <div class="gl-plot-display-area has-local-controls has-cursor-guides"> | ||||
|                 <div class="l-state-indicators"> | ||||
|                     <span class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle" | ||||
|                           title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data." | ||||
|                     <span | ||||
|                         class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle" | ||||
|                         title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data." | ||||
|                     ></span> | ||||
|                 </div> | ||||
|  | ||||
|                 <mct-ticks v-show="gridLines && !options.compact" | ||||
|                            :axis-type="'xAxis'" | ||||
|                            :position="'right'" | ||||
|                            @plotTickWidth="onTickWidthChange" | ||||
|                 <mct-ticks | ||||
|                     v-show="gridLines && !options.compact" | ||||
|                     :axis-type="'xAxis'" | ||||
|                     :position="'right'" | ||||
|                     @plotTickWidth="onTickWidthChange" | ||||
|                 /> | ||||
|  | ||||
|                 <mct-ticks v-show="gridLines" | ||||
|                            :axis-type="'yAxis'" | ||||
|                            :position="'bottom'" | ||||
|                            @plotTickWidth="onTickWidthChange" | ||||
|                 <mct-ticks | ||||
|                     v-show="gridLines" | ||||
|                     :axis-type="'yAxis'" | ||||
|                     :position="'bottom'" | ||||
|                     @plotTickWidth="onTickWidthChange" | ||||
|                 /> | ||||
|  | ||||
|                 <div ref="chartContainer" | ||||
|                      class="gl-plot-chart-wrapper" | ||||
|                 <div | ||||
|                     ref="chartContainer" | ||||
|                     class="gl-plot-chart-wrapper" | ||||
|                 > | ||||
|                     <mct-chart :rectangles="rectangles" | ||||
|                                :highlights="highlights" | ||||
|                                :show-limit-line-labels="showLimitLineLabels" | ||||
|                                @plotReinitializeCanvas="initCanvas" | ||||
|                     <mct-chart | ||||
|                         :rectangles="rectangles" | ||||
|                         :highlights="highlights" | ||||
|                         :show-limit-line-labels="showLimitLineLabels" | ||||
|                         @plotReinitializeCanvas="initCanvas" | ||||
|                     /> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="gl-plot__local-controls h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover"> | ||||
|                     <div v-if="!options.compact" | ||||
|                          class="c-button-set c-button-set--strip-h js-zoom" | ||||
|                     <div | ||||
|                         v-if="!options.compact" | ||||
|                         class="c-button-set c-button-set--strip-h js-zoom" | ||||
|                     > | ||||
|                         <button class="c-button icon-minus" | ||||
|                                 title="Zoom out" | ||||
|                                 @click="zoom('out', 0.2)" | ||||
|                         <button | ||||
|                             class="c-button icon-minus" | ||||
|                             title="Zoom out" | ||||
|                             @click="zoom('out', 0.2)" | ||||
|                         > | ||||
|                         </button> | ||||
|                         <button class="c-button icon-plus" | ||||
|                                 title="Zoom in" | ||||
|                                 @click="zoom('in', 0.2)" | ||||
|                         <button | ||||
|                             class="c-button icon-plus" | ||||
|                             title="Zoom in" | ||||
|                             @click="zoom('in', 0.2)" | ||||
|                         > | ||||
|                         </button> | ||||
|                     </div> | ||||
|                     <div v-if="plotHistory.length && !options.compact" | ||||
|                          class="c-button-set c-button-set--strip-h js-pan" | ||||
|                     <div | ||||
|                         v-if="plotHistory.length && !options.compact" | ||||
|                         class="c-button-set c-button-set--strip-h js-pan" | ||||
|                     > | ||||
|                         <button class="c-button icon-arrow-left" | ||||
|                                 title="Restore previous pan/zoom" | ||||
|                                 @click="back()" | ||||
|                         <button | ||||
|                             class="c-button icon-arrow-left" | ||||
|                             title="Restore previous pan/zoom" | ||||
|                             @click="back()" | ||||
|                         > | ||||
|                         </button> | ||||
|                         <button class="c-button icon-reset" | ||||
|                                 title="Reset pan/zoom" | ||||
|                                 @click="clear()" | ||||
|                         <button | ||||
|                             class="c-button icon-reset" | ||||
|                             title="Reset pan/zoom" | ||||
|                             @click="clear()" | ||||
|                         > | ||||
|                         </button> | ||||
|                     </div> | ||||
|                     <div v-if="isRealTime && !options.compact" | ||||
|                          class="c-button-set c-button-set--strip-h js-pause" | ||||
|                     <div | ||||
|                         v-if="isRealTime && !options.compact" | ||||
|                         class="c-button-set c-button-set--strip-h js-pause" | ||||
|                     > | ||||
|                         <button v-if="!isFrozen" | ||||
|                                 class="c-button icon-pause" | ||||
|                                 title="Pause incoming real-time data" | ||||
|                                 @click="pause()" | ||||
|                         <button | ||||
|                             v-if="!isFrozen" | ||||
|                             class="c-button icon-pause" | ||||
|                             title="Pause incoming real-time data" | ||||
|                             @click="pause()" | ||||
|                         > | ||||
|                         </button> | ||||
|                         <button v-if="isFrozen" | ||||
|                                 class="c-button icon-arrow-right pause-play is-paused" | ||||
|                                 title="Resume displaying real-time data" | ||||
|                                 @click="play()" | ||||
|                         <button | ||||
|                             v-if="isFrozen" | ||||
|                             class="c-button icon-arrow-right pause-play is-paused" | ||||
|                             title="Resume displaying real-time data" | ||||
|                             @click="play()" | ||||
|                         > | ||||
|                         </button> | ||||
|                     </div> | ||||
|                     <div v-if="isTimeOutOfSync || isFrozen" | ||||
|                          class="c-button-set c-button-set--strip-h" | ||||
|                     <div | ||||
|                         v-if="isTimeOutOfSync || isFrozen" | ||||
|                         class="c-button-set c-button-set--strip-h" | ||||
|                     > | ||||
|                         <button class="c-button icon-clock" | ||||
|                                 title="Synchronize Time Conductor" | ||||
|                                 @click="showSynchronizeDialog()" | ||||
|                         <button | ||||
|                             class="c-button icon-clock" | ||||
|                             title="Synchronize Time Conductor" | ||||
|                             @click="showSynchronizeDialog()" | ||||
|                         > | ||||
|                         </button> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 <!--Cursor guides--> | ||||
|                 <div v-show="cursorGuide" | ||||
|                      ref="cursorGuideVertical" | ||||
|                      class="c-cursor-guide--v js-cursor-guide--v" | ||||
|                 <div | ||||
|                     v-show="cursorGuide" | ||||
|                     ref="cursorGuideVertical" | ||||
|                     class="c-cursor-guide--v js-cursor-guide--v" | ||||
|                 > | ||||
|                 </div> | ||||
|                 <div v-show="cursorGuide" | ||||
|                      ref="cursorGuideHorizontal" | ||||
|                      class="c-cursor-guide--h js-cursor-guide--h" | ||||
|                 <div | ||||
|                     v-show="cursorGuide" | ||||
|                     ref="cursorGuideHorizontal" | ||||
|                     class="c-cursor-guide--h js-cursor-guide--h" | ||||
|                 > | ||||
|                 </div> | ||||
|             </div> | ||||
|             <x-axis v-if="seriesModels.length > 0 && !options.compact" | ||||
|                     :series-model="seriesModels[0]" | ||||
|             <x-axis | ||||
|                 v-if="seriesModels.length > 0 && !options.compact" | ||||
|                 :series-model="seriesModels[0]" | ||||
|             /> | ||||
|  | ||||
|         </div> | ||||
|   | ||||
| @@ -21,53 +21,60 @@ | ||||
| --> | ||||
|  | ||||
| <template> | ||||
| <div ref="tickContainer" | ||||
|      class="u-contents js-ticks" | ||||
| <div | ||||
|     ref="tickContainer" | ||||
|     class="u-contents js-ticks" | ||||
| > | ||||
|     <div v-if="position === 'left'" | ||||
|          class="gl-plot-tick-wrapper" | ||||
|     <div | ||||
|         v-if="position === 'left'" | ||||
|         class="gl-plot-tick-wrapper" | ||||
|     > | ||||
|         <div v-for="tick in ticks" | ||||
|              :key="tick.value" | ||||
|              class="gl-plot-tick gl-plot-x-tick-label" | ||||
|              :style="{ | ||||
|                  left: (100 * (tick.value - min) / interval) + '%' | ||||
|              }" | ||||
|              :title="tick.fullText || tick.text" | ||||
|         <div | ||||
|             v-for="tick in ticks" | ||||
|             :key="tick.value" | ||||
|             class="gl-plot-tick gl-plot-x-tick-label" | ||||
|             :style="{ | ||||
|                 left: (100 * (tick.value - min) / interval) + '%' | ||||
|             }" | ||||
|             :title="tick.fullText || tick.text" | ||||
|         > | ||||
|             {{ tick.text }} | ||||
|         </div> | ||||
|     </div> | ||||
|     <div v-if="position === 'top'" | ||||
|          class="gl-plot-tick-wrapper" | ||||
|     <div | ||||
|         v-if="position === 'top'" | ||||
|         class="gl-plot-tick-wrapper" | ||||
|     > | ||||
|         <div v-for="tick in ticks" | ||||
|              :key="tick.value" | ||||
|              class="gl-plot-tick gl-plot-y-tick-label" | ||||
|              :style="{ top: (100 * (max - tick.value) / interval) + '%' }" | ||||
|              :title="tick.fullText || tick.text" | ||||
|              style="margin-top: -0.50em; direction: ltr;" | ||||
|         <div | ||||
|             v-for="tick in ticks" | ||||
|             :key="tick.value" | ||||
|             class="gl-plot-tick gl-plot-y-tick-label" | ||||
|             :style="{ top: (100 * (max - tick.value) / interval) + '%' }" | ||||
|             :title="tick.fullText || tick.text" | ||||
|             style="margin-top: -0.50em; direction: ltr;" | ||||
|         > | ||||
|             <span>{{ tick.text }}</span> | ||||
|         </div> | ||||
|     </div> | ||||
|     <!-- grid lines follow --> | ||||
|     <template v-if="position === 'right'"> | ||||
|         <div v-for="tick in ticks" | ||||
|              :key="tick.value" | ||||
|              class="gl-plot-hash hash-v" | ||||
|              :style="{ | ||||
|                  right: (100 * (max - tick.value) / interval) + '%', | ||||
|                  height: '100%' | ||||
|              }" | ||||
|         <div | ||||
|             v-for="tick in ticks" | ||||
|             :key="tick.value" | ||||
|             class="gl-plot-hash hash-v" | ||||
|             :style="{ | ||||
|                 right: (100 * (max - tick.value) / interval) + '%', | ||||
|                 height: '100%' | ||||
|             }" | ||||
|         > | ||||
|         </div> | ||||
|     </template> | ||||
|     <template v-if="position === 'bottom'"> | ||||
|         <div v-for="tick in ticks" | ||||
|              :key="tick.value" | ||||
|              class="gl-plot-hash hash-h" | ||||
|              :style="{ bottom: (100 * (tick.value - min) / interval) + '%', width: '100%' }" | ||||
|         <div | ||||
|             v-for="tick in ticks" | ||||
|             :key="tick.value" | ||||
|             class="gl-plot-hash hash-h" | ||||
|             :style="{ bottom: (100 * (tick.value - min) / interval) + '%', width: '100%' }" | ||||
|         > | ||||
|         </div> | ||||
|     </template> | ||||
|   | ||||
| @@ -20,52 +20,61 @@ | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <template> | ||||
| <div ref="plotWrapper" | ||||
|      class="c-plot holder holder-plot has-control-bar" | ||||
| <div | ||||
|     ref="plotWrapper" | ||||
|     class="c-plot holder holder-plot has-control-bar" | ||||
| > | ||||
|     <div v-if="!options.compact" | ||||
|          class="c-control-bar" | ||||
|     <div | ||||
|         v-if="!options.compact" | ||||
|         class="c-control-bar" | ||||
|     > | ||||
|         <span class="c-button-set c-button-set--strip-h"> | ||||
|             <button class="c-button icon-download" | ||||
|                     title="Export This View's Data as PNG" | ||||
|                     @click="exportPNG()" | ||||
|             <button | ||||
|                 class="c-button icon-download" | ||||
|                 title="Export This View's Data as PNG" | ||||
|                 @click="exportPNG()" | ||||
|             > | ||||
|                 <span class="c-button__label">PNG</span> | ||||
|             </button> | ||||
|             <button class="c-button" | ||||
|                     title="Export This View's Data as JPG" | ||||
|                     @click="exportJPG()" | ||||
|             <button | ||||
|                 class="c-button" | ||||
|                 title="Export This View's Data as JPG" | ||||
|                 @click="exportJPG()" | ||||
|             > | ||||
|                 <span class="c-button__label">JPG</span> | ||||
|             </button> | ||||
|         </span> | ||||
|         <button class="c-button icon-crosshair" | ||||
|                 :class="{ 'is-active': cursorGuide }" | ||||
|                 title="Toggle cursor guides" | ||||
|                 @click="toggleCursorGuide" | ||||
|         <button | ||||
|             class="c-button icon-crosshair" | ||||
|             :class="{ 'is-active': cursorGuide }" | ||||
|             title="Toggle cursor guides" | ||||
|             @click="toggleCursorGuide" | ||||
|         > | ||||
|         </button> | ||||
|         <button class="c-button" | ||||
|                 :class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }" | ||||
|                 title="Toggle grid lines" | ||||
|                 @click="toggleGridLines" | ||||
|         <button | ||||
|             class="c-button" | ||||
|             :class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }" | ||||
|             title="Toggle grid lines" | ||||
|             @click="toggleGridLines" | ||||
|         > | ||||
|         </button> | ||||
|     </div> | ||||
|  | ||||
|     <div ref="plotContainer" | ||||
|          class="l-view-section u-style-receiver js-style-receiver" | ||||
|          :class="{'s-status-timeconductor-unsynced': status && status === 'timeconductor-unsynced'}" | ||||
|     <div | ||||
|         ref="plotContainer" | ||||
|         class="l-view-section u-style-receiver js-style-receiver" | ||||
|         :class="{'s-status-timeconductor-unsynced': status && status === 'timeconductor-unsynced'}" | ||||
|     > | ||||
|         <div v-show="!!loading" | ||||
|              class="c-loading--overlay loading" | ||||
|         <div | ||||
|             v-show="!!loading" | ||||
|             class="c-loading--overlay loading" | ||||
|         ></div> | ||||
|         <mct-plot :grid-lines="gridLines" | ||||
|                   :cursor-guide="cursorGuide" | ||||
|                   :options="options" | ||||
|                   @loadingUpdated="loadingUpdated" | ||||
|                   @statusUpdated="setStatus" | ||||
|         <mct-plot | ||||
|             :grid-lines="gridLines" | ||||
|             :cursor-guide="cursorGuide" | ||||
|             :options="options" | ||||
|             @loadingUpdated="loadingUpdated" | ||||
|             @statusUpdated="setStatus" | ||||
|         /> | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -21,12 +21,14 @@ | ||||
| --> | ||||
|  | ||||
| <template> | ||||
| <div v-if="loaded" | ||||
|      class="gl-plot-axis-area gl-plot-x has-local-controls" | ||||
| <div | ||||
|     v-if="loaded" | ||||
|     class="gl-plot-axis-area gl-plot-x has-local-controls" | ||||
| > | ||||
|     <mct-ticks :axis-type="'xAxis'" | ||||
|                :position="'left'" | ||||
|                @plotTickWidth="onTickWidthChange" | ||||
|     <mct-ticks | ||||
|         :axis-type="'xAxis'" | ||||
|         :position="'left'" | ||||
|         @plotTickWidth="onTickWidthChange" | ||||
|     /> | ||||
|  | ||||
|     <div | ||||
| @@ -42,9 +44,10 @@ | ||||
|         class="gl-plot-x-label__select local-controls--hidden" | ||||
|         @change="toggleXKeyOption()" | ||||
|     > | ||||
|         <option v-for="option in xKeyOptions" | ||||
|                 :key="option.key" | ||||
|                 :value="option.key" | ||||
|         <option | ||||
|             v-for="option in xKeyOptions" | ||||
|             :key="option.key" | ||||
|             :value="option.key" | ||||
|         >{{ option.name }} | ||||
|         </option> | ||||
|     </select> | ||||
|   | ||||
| @@ -20,37 +20,42 @@ | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <template> | ||||
| <div v-if="loaded" | ||||
|      class="gl-plot-axis-area gl-plot-y has-local-controls" | ||||
|      :style="{ | ||||
|          width: (tickWidth + 20) + 'px' | ||||
|      }" | ||||
| <div | ||||
|     v-if="loaded" | ||||
|     class="gl-plot-axis-area gl-plot-y has-local-controls" | ||||
|     :style="{ | ||||
|         width: (tickWidth + 20) + 'px' | ||||
|     }" | ||||
| > | ||||
|  | ||||
|     <div v-if="singleSeries" | ||||
|          class="gl-plot-label gl-plot-y-label" | ||||
|          :class="{'icon-gear': (yKeyOptions.length > 1)}" | ||||
|     <div | ||||
|         v-if="singleSeries" | ||||
|         class="gl-plot-label gl-plot-y-label" | ||||
|         :class="{'icon-gear': (yKeyOptions.length > 1)}" | ||||
|     >{{ yAxisLabel }} | ||||
|     </div> | ||||
|  | ||||
|     <select v-if="yKeyOptions.length > 1 && singleSeries" | ||||
|             v-model="yAxisLabel" | ||||
|             class="gl-plot-y-label__select local-controls--hidden" | ||||
|             @change="toggleYAxisLabel" | ||||
|     <select | ||||
|         v-if="yKeyOptions.length > 1 && singleSeries" | ||||
|         v-model="yAxisLabel" | ||||
|         class="gl-plot-y-label__select local-controls--hidden" | ||||
|         @change="toggleYAxisLabel" | ||||
|     > | ||||
|         <option v-for="(option, index) in yKeyOptions" | ||||
|                 :key="index" | ||||
|                 :value="option.name" | ||||
|                 :selected="option.name === yAxisLabel" | ||||
|         <option | ||||
|             v-for="(option, index) in yKeyOptions" | ||||
|             :key="index" | ||||
|             :value="option.name" | ||||
|             :selected="option.name === yAxisLabel" | ||||
|         > | ||||
|             {{ option.name }} | ||||
|         </option> | ||||
|     </select> | ||||
|  | ||||
|     <mct-ticks :axis-type="'yAxis'" | ||||
|                class="gl-plot-ticks" | ||||
|                :position="'top'" | ||||
|                @plotTickWidth="onTickWidthChange" | ||||
|     <mct-ticks | ||||
|         :axis-type="'yAxis'" | ||||
|         class="gl-plot-ticks" | ||||
|         :position="'top'" | ||||
|         @plotTickWidth="onTickWidthChange" | ||||
|     /> | ||||
| </div> | ||||
| </template> | ||||
|   | ||||
| @@ -1,14 +1,16 @@ | ||||
| <template> | ||||
| <div class="c-plot-limit" | ||||
|      :style="styleObj" | ||||
|      :class="limitClass" | ||||
| <div | ||||
|     class="c-plot-limit" | ||||
|     :style="styleObj" | ||||
|     :class="limitClass" | ||||
| > | ||||
|     <div class="c-plot-limit__label"> | ||||
|         <span class="c-plot-limit__direction-icon"></span> | ||||
|         <span class="c-plot-limit__severity-icon"></span> | ||||
|         <span class="c-plot-limit__limit-value">{{ limit.value }}</span> | ||||
|         <span class="c-plot-limit__series-color-swatch" | ||||
|               :style="{ 'background-color': limit.seriesColor }" | ||||
|         <span | ||||
|             class="c-plot-limit__series-color-swatch" | ||||
|             :style="{ 'background-color': limit.seriesColor }" | ||||
|         ></span> | ||||
|         <span class="c-plot-limit__series-name">{{ limit.name }}</span> | ||||
|     </div> | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| <template> | ||||
| <div :style="styleObj" | ||||
|      class="c-plot-limit-line js-limit-line" | ||||
|      :class="limitClass" | ||||
| <div | ||||
|     :style="styleObj" | ||||
|     class="c-plot-limit-line js-limit-line" | ||||
|     :class="limitClass" | ||||
| ></div> | ||||
| </template> | ||||
|  | ||||
|   | ||||
| @@ -26,8 +26,9 @@ | ||||
| <div class="gl-plot-chart-area"> | ||||
|     <span v-html="canvasTemplate"></span> | ||||
|     <span v-html="canvasTemplate"></span> | ||||
|     <div ref="limitArea" | ||||
|          class="js-limit-area" | ||||
|     <div | ||||
|         ref="limitArea" | ||||
|         class="js-limit-area" | ||||
|     ></div> | ||||
| </div> | ||||
| </template> | ||||
|   | ||||
| @@ -20,49 +20,58 @@ | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <template> | ||||
| <div v-if="loaded" | ||||
|      class="js-plot-options-browse" | ||||
| <div | ||||
|     v-if="loaded" | ||||
|     class="js-plot-options-browse" | ||||
| > | ||||
|     <ul class="c-tree"> | ||||
|         <h2 title="Plot series display properties in this object">Plot Series</h2> | ||||
|         <plot-options-item v-for="series in plotSeries" | ||||
|                            :key="series.key" | ||||
|                            :series="series" | ||||
|         <plot-options-item | ||||
|             v-for="series in plotSeries" | ||||
|             :key="series.key" | ||||
|             :series="series" | ||||
|         /> | ||||
|     </ul> | ||||
|     <div v-if="plotSeries.length" | ||||
|          class="grid-properties" | ||||
|     <div | ||||
|         v-if="plotSeries.length" | ||||
|         class="grid-properties" | ||||
|     > | ||||
|         <ul class="l-inspector-part"> | ||||
|             <h2 title="Y axis settings for this object">Y Axis</h2> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Manually override how the Y axis is labeled." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="Manually override how the Y axis is labeled." | ||||
|                 >Label</div> | ||||
|                 <div class="grid-cell value">{{ label ? label : "Not defined" }}</div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Automatically scale the Y axis to keep all values in view." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="Automatically scale the Y axis to keep all values in view." | ||||
|                 >Autoscale</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     {{ autoscale ? "Enabled: " : "Disabled" }} | ||||
|                     {{ autoscale ? autoscalePadding : "" }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li v-if="!autoscale && rangeMin" | ||||
|             <li | ||||
|                 v-if="!autoscale && rangeMin" | ||||
|                 class="grid-row" | ||||
|             > | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Minimum Y axis value." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="Minimum Y axis value." | ||||
|                 >Minimum value</div> | ||||
|                 <div class="grid-cell value">{{ rangeMin }}</div> | ||||
|             </li> | ||||
|             <li v-if="!autoscale && rangeMax" | ||||
|             <li | ||||
|                 v-if="!autoscale && rangeMax" | ||||
|                 class="grid-row" | ||||
|             > | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Maximum Y axis value." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="Maximum Y axis value." | ||||
|                 >Maximum value</div> | ||||
|                 <div class="grid-cell value">{{ rangeMax }}</div> | ||||
|             </li> | ||||
| @@ -70,26 +79,30 @@ | ||||
|         <ul class="l-inspector-part"> | ||||
|             <h2 title="Legend settings for this object">Legend</h2> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="The position of the legend relative to the plot display area." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="The position of the legend relative to the plot display area." | ||||
|                 >Position</div> | ||||
|                 <div class="grid-cell value capitalize">{{ position }}</div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Hide the legend when the plot is small" | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="Hide the legend when the plot is small" | ||||
|                 >Hide when plot small</div> | ||||
|                 <div class="grid-cell value">{{ hideLegendWhenSmall ? "Yes" : "No" }}</div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Show the legend expanded by default" | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="Show the legend expanded by default" | ||||
|                 >Expand by Default</div> | ||||
|                 <div class="grid-cell value">{{ expandByDefault ? "Yes" : "No" }}</div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="What to display in the legend when it's collapsed." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="What to display in the legend when it's collapsed." | ||||
|                 >Show when collapsed:</div> | ||||
|                 <div class="grid-cell value">{{ | ||||
|                     valueToShowWhenCollapsed.replace('nearest', '') | ||||
| @@ -97,8 +110,9 @@ | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="What to display in the legend when it's expanded." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="What to display in the legend when it's expanded." | ||||
|                 >Show when expanded:</div> | ||||
|                 <div class="grid-cell value comma-list"> | ||||
|                     <span v-if="showTimestampWhenExpanded">Timestamp</span> | ||||
|   | ||||
| @@ -20,26 +20,30 @@ | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <template> | ||||
| <div v-if="loaded" | ||||
|      class="js-plot-options-edit" | ||||
| <div | ||||
|     v-if="loaded" | ||||
|     class="js-plot-options-edit" | ||||
| > | ||||
|     <ul class="c-tree"> | ||||
|         <h2 title="Display properties for this object">Plot Series</h2> | ||||
|         <li v-for="series in plotSeries" | ||||
|         <li | ||||
|             v-for="series in plotSeries" | ||||
|             :key="series.key" | ||||
|         > | ||||
|             <series-form :series="series" /> | ||||
|         </li> | ||||
|     </ul> | ||||
|     <y-axis-form v-if="plotSeries.length" | ||||
|                  class="grid-properties" | ||||
|                  :y-axis="config.yAxis" | ||||
|     <y-axis-form | ||||
|         v-if="plotSeries.length" | ||||
|         class="grid-properties" | ||||
|         :y-axis="config.yAxis" | ||||
|     /> | ||||
|     <ul class="l-inspector-part"> | ||||
|         <h2 title="Legend options">Legend</h2> | ||||
|         <legend-form v-if="plotSeries.length" | ||||
|                      class="grid-properties" | ||||
|                      :legend="config.legend" | ||||
|         <legend-form | ||||
|             v-if="plotSeries.length" | ||||
|             class="grid-properties" | ||||
|             :legend="config.legend" | ||||
|         /> | ||||
|     </ul> | ||||
| </div> | ||||
|   | ||||
| @@ -1,41 +1,49 @@ | ||||
| <template> | ||||
| <ul> | ||||
|     <li class="c-tree__item menus-to-left" | ||||
|     <li | ||||
|         class="c-tree__item menus-to-left" | ||||
|         :class="isAliasClass" | ||||
|     > | ||||
|         <span class="c-disclosure-triangle is-enabled flex-elem" | ||||
|               :class="expandedCssClass" | ||||
|               @click="toggleExpanded" | ||||
|         <span | ||||
|             class="c-disclosure-triangle is-enabled flex-elem" | ||||
|             :class="expandedCssClass" | ||||
|             @click="toggleExpanded" | ||||
|         > | ||||
|         </span> | ||||
|         <div class="c-object-label" | ||||
|              :class="statusClass" | ||||
|         <div | ||||
|             class="c-object-label" | ||||
|             :class="statusClass" | ||||
|         > | ||||
|             <div class="c-object-label__type-icon" | ||||
|                  :class="getSeriesClass" | ||||
|             <div | ||||
|                 class="c-object-label__type-icon" | ||||
|                 :class="getSeriesClass" | ||||
|             > | ||||
|                 <span class="is-status__indicator" | ||||
|                       title="This item is missing or suspect" | ||||
|                 <span | ||||
|                     class="is-status__indicator" | ||||
|                     title="This item is missing or suspect" | ||||
|                 ></span> | ||||
|             </div> | ||||
|             <div class="c-object-label__name">{{ series.domainObject.name }}</div> | ||||
|         </div> | ||||
|     </li> | ||||
|     <li v-show="expanded" | ||||
|     <li | ||||
|         v-show="expanded" | ||||
|         class="c-tree__item menus-to-left" | ||||
|     > | ||||
|         <ul class="grid-properties js-plot-options-browse-properties"> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="The field to be plotted as a value for this series." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="The field to be plotted as a value for this series." | ||||
|                 >Value</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     {{ yKey }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="The rendering method to join lines for this series." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="The rendering method to join lines for this series." | ||||
|                 >Line Method</div> | ||||
|                 <div class="grid-cell value">{{ { | ||||
|                     'none': 'None', | ||||
| @@ -45,33 +53,37 @@ | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Whether markers are displayed, and their size." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="Whether markers are displayed, and their size." | ||||
|                 >Markers</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     {{ markerOptionsDisplayText }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Display markers visually denoting points in alarm." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="Display markers visually denoting points in alarm." | ||||
|                 >Alarm Markers</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     {{ alarmMarkers ? "Enabled" : "Disabled" }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Display lines visually denoting alarm limits." | ||||
|                 <div | ||||
|                     class="grid-cell label" | ||||
|                     title="Display lines visually denoting alarm limits." | ||||
|                 >Limit lines</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     {{ limitLines ? "Enabled" : "Disabled" }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <ColorSwatch :current-color="seriesHexColor" | ||||
|                          edit-title="Manually set the plot line and marker color for this series." | ||||
|                          view-title="The plot line and marker color for this series." | ||||
|                          short-label="Color" | ||||
|             <ColorSwatch | ||||
|                 :current-color="seriesHexColor" | ||||
|                 edit-title="Manually set the plot line and marker color for this series." | ||||
|                 view-title="The plot line and marker color for this series." | ||||
|                 short-label="Color" | ||||
|             /> | ||||
|         </ul> | ||||
|     </li> | ||||
|   | ||||
| @@ -1,12 +1,14 @@ | ||||
| <template> | ||||
| <div> | ||||
|     <li class="grid-row"> | ||||
|         <div class="grid-cell label" | ||||
|              title="The position of the legend relative to the plot display area." | ||||
|         <div | ||||
|             class="grid-cell label" | ||||
|             title="The position of the legend relative to the plot display area." | ||||
|         >Position</div> | ||||
|         <div class="grid-cell value"> | ||||
|             <select v-model="position" | ||||
|                     @change="updateForm('position')" | ||||
|             <select | ||||
|                 v-model="position" | ||||
|                 @change="updateForm('position')" | ||||
|             > | ||||
|                 <option value="top">Top</option> | ||||
|                 <option value="right">Right</option> | ||||
| @@ -16,30 +18,36 @@ | ||||
|         </div> | ||||
|     </li> | ||||
|     <li class="grid-row"> | ||||
|         <div class="grid-cell label" | ||||
|              title="Hide the legend when the plot is small" | ||||
|         <div | ||||
|             class="grid-cell label" | ||||
|             title="Hide the legend when the plot is small" | ||||
|         >Hide when plot small</div> | ||||
|         <div class="grid-cell value"><input v-model="hideLegendWhenSmall" | ||||
|                                             type="checkbox" | ||||
|                                             @change="updateForm('hideLegendWhenSmall')" | ||||
|         <div class="grid-cell value"><input | ||||
|             v-model="hideLegendWhenSmall" | ||||
|             type="checkbox" | ||||
|             @change="updateForm('hideLegendWhenSmall')" | ||||
|         ></div> | ||||
|     </li> | ||||
|     <li class="grid-row"> | ||||
|         <div class="grid-cell label" | ||||
|              title="Show the legend expanded by default" | ||||
|         <div | ||||
|             class="grid-cell label" | ||||
|             title="Show the legend expanded by default" | ||||
|         >Expand by default</div> | ||||
|         <div class="grid-cell value"><input v-model="expandByDefault" | ||||
|                                             type="checkbox" | ||||
|                                             @change="updateForm('expandByDefault')" | ||||
|         <div class="grid-cell value"><input | ||||
|             v-model="expandByDefault" | ||||
|             type="checkbox" | ||||
|             @change="updateForm('expandByDefault')" | ||||
|         ></div> | ||||
|     </li> | ||||
|     <li class="grid-row"> | ||||
|         <div class="grid-cell label" | ||||
|              title="What to display in the legend when it's collapsed." | ||||
|         <div | ||||
|             class="grid-cell label" | ||||
|             title="What to display in the legend when it's collapsed." | ||||
|         >When collapsed show</div> | ||||
|         <div class="grid-cell value"> | ||||
|             <select v-model="valueToShowWhenCollapsed" | ||||
|                     @change="updateForm('valueToShowWhenCollapsed')" | ||||
|             <select | ||||
|                 v-model="valueToShowWhenCollapsed" | ||||
|                 @change="updateForm('valueToShowWhenCollapsed')" | ||||
|             > | ||||
|                 <option value="none">Nothing</option> | ||||
|                 <option value="nearestTimestamp">Nearest timestamp</option> | ||||
| @@ -51,30 +59,36 @@ | ||||
|         </div> | ||||
|     </li> | ||||
|     <li class="grid-row"> | ||||
|         <div class="grid-cell label" | ||||
|              title="What to display in the legend when it's expanded." | ||||
|         <div | ||||
|             class="grid-cell label" | ||||
|             title="What to display in the legend when it's expanded." | ||||
|         >When expanded show</div> | ||||
|         <div class="grid-cell value"> | ||||
|             <ul> | ||||
|                 <li><input v-model="showTimestampWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showTimestampWhenExpanded')" | ||||
|                 <li><input | ||||
|                     v-model="showTimestampWhenExpanded" | ||||
|                     type="checkbox" | ||||
|                     @change="updateForm('showTimestampWhenExpanded')" | ||||
|                 > Nearest timestamp</li> | ||||
|                 <li><input v-model="showValueWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showValueWhenExpanded')" | ||||
|                 <li><input | ||||
|                     v-model="showValueWhenExpanded" | ||||
|                     type="checkbox" | ||||
|                     @change="updateForm('showValueWhenExpanded')" | ||||
|                 > Nearest value</li> | ||||
|                 <li><input v-model="showMinimumWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showMinimumWhenExpanded')" | ||||
|                 <li><input | ||||
|                     v-model="showMinimumWhenExpanded" | ||||
|                     type="checkbox" | ||||
|                     @change="updateForm('showMinimumWhenExpanded')" | ||||
|                 > Minimum value</li> | ||||
|                 <li><input v-model="showMaximumWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showMaximumWhenExpanded')" | ||||
|                 <li><input | ||||
|                     v-model="showMaximumWhenExpanded" | ||||
|                     type="checkbox" | ||||
|                     @change="updateForm('showMaximumWhenExpanded')" | ||||
|                 > Maximum value</li> | ||||
|                 <li><input v-model="showUnitsWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showUnitsWhenExpanded')" | ||||
|                 <li><input | ||||
|                     v-model="showUnitsWhenExpanded" | ||||
|                     type="checkbox" | ||||
|                     @change="updateForm('showUnitsWhenExpanded')" | ||||
|                 > Units</li> | ||||
|             </ul> | ||||
|  | ||||
|   | ||||
| @@ -1,40 +1,48 @@ | ||||
| <template> | ||||
| <ul> | ||||
|     <li class="c-tree__item menus-to-left" | ||||
|     <li | ||||
|         class="c-tree__item menus-to-left" | ||||
|         :class="isAliasCss" | ||||
|     > | ||||
|         <span class="c-disclosure-triangle is-enabled flex-elem" | ||||
|               :class="expandedCssClass" | ||||
|               @click="toggleExpanded" | ||||
|         <span | ||||
|             class="c-disclosure-triangle is-enabled flex-elem" | ||||
|             :class="expandedCssClass" | ||||
|             @click="toggleExpanded" | ||||
|         > | ||||
|         </span> | ||||
|         <div :class="objectLabelCss"> | ||||
|             <div class="c-object-label__type-icon" | ||||
|                  :class="[seriesCss]" | ||||
|             <div | ||||
|                 class="c-object-label__type-icon" | ||||
|                 :class="[seriesCss]" | ||||
|             > | ||||
|                 <span class="is-status__indicator" | ||||
|                       title="This item is missing or suspect" | ||||
|                 <span | ||||
|                     class="is-status__indicator" | ||||
|                     title="This item is missing or suspect" | ||||
|                 ></span> | ||||
|             </div> | ||||
|             <div class="c-object-label__name">{{ series.domainObject.name }}</div> | ||||
|         </div> | ||||
|     </li> | ||||
|     <ul v-show="expanded" | ||||
|     <ul | ||||
|         v-show="expanded" | ||||
|         class="grid-properties js-plot-options-edit-properties" | ||||
|     > | ||||
|         <li class="grid-row"> | ||||
|             <!-- Value to be displayed --> | ||||
|             <div class="grid-cell label" | ||||
|                  title="The field to be plotted as a value for this series." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="The field to be plotted as a value for this series." | ||||
|             >Value</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <select v-model="yKey" | ||||
|                         @change="updateForm('yKey')" | ||||
|                 <select | ||||
|                     v-model="yKey" | ||||
|                     @change="updateForm('yKey')" | ||||
|                 > | ||||
|                     <option v-for="option in yKeyOptions" | ||||
|                             :key="option.value" | ||||
|                             :value="option.value" | ||||
|                             :selected="option.value == yKey" | ||||
|                     <option | ||||
|                         v-for="option in yKeyOptions" | ||||
|                         :key="option.value" | ||||
|                         :value="option.value" | ||||
|                         :selected="option.value == yKey" | ||||
|                     > | ||||
|                         {{ option.name }} | ||||
|                     </option> | ||||
| @@ -42,12 +50,14 @@ | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="The rendering method to join lines for this series." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="The rendering method to join lines for this series." | ||||
|             >Line Method</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <select v-model="interpolate" | ||||
|                         @change="updateForm('interpolate')" | ||||
|                 <select | ||||
|                     v-model="interpolate" | ||||
|                     @change="updateForm('interpolate')" | ||||
|                 > | ||||
|                     <option value="none">None</option> | ||||
|                     <option value="linear">Linear interpolate</option> | ||||
| @@ -56,13 +66,15 @@ | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Whether markers are displayed." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="Whether markers are displayed." | ||||
|             >Markers</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <input v-model="markers" | ||||
|                        type="checkbox" | ||||
|                        @change="updateForm('markers')" | ||||
|                 <input | ||||
|                     v-model="markers" | ||||
|                     type="checkbox" | ||||
|                     @change="updateForm('markers')" | ||||
|                 > | ||||
|                 <select | ||||
|                     v-show="markers" | ||||
| @@ -81,47 +93,56 @@ | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Display markers visually denoting points in alarm." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="Display markers visually denoting points in alarm." | ||||
|             >Alarm Markers</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <input v-model="alarmMarkers" | ||||
|                        type="checkbox" | ||||
|                        @change="updateForm('alarmMarkers')" | ||||
|                 <input | ||||
|                     v-model="alarmMarkers" | ||||
|                     type="checkbox" | ||||
|                     @change="updateForm('alarmMarkers')" | ||||
|                 > | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Display limit lines" | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="Display limit lines" | ||||
|             >Limit lines</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <input v-model="limitLines" | ||||
|                        type="checkbox" | ||||
|                        @change="updateForm('limitLines')" | ||||
|                 <input | ||||
|                     v-model="limitLines" | ||||
|                     type="checkbox" | ||||
|                     @change="updateForm('limitLines')" | ||||
|                 > | ||||
|             </div> | ||||
|         </li> | ||||
|         <li v-show="markers || alarmMarkers" | ||||
|         <li | ||||
|             v-show="markers || alarmMarkers" | ||||
|             class="grid-row" | ||||
|         > | ||||
|             <div class="grid-cell label" | ||||
|                  title="The size of regular and alarm markers for this series." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="The size of regular and alarm markers for this series." | ||||
|             >Marker Size:</div> | ||||
|             <div class="grid-cell value"><input v-model="markerSize" | ||||
|                                                 class="c-input--flex" | ||||
|                                                 type="text" | ||||
|                                                 @change="updateForm('markerSize')" | ||||
|             <div class="grid-cell value"><input | ||||
|                 v-model="markerSize" | ||||
|                 class="c-input--flex" | ||||
|                 type="text" | ||||
|                 @change="updateForm('markerSize')" | ||||
|             ></div> | ||||
|         </li> | ||||
|         <li v-show="interpolate !== 'none' || markers" | ||||
|         <li | ||||
|             v-show="interpolate !== 'none' || markers" | ||||
|             class="grid-row" | ||||
|         > | ||||
|             <ColorSwatch :current-color="currentColor" | ||||
|                          edit-title="Manually set the plot line and marker color for this series." | ||||
|                          view-title="The plot line and marker color for this series." | ||||
|                          short-label="Color" | ||||
|                          @colorSet="setColor" | ||||
|             <ColorSwatch | ||||
|                 :current-color="currentColor" | ||||
|                 edit-title="Manually set the plot line and marker color for this series." | ||||
|                 view-title="The plot line and marker color for this series." | ||||
|                 short-label="Color" | ||||
|                 @colorSet="setColor" | ||||
|             /> | ||||
|         </li> | ||||
|     </ul> | ||||
|   | ||||
| @@ -3,71 +3,84 @@ | ||||
|     <ul class="l-inspector-part"> | ||||
|         <h2>Y Axis</h2> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Manually override how the Y axis is labeled." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="Manually override how the Y axis is labeled." | ||||
|             >Label</div> | ||||
|             <div class="grid-cell value"><input v-model="label" | ||||
|                                                 class="c-input--flex" | ||||
|                                                 type="text" | ||||
|                                                 @change="updateForm('label')" | ||||
|             <div class="grid-cell value"><input | ||||
|                 v-model="label" | ||||
|                 class="c-input--flex" | ||||
|                 type="text" | ||||
|                 @change="updateForm('label')" | ||||
|             ></div> | ||||
|         </li> | ||||
|     </ul> | ||||
|     <ul class="l-inspector-part"> | ||||
|         <h2>Y Axis Scaling</h2> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Automatically scale the Y axis to keep all values in view." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="Automatically scale the Y axis to keep all values in view." | ||||
|             >Auto scale</div> | ||||
|             <div class="grid-cell value"><input v-model="autoscale" | ||||
|                                                 type="checkbox" | ||||
|                                                 @change="updateForm('autoscale')" | ||||
|             <div class="grid-cell value"><input | ||||
|                 v-model="autoscale" | ||||
|                 type="checkbox" | ||||
|                 @change="updateForm('autoscale')" | ||||
|             ></div> | ||||
|         </li> | ||||
|         <li v-show="autoscale" | ||||
|         <li | ||||
|             v-show="autoscale" | ||||
|             class="grid-row" | ||||
|         > | ||||
|             <div class="grid-cell label" | ||||
|                  title="Percentage of padding above and below plotted min and max values. 0.1, 1.0, etc." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="Percentage of padding above and below plotted min and max values. 0.1, 1.0, etc." | ||||
|             > | ||||
|                 Padding</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <input v-model="autoscalePadding" | ||||
|                        class="c-input--flex" | ||||
|                        type="text" | ||||
|                        @change="updateForm('autoscalePadding')" | ||||
|                 <input | ||||
|                     v-model="autoscalePadding" | ||||
|                     class="c-input--flex" | ||||
|                     type="text" | ||||
|                     @change="updateForm('autoscalePadding')" | ||||
|                 > | ||||
|             </div> | ||||
|         </li> | ||||
|     </ul> | ||||
|     <ul v-show="!autoscale" | ||||
|     <ul | ||||
|         v-show="!autoscale" | ||||
|         class="l-inspector-part" | ||||
|     > | ||||
|         <div v-show="!autoscale && validation.range" | ||||
|              class="grid-span-all form-error" | ||||
|         <div | ||||
|             v-show="!autoscale && validation.range" | ||||
|             class="grid-span-all form-error" | ||||
|         > | ||||
|             {{ validation.range }} | ||||
|         </div> | ||||
|         <li class="grid-row force-border"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Minimum Y axis value." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="Minimum Y axis value." | ||||
|             >Minimum Value</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <input v-model="rangeMin" | ||||
|                        class="c-input--flex" | ||||
|                        type="number" | ||||
|                        @change="updateForm('range')" | ||||
|                 <input | ||||
|                     v-model="rangeMin" | ||||
|                     class="c-input--flex" | ||||
|                     type="number" | ||||
|                     @change="updateForm('range')" | ||||
|                 > | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Maximum Y axis value." | ||||
|             <div | ||||
|                 class="grid-cell label" | ||||
|                 title="Maximum Y axis value." | ||||
|             >Maximum Value</div> | ||||
|             <div class="grid-cell value"><input v-model="rangeMax" | ||||
|                                                 class="c-input--flex" | ||||
|                                                 type="number" | ||||
|                                                 @change="updateForm('range')" | ||||
|             <div class="grid-cell value"><input | ||||
|                 v-model="rangeMax" | ||||
|                 class="c-input--flex" | ||||
|                 type="number" | ||||
|                 @change="updateForm('range')" | ||||
|             ></div> | ||||
|         </li> | ||||
|     </ul> | ||||
|   | ||||
| @@ -20,43 +20,51 @@ | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <template> | ||||
| <div class="c-plot-legend gl-plot-legend" | ||||
|      :class="{ | ||||
|          'hover-on-plot': !!highlights.length, | ||||
|          'is-legend-hidden': isLegendHidden | ||||
|      }" | ||||
| <div | ||||
|     class="c-plot-legend gl-plot-legend" | ||||
|     :class="{ | ||||
|         'hover-on-plot': !!highlights.length, | ||||
|         'is-legend-hidden': isLegendHidden | ||||
|     }" | ||||
| > | ||||
|     <div class="c-plot-legend__view-control gl-plot-legend__view-control c-disclosure-triangle is-enabled" | ||||
|          :class="{ 'c-disclosure-triangle--expanded': isLegendExpanded }" | ||||
|          @click="expandLegend" | ||||
|     <div | ||||
|         class="c-plot-legend__view-control gl-plot-legend__view-control c-disclosure-triangle is-enabled" | ||||
|         :class="{ 'c-disclosure-triangle--expanded': isLegendExpanded }" | ||||
|         @click="expandLegend" | ||||
|     > | ||||
|     </div> | ||||
|  | ||||
|     <div class="c-plot-legend__wrapper" | ||||
|          :class="{ 'is-cursor-locked': cursorLocked }" | ||||
|     <div | ||||
|         class="c-plot-legend__wrapper" | ||||
|         :class="{ 'is-cursor-locked': cursorLocked }" | ||||
|     > | ||||
|  | ||||
|         <!-- COLLAPSED PLOT LEGEND --> | ||||
|         <div class="plot-wrapper-collapsed-legend" | ||||
|              :class="{'is-cursor-locked': cursorLocked }" | ||||
|         <div | ||||
|             class="plot-wrapper-collapsed-legend" | ||||
|             :class="{'is-cursor-locked': cursorLocked }" | ||||
|         > | ||||
|             <div class="c-state-indicator__alert-cursor-lock icon-cursor-lock" | ||||
|                  title="Cursor is point locked. Click anywhere in the plot to unlock." | ||||
|             <div | ||||
|                 class="c-state-indicator__alert-cursor-lock icon-cursor-lock" | ||||
|                 title="Cursor is point locked. Click anywhere in the plot to unlock." | ||||
|             ></div> | ||||
|             <plot-legend-item-collapsed v-for="seriesObject in series" | ||||
|                                         :key="seriesObject.keyString" | ||||
|                                         :highlights="highlights" | ||||
|                                         :value-to-show-when-collapsed="legend.get('valueToShowWhenCollapsed')" | ||||
|                                         :series-object="seriesObject" | ||||
|                                         @legendHoverChanged="legendHoverChanged" | ||||
|             <plot-legend-item-collapsed | ||||
|                 v-for="seriesObject in series" | ||||
|                 :key="seriesObject.keyString" | ||||
|                 :highlights="highlights" | ||||
|                 :value-to-show-when-collapsed="legend.get('valueToShowWhenCollapsed')" | ||||
|                 :series-object="seriesObject" | ||||
|                 @legendHoverChanged="legendHoverChanged" | ||||
|             /> | ||||
|         </div> | ||||
|         <!-- EXPANDED PLOT LEGEND --> | ||||
|         <div class="plot-wrapper-expanded-legend" | ||||
|              :class="{'is-cursor-locked': cursorLocked }" | ||||
|         <div | ||||
|             class="plot-wrapper-expanded-legend" | ||||
|             :class="{'is-cursor-locked': cursorLocked }" | ||||
|         > | ||||
|             <div class="c-state-indicator__alert-cursor-lock--verbose icon-cursor-lock" | ||||
|                  title="Click anywhere in the plot to unlock." | ||||
|             <div | ||||
|                 class="c-state-indicator__alert-cursor-lock--verbose icon-cursor-lock" | ||||
|                 title="Click anywhere in the plot to unlock." | ||||
|             > Cursor locked to point</div> | ||||
|             <table> | ||||
|                 <thead> | ||||
| @@ -71,12 +79,14 @@ | ||||
|                         <th v-if="showUnitsWhenExpanded"> | ||||
|                             Unit | ||||
|                         </th> | ||||
|                         <th v-if="showMinimumWhenExpanded" | ||||
|                         <th | ||||
|                             v-if="showMinimumWhenExpanded" | ||||
|                             class="mobile-hide" | ||||
|                         > | ||||
|                             Min | ||||
|                         </th> | ||||
|                         <th v-if="showMaximumWhenExpanded" | ||||
|                         <th | ||||
|                             v-if="showMaximumWhenExpanded" | ||||
|                             class="mobile-hide" | ||||
|                         > | ||||
|                             Max | ||||
| @@ -84,12 +94,13 @@ | ||||
|                     </tr> | ||||
|                 </thead> | ||||
|                 <tbody> | ||||
|                     <plot-legend-item-expanded v-for="seriesObject in series" | ||||
|                                                :key="seriesObject.keyString" | ||||
|                                                :series-object="seriesObject" | ||||
|                                                :highlights="highlights" | ||||
|                                                :legend="legend" | ||||
|                                                @legendHoverChanged="legendHoverChanged" | ||||
|                     <plot-legend-item-expanded | ||||
|                         v-for="seriesObject in series" | ||||
|                         :key="seriesObject.keyString" | ||||
|                         :series-object="seriesObject" | ||||
|                         :highlights="highlights" | ||||
|                         :legend="legend" | ||||
|                         @legendHoverChanged="legendHoverChanged" | ||||
|                     /> | ||||
|                 </tbody> | ||||
|             </table> | ||||
|   | ||||
| @@ -20,26 +20,30 @@ | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <template> | ||||
| <div class="plot-legend-item" | ||||
|      :class="{ | ||||
|          'is-status--missing': isMissing | ||||
|      }" | ||||
|      @mouseover="toggleHover(true)" | ||||
|      @mouseleave="toggleHover(false)" | ||||
| <div | ||||
|     class="plot-legend-item" | ||||
|     :class="{ | ||||
|         'is-status--missing': isMissing | ||||
|     }" | ||||
|     @mouseover="toggleHover(true)" | ||||
|     @mouseleave="toggleHover(false)" | ||||
| > | ||||
|     <div class="plot-series-swatch-and-name"> | ||||
|         <span class="plot-series-color-swatch" | ||||
|               :style="{ 'background-color': colorAsHexString }" | ||||
|         <span | ||||
|             class="plot-series-color-swatch" | ||||
|             :style="{ 'background-color': colorAsHexString }" | ||||
|         > | ||||
|         </span> | ||||
|         <span class="is-status__indicator" | ||||
|               title="This item is missing or suspect" | ||||
|         <span | ||||
|             class="is-status__indicator" | ||||
|             title="This item is missing or suspect" | ||||
|         ></span> | ||||
|         <span class="plot-series-name">{{ nameWithUnit }}</span> | ||||
|     </div> | ||||
|     <div v-show="!!highlights.length && (valueToShowWhenCollapsed !== 'none')" | ||||
|          class="plot-series-value hover-value-enabled" | ||||
|          :class="[{ 'cursor-hover': notNearest }, valueToDisplayWhenCollapsedClass, mctLimitStateClass]" | ||||
|     <div | ||||
|         v-show="!!highlights.length && (valueToShowWhenCollapsed !== 'none')" | ||||
|         class="plot-series-value hover-value-enabled" | ||||
|         :class="[{ 'cursor-hover': notNearest }, valueToDisplayWhenCollapsedClass, mctLimitStateClass]" | ||||
|     > | ||||
|         <span v-if="valueToShowWhenCollapsed === 'nearestValue'">{{ formattedYValue }}</span> | ||||
|         <span v-else-if="valueToShowWhenCollapsed === 'nearestTimestamp'">{{ formattedXValue }}</span> | ||||
|   | ||||
| @@ -29,12 +29,14 @@ | ||||
|     @mouseleave="toggleHover(false)" | ||||
| > | ||||
|     <td class="plot-series-swatch-and-name"> | ||||
|         <span class="plot-series-color-swatch" | ||||
|               :style="{ 'background-color': colorAsHexString }" | ||||
|         <span | ||||
|             class="plot-series-color-swatch" | ||||
|             :style="{ 'background-color': colorAsHexString }" | ||||
|         > | ||||
|         </span> | ||||
|         <span class="is-status__indicator" | ||||
|               title="This item is missing or suspect" | ||||
|         <span | ||||
|             class="is-status__indicator" | ||||
|             title="This item is missing or suspect" | ||||
|         ></span> | ||||
|         <span class="plot-series-name">{{ name }}</span> | ||||
|     </td> | ||||
| @@ -45,8 +47,9 @@ | ||||
|         </span> | ||||
|     </td> | ||||
|     <td v-if="showValueWhenExpanded"> | ||||
|         <span class="plot-series-value cursor-hover hover-value-enabled" | ||||
|               :class="[mctLimitStateClass]" | ||||
|         <span | ||||
|             class="plot-series-value cursor-hover hover-value-enabled" | ||||
|             :class="[mctLimitStateClass]" | ||||
|         > | ||||
|             {{ formattedYValue }} | ||||
|         </span> | ||||
| @@ -56,14 +59,16 @@ | ||||
|             {{ unit }} | ||||
|         </span> | ||||
|     </td> | ||||
|     <td v-if="showMinimumWhenExpanded" | ||||
|     <td | ||||
|         v-if="showMinimumWhenExpanded" | ||||
|         class="mobile-hide" | ||||
|     > | ||||
|         <span class="plot-series-value"> | ||||
|             {{ formattedMinY }} | ||||
|         </span> | ||||
|     </td> | ||||
|     <td v-if="showMaximumWhenExpanded" | ||||
|     <td | ||||
|         v-if="showMaximumWhenExpanded" | ||||
|         class="mobile-hide" | ||||
|     > | ||||
|         <span class="plot-series-value"> | ||||
|   | ||||
| @@ -22,47 +22,53 @@ | ||||
|  | ||||
| <template> | ||||
| <div class="c-plot c-plot--stacked holder holder-plot has-control-bar"> | ||||
|     <div v-show="!hideExportButtons && !options.compact" | ||||
|          class="c-control-bar" | ||||
|     <div | ||||
|         v-show="!hideExportButtons && !options.compact" | ||||
|         class="c-control-bar" | ||||
|     > | ||||
|         <span class="c-button-set c-button-set--strip-h"> | ||||
|             <button class="c-button icon-download" | ||||
|                     title="Export This View's Data as PNG" | ||||
|                     @click="exportPNG()" | ||||
|             <button | ||||
|                 class="c-button icon-download" | ||||
|                 title="Export This View's Data as PNG" | ||||
|                 @click="exportPNG()" | ||||
|             > | ||||
|                 <span class="c-button__label">PNG</span> | ||||
|             </button> | ||||
|             <button class="c-button" | ||||
|                     title="Export This View's Data as JPG" | ||||
|                     @click="exportJPG()" | ||||
|             <button | ||||
|                 class="c-button" | ||||
|                 title="Export This View's Data as JPG" | ||||
|                 @click="exportJPG()" | ||||
|             > | ||||
|                 <span class="c-button__label">JPG</span> | ||||
|             </button> | ||||
|         </span> | ||||
|         <button class="c-button icon-crosshair" | ||||
|                 :class="{ 'is-active': cursorGuide }" | ||||
|                 title="Toggle cursor guides" | ||||
|                 @click="toggleCursorGuide" | ||||
|         <button | ||||
|             class="c-button icon-crosshair" | ||||
|             :class="{ 'is-active': cursorGuide }" | ||||
|             title="Toggle cursor guides" | ||||
|             @click="toggleCursorGuide" | ||||
|         > | ||||
|         </button> | ||||
|         <button class="c-button" | ||||
|                 :class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }" | ||||
|                 title="Toggle grid lines" | ||||
|                 @click="toggleGridLines" | ||||
|         <button | ||||
|             class="c-button" | ||||
|             :class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }" | ||||
|             title="Toggle grid lines" | ||||
|             @click="toggleGridLines" | ||||
|         > | ||||
|         </button> | ||||
|     </div> | ||||
|     <div class="l-view-section"> | ||||
|         <stacked-plot-item v-for="object in compositionObjects" | ||||
|                            :key="object.id" | ||||
|                            class="c-plot--stacked-container" | ||||
|                            :object="object" | ||||
|                            :options="options" | ||||
|                            :grid-lines="gridLines" | ||||
|                            :cursor-guide="cursorGuide" | ||||
|                            :plot-tick-width="maxTickWidth" | ||||
|                            @plotTickWidth="onTickWidthChange" | ||||
|                            @loadingUpdated="loadingUpdated" | ||||
|         <stacked-plot-item | ||||
|             v-for="object in compositionObjects" | ||||
|             :key="object.id" | ||||
|             class="c-plot--stacked-container" | ||||
|             :object="object" | ||||
|             :options="options" | ||||
|             :grid-lines="gridLines" | ||||
|             :cursor-guide="cursorGuide" | ||||
|             :plot-tick-width="maxTickWidth" | ||||
|             @plotTickWidth="onTickWidthChange" | ||||
|             @loadingUpdated="loadingUpdated" | ||||
|         /> | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -61,7 +61,6 @@ define([ | ||||
|     './URLTimeSettingsSynchronizer/plugin', | ||||
|     './notificationIndicator/plugin', | ||||
|     './newFolderAction/plugin', | ||||
|     './nonEditableFolder/plugin', | ||||
|     './persistence/couch/plugin', | ||||
|     './defaultRootName/plugin', | ||||
|     './plan/plugin', | ||||
| @@ -119,7 +118,6 @@ define([ | ||||
|     URLTimeSettingsSynchronizer, | ||||
|     NotificationIndicator, | ||||
|     NewFolderAction, | ||||
|     NonEditableFolder, | ||||
|     CouchDBPlugin, | ||||
|     DefaultRootName, | ||||
|     PlanLayout, | ||||
| @@ -197,7 +195,6 @@ define([ | ||||
|     plugins.URLTimeSettingsSynchronizer = URLTimeSettingsSynchronizer.default; | ||||
|     plugins.NotificationIndicator = NotificationIndicator.default; | ||||
|     plugins.NewFolderAction = NewFolderAction.default; | ||||
|     plugins.NonEditableFolder = NonEditableFolder.default; | ||||
|     plugins.ISOTimeFormat = ISOTimeFormat.default; | ||||
|     plugins.DefaultRootName = DefaultRootName.default; | ||||
|     plugins.PlanLayout = PlanLayout.default; | ||||
|   | ||||
| @@ -106,6 +106,11 @@ export default class RemoveAction { | ||||
|         let child = objectPath[0]; | ||||
|         let locked = child.locked ? child.locked : parent && parent.locked; | ||||
|         let isEditing = this.openmct.editor.isEditing(); | ||||
|         let isPersistable = this.openmct.objects.isPersistable(child.identifier); | ||||
|  | ||||
|         if (locked || !isPersistable) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (isEditing) { | ||||
|             let currentItemInView = this.openmct.router.path[0]; | ||||
| @@ -116,10 +121,6 @@ export default class RemoveAction { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (locked) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return parentType | ||||
|             && parentType.definition.creatable | ||||
|             && Array.isArray(parent.composition); | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user