mirror of
https://github.com/nasa/openmct.git
synced 2025-06-26 11:09:22 +00:00
Compare commits
11 Commits
remove-dep
...
recent-obj
Author | SHA1 | Date | |
---|---|---|---|
9561ac446a | |||
890e0115b3 | |||
bc46ab7393 | |||
c8fbdafc1a | |||
7a82e8c0a6 | |||
4640ab8331 | |||
16253a921f | |||
1ab48b6f50 | |||
48843ba3b0 | |||
de46b26029 | |||
45996f730b |
@ -22,3 +22,9 @@
|
|||||||
!index.html
|
!index.html
|
||||||
!openmct.js
|
!openmct.js
|
||||||
!SECURITY.md
|
!SECURITY.md
|
||||||
|
|
||||||
|
# Add e2e tests to npm package
|
||||||
|
!/e2e/**/*
|
||||||
|
|
||||||
|
# ... except our test-data folder files.
|
||||||
|
/e2e/test-data/*.json
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
This is the OpenMCT common webpack file. It is imported by the other three webpack configurations:
|
This is the OpenMCT common webpack file. It is imported by the other three webpack configurations:
|
||||||
- webpack.prod.mjs - the production configuration for OpenMCT (default)
|
- webpack.prod.js - the production configuration for OpenMCT (default)
|
||||||
- webpack.dev.mjs - the development configuration for OpenMCT
|
- webpack.dev.js - the development configuration for OpenMCT
|
||||||
- webpack.coverage.mjs - imports webpack.dev.js and adds code coverage
|
- webpack.coverage.js - imports webpack.dev.js and adds code coverage
|
||||||
There are separate npm scripts to use these configurations, though simply running `npm install`
|
There are separate npm scripts to use these configurations, though simply running `npm install`
|
||||||
will use the default production configuration.
|
will use the default production configuration.
|
||||||
*/
|
*/
|
||||||
@ -15,7 +15,6 @@ import CopyWebpackPlugin from 'copy-webpack-plugin';
|
|||||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||||
import { VueLoaderPlugin } from 'vue-loader';
|
import { VueLoaderPlugin } from 'vue-loader';
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import { merge } from 'webpack-merge';
|
|
||||||
let gitRevision = 'error-retrieving-revision';
|
let gitRevision = 'error-retrieving-revision';
|
||||||
let gitBranch = 'error-retrieving-branch';
|
let gitBranch = 'error-retrieving-branch';
|
||||||
|
|
||||||
@ -55,11 +54,9 @@ const config = {
|
|||||||
globalObject: 'this',
|
globalObject: 'this',
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
path: path.resolve(projectRootDir, 'dist'),
|
path: path.resolve(projectRootDir, 'dist'),
|
||||||
library: {
|
library: 'openmct',
|
||||||
name: 'openmct',
|
libraryExport: 'default',
|
||||||
type: 'umd',
|
libraryTarget: 'umd',
|
||||||
export: 'default'
|
|
||||||
},
|
|
||||||
publicPath: '',
|
publicPath: '',
|
||||||
hashFunction: 'xxhash64',
|
hashFunction: 'xxhash64',
|
||||||
clean: true
|
clean: true
|
@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
This file extends the webpack.dev.mjs config to add babel istanbul coverage.
|
This file extends the webpack.dev.js config to add babel istanbul coverage.
|
||||||
OpenMCT Continuous Integration servers use this configuration to add code coverage
|
OpenMCT Continuous Integration servers use this configuration to add code coverage
|
||||||
information to pull requests.
|
information to pull requests.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import config from './webpack.dev.mjs';
|
import config from './webpack.dev.js';
|
||||||
|
|
||||||
config.devtool = 'source-map';
|
config.devtool = 'source-map';
|
||||||
config.devServer.hot = false;
|
config.devServer.hot = false;
|
||||||
@ -16,6 +16,7 @@ config.module.rules.push({
|
|||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: {
|
options: {
|
||||||
retainLines: true,
|
retainLines: true,
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
plugins: [
|
plugins: [
|
||||||
[
|
[
|
||||||
'babel-plugin-istanbul',
|
'babel-plugin-istanbul',
|
@ -1,15 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
This configuration should be used for development purposes. It contains full source map, a
|
This configuration should be used for development purposes. It contains full source map, a
|
||||||
devServer (which be invoked using by `npm start`), and a non-minified Vue.js distribution.
|
devServer (which be invoked using by `npm start`), and a non-minified Vue.js distribution.
|
||||||
If OpenMCT is to be used for a production server, use webpack.prod.mjs instead.
|
If OpenMCT is to be used for a production server, use webpack.prod.js instead.
|
||||||
*/
|
*/
|
||||||
import { fileURLToPath } from 'node:url';
|
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import { merge } from 'webpack-merge';
|
import { merge } from 'webpack-merge';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
import common from './webpack.common.mjs';
|
import common from './webpack.common.js';
|
||||||
|
|
||||||
export default merge(common, {
|
export default merge(common, {
|
||||||
mode: 'development',
|
mode: 'development',
|
@ -6,7 +6,7 @@ It is the default webpack configuration.
|
|||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import { merge } from 'webpack-merge';
|
import { merge } from 'webpack-merge';
|
||||||
|
|
||||||
import common from './webpack.common.mjs';
|
import common from './webpack.common.js';
|
||||||
|
|
||||||
export default merge(common, {
|
export default merge(common, {
|
||||||
mode: 'production',
|
mode: 'production',
|
@ -63,7 +63,7 @@ Once the file is generated, it can be published to codecov with
|
|||||||
### e2e
|
### e2e
|
||||||
The e2e line coverage is a bit more complex than the karma implementation. This is the general sequence of events:
|
The e2e line coverage is a bit more complex than the karma implementation. This is the general sequence of events:
|
||||||
|
|
||||||
1. Each e2e suite will start webpack with the ```npm run start:coverage``` command with config `webpack.coverage.mjs` and the `babel-plugin-istanbul` plugin to generate code coverage during e2e test execution using our custom [baseFixture](./baseFixtures.js).
|
1. Each e2e suite will start webpack with the ```npm run start:coverage``` command with config `webpack.coverage.js` and the `babel-plugin-istanbul` plugin to generate code coverage during e2e test execution using our custom [baseFixture](./baseFixtures.js).
|
||||||
1. During testcase execution, each e2e shard will generate its piece of the larger coverage suite. **This coverage file is not merged**. The raw coverage file is stored in a `.nyc_report` directory.
|
1. During testcase execution, each e2e shard will generate its piece of the larger coverage suite. **This coverage file is not merged**. The raw coverage file is stored in a `.nyc_report` directory.
|
||||||
1. [nyc](https://github.com/istanbuljs/nyc) converts this directory into a `lcov` file with the following command `npm run cov:e2e:report`
|
1. [nyc](https://github.com/istanbuljs/nyc) converts this directory into a `lcov` file with the following command `npm run cov:e2e:report`
|
||||||
1. Most of the tests are run in the '@stable' configuration and focus on chrome/ubuntu at a single resolution. This coverage is published to codecov with `npm run cov:e2e:stable:publish`.
|
1. Most of the tests are run in the '@stable' configuration and focus on chrome/ubuntu at a single resolution. This coverage is published to codecov with `npm run cov:e2e:stable:publish`.
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
*
|
|
||||||
!appActions.js
|
|
||||||
!baseFixtures.js
|
|
||||||
!pluginFixtures.js
|
|
||||||
!avpFixtures.js
|
|
||||||
!index.js
|
|
||||||
!*.md
|
|
@ -167,9 +167,9 @@ When an a11y test fails, the result must be interpreted in the html test report
|
|||||||
|
|
||||||
The open source performance tests function in three ways which match their naming and folder structure:
|
The open source performance tests function in three ways which match their naming and folder structure:
|
||||||
|
|
||||||
`tests/performance` - The tests at the root of this folder path detect functional changes which are mostly apparent with large performance regressions like [this](https://github.com/nasa/openmct/issues/6879). These tests run against openmct webpack in `production-mode` with the `npm run test:perf:localhost` script.
|
`./e2e/tests/performance` - The tests at the root of this folder path detect functional changes which are mostly apparent with large performance regressions like [this](https://github.com/nasa/openmct/issues/6879). These tests run against openmct webpack in `production-mode` with the `npm run test:perf:localhost` script.
|
||||||
`tests/performance/contract/` - These tests serve as [contracts](https://martinfowler.com/bliki/ContractTest.html) for the locator logic, functionality, and assumptions will work in our downstream, closed source test suites. These tests run against openmct webpack in `dev-mode` with the `npm run test:perf:contract` script.
|
`./e2e/tests/performance/contract/` - These tests serve as [contracts](https://martinfowler.com/bliki/ContractTest.html) for the locator logic, functionality, and assumptions will work in our downstream, closed source test suites. These tests run against openmct webpack in `dev-mode` with the `npm run test:perf:contract` script.
|
||||||
`tests/performance/memory/` - These tests execute memory leak detection checks in various ways. This is expected to evolve as we move to the `memlab` project. These tests run against openmct webpack in `production-mode` with the `npm run test:perf:memory` script.
|
`./e2e/tests/performance/memory/` - These tests execute memory leak detection checks in various ways. This is expected to evolve as we move to the `memlab` project. These tests run against openmct webpack in `production-mode` with the `npm run test:perf:memory` script.
|
||||||
|
|
||||||
These tests are expected to become blocking and gating with assertions as we extend the capabilities of Playwright.
|
These tests are expected to become blocking and gating with assertions as we extend the capabilities of Playwright.
|
||||||
|
|
||||||
|
@ -60,16 +60,14 @@ function waitForAnimations(locator) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const istanbulCLIOutput = fileURLToPath(new URL('.nyc_output', import.meta.url));
|
|
||||||
|
|
||||||
const extendedTest = test.extend({
|
|
||||||
/**
|
/**
|
||||||
* Path to output raw coverage files. Can be overridden in Playwright config file.
|
* This is part of our codecoverage shim.
|
||||||
* @see {@link https://github.com/mxschmitt/playwright-test-coverage Github Example Project}
|
* @see {@link https://github.com/mxschmitt/playwright-test-coverage Github Example Project}
|
||||||
* @constant {string}
|
* @constant {string}
|
||||||
*/
|
*/
|
||||||
|
const istanbulCLIOutput = path.join(process.cwd(), '.nyc_output');
|
||||||
|
|
||||||
coveragePath: [istanbulCLIOutput, { option: true }],
|
const extendedTest = test.extend({
|
||||||
/**
|
/**
|
||||||
* This allows the test to manipulate the browser clock. This is useful for Visual and Snapshot tests which need
|
* This allows the test to manipulate the browser clock. This is useful for Visual and Snapshot tests which need
|
||||||
* the Time Indicator Clock to be in a specific state.
|
* the Time Indicator Clock to be in a specific state.
|
||||||
@ -150,17 +148,17 @@ const extendedTest = test.extend({
|
|||||||
* Extends the base context class to add codecoverage shim.
|
* Extends the base context class to add codecoverage shim.
|
||||||
* @see {@link https://github.com/mxschmitt/playwright-test-coverage Github Project}
|
* @see {@link https://github.com/mxschmitt/playwright-test-coverage Github Project}
|
||||||
*/
|
*/
|
||||||
context: async ({ context, coveragePath }, use) => {
|
context: async ({ context }, use) => {
|
||||||
await context.addInitScript(() =>
|
await context.addInitScript(() =>
|
||||||
window.addEventListener('beforeunload', () =>
|
window.addEventListener('beforeunload', () =>
|
||||||
window.collectIstanbulCoverage(JSON.stringify(window.__coverage__))
|
window.collectIstanbulCoverage(JSON.stringify(window.__coverage__))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
await fs.promises.mkdir(coveragePath, { recursive: true });
|
await fs.promises.mkdir(istanbulCLIOutput, { recursive: true });
|
||||||
await context.exposeFunction('collectIstanbulCoverage', (coverageJSON) => {
|
await context.exposeFunction('collectIstanbulCoverage', (coverageJSON) => {
|
||||||
if (coverageJSON) {
|
if (coverageJSON) {
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(coveragePath, `playwright_coverage_${uuid()}.json`),
|
path.join(istanbulCLIOutput, `playwright_coverage_${uuid()}.json`),
|
||||||
coverageJSON
|
coverageJSON
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -168,9 +166,9 @@ const extendedTest = test.extend({
|
|||||||
|
|
||||||
await use(context);
|
await use(context);
|
||||||
for (const page of context.pages()) {
|
for (const page of context.pages()) {
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() =>
|
||||||
window.collectIstanbulCoverage(JSON.stringify(window.__coverage__));
|
window.collectIstanbulCoverage(JSON.stringify(window.__coverage__))
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
// Import everything from the specific fixture files
|
|
||||||
import * as appActions from './appActions.js';
|
|
||||||
import * as avpFixtures from './avpFixtures.js';
|
|
||||||
import * as baseFixtures from './baseFixtures.js';
|
|
||||||
import * as pluginFixtures from './pluginFixtures.js';
|
|
||||||
|
|
||||||
// Export these as named exports
|
|
||||||
export { appActions, avpFixtures, baseFixtures, pluginFixtures };
|
|
1449
e2e/package-lock.json
generated
1449
e2e/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "openmct-e2e",
|
|
||||||
"version": "4.0.0-next",
|
|
||||||
"description": "The Open MCT e2e framework",
|
|
||||||
"type": "module",
|
|
||||||
"module": "index.js",
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"import": "./index.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"pretest:visual": "npm install",
|
|
||||||
"test": "npx playwright test",
|
|
||||||
"test:visual": "percy exec"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/sinonjs__fake-timers": "8.1.5",
|
|
||||||
"@percy/cli": "1.27.4",
|
|
||||||
"@percy/playwright": "1.0.4",
|
|
||||||
"@playwright/test": "1.42.1",
|
|
||||||
"@axe-core/playwright": "4.8.5",
|
|
||||||
"sinon": "17.0.0"
|
|
||||||
},
|
|
||||||
"author": "NASA Ames Research Center",
|
|
||||||
"license": "Apache-2.0"
|
|
||||||
}
|
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
import { devices } from '@playwright/test';
|
import { devices } from '@playwright/test';
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
const MAX_FAILURES = 5;
|
const MAX_FAILURES = 5;
|
||||||
const NUM_WORKERS = 2;
|
const NUM_WORKERS = 2;
|
||||||
|
|
||||||
@ -16,7 +15,6 @@ const config = {
|
|||||||
timeout: 60 * 1000,
|
timeout: 60 * 1000,
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npm run start:coverage',
|
command: 'npm run start:coverage',
|
||||||
cwd: fileURLToPath(new URL('../', import.meta.url)), // Provide cwd for the root of the project
|
|
||||||
url: 'http://localhost:8080/#',
|
url: 'http://localhost:8080/#',
|
||||||
timeout: 200 * 1000,
|
timeout: 200 * 1000,
|
||||||
reuseExistingServer: true //This was originally disabled to prevent differences in local debugging vs. CI. However, it significantly speeds up local debugging.
|
reuseExistingServer: true //This was originally disabled to prevent differences in local debugging vs. CI. However, it significantly speeds up local debugging.
|
||||||
@ -29,9 +27,7 @@ const config = {
|
|||||||
ignoreHTTPSErrors: true,
|
ignoreHTTPSErrors: true,
|
||||||
screenshot: 'only-on-failure',
|
screenshot: 'only-on-failure',
|
||||||
trace: 'on-first-retry',
|
trace: 'on-first-retry',
|
||||||
video: 'off',
|
video: 'off'
|
||||||
// @ts-ignore - custom configuration option for nyc codecoverage output path
|
|
||||||
coveragePath: fileURLToPath(new URL('../.nyc_output', import.meta.url))
|
|
||||||
},
|
},
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// playwright.config.js
|
// playwright.config.js
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
||||||
const config = {
|
const config = {
|
||||||
retries: 0,
|
retries: 0,
|
||||||
@ -10,7 +10,6 @@ const config = {
|
|||||||
timeout: 30 * 1000,
|
timeout: 30 * 1000,
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npm run start:coverage',
|
command: 'npm run start:coverage',
|
||||||
cwd: fileURLToPath(new URL('../', import.meta.url)), // Provide cwd for the root of the project
|
|
||||||
url: 'http://localhost:8080/#',
|
url: 'http://localhost:8080/#',
|
||||||
timeout: 120 * 1000,
|
timeout: 120 * 1000,
|
||||||
reuseExistingServer: true
|
reuseExistingServer: true
|
||||||
|
@ -14,7 +14,6 @@ const config = {
|
|||||||
timeout: 30 * 1000,
|
timeout: 30 * 1000,
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npm run start:coverage',
|
command: 'npm run start:coverage',
|
||||||
cwd: fileURLToPath(new URL('../', import.meta.url)), // Provide cwd for the root of the project
|
|
||||||
url: 'http://localhost:8080/#',
|
url: 'http://localhost:8080/#',
|
||||||
timeout: 200 * 1000,
|
timeout: 200 * 1000,
|
||||||
reuseExistingServer: true //This was originally disabled to prevent differences in local debugging vs. CI. However, it significantly speeds up local debugging.
|
reuseExistingServer: true //This was originally disabled to prevent differences in local debugging vs. CI. However, it significantly speeds up local debugging.
|
||||||
@ -28,9 +27,7 @@ const config = {
|
|||||||
ignoreHTTPSErrors: true,
|
ignoreHTTPSErrors: true,
|
||||||
screenshot: 'only-on-failure',
|
screenshot: 'only-on-failure',
|
||||||
trace: 'on-first-retry',
|
trace: 'on-first-retry',
|
||||||
video: 'off',
|
video: 'off'
|
||||||
// @ts-ignore - custom configuration option for nyc codecoverage output path
|
|
||||||
coveragePath: fileURLToPath(new URL('../.nyc_output', import.meta.url))
|
|
||||||
},
|
},
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// playwright.config.js
|
// playwright.config.js
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
||||||
const config = {
|
const config = {
|
||||||
retries: 1, //Only for debugging purposes for trace: 'on-first-retry'
|
retries: 1, //Only for debugging purposes for trace: 'on-first-retry'
|
||||||
@ -10,7 +10,6 @@ const config = {
|
|||||||
workers: 1, //Only run in serial with 1 worker
|
workers: 1, //Only run in serial with 1 worker
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npm run start', //need development mode for performance.marks and others
|
command: 'npm run start', //need development mode for performance.marks and others
|
||||||
cwd: fileURLToPath(new URL('../', import.meta.url)), // Provide cwd for the root of the project
|
|
||||||
url: 'http://localhost:8080/#',
|
url: 'http://localhost:8080/#',
|
||||||
timeout: 200 * 1000,
|
timeout: 200 * 1000,
|
||||||
reuseExistingServer: false
|
reuseExistingServer: false
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// playwright.config.js
|
// playwright.config.js
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
||||||
const config = {
|
const config = {
|
||||||
retries: 0, //Only for debugging purposes for trace: 'on-first-retry'
|
retries: 0, //Only for debugging purposes for trace: 'on-first-retry'
|
||||||
@ -10,7 +10,6 @@ const config = {
|
|||||||
workers: 1, //Only run in serial with 1 worker
|
workers: 1, //Only run in serial with 1 worker
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npm run start:prod', //Production mode
|
command: 'npm run start:prod', //Production mode
|
||||||
cwd: fileURLToPath(new URL('../', import.meta.url)), // Provide cwd for the root of the project
|
|
||||||
url: 'http://localhost:8080/#',
|
url: 'http://localhost:8080/#',
|
||||||
timeout: 200 * 1000,
|
timeout: 200 * 1000,
|
||||||
reuseExistingServer: false //Must be run with this option to prevent dev mode
|
reuseExistingServer: false //Must be run with this option to prevent dev mode
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// playwright.config.js
|
// playwright.config.js
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
/** @type {import('@playwright/test').PlaywrightTestConfig<{ theme: string }>} */
|
/** @type {import('@playwright/test').PlaywrightTestConfig<{ theme: string }>} */
|
||||||
const config = {
|
const config = {
|
||||||
retries: 0, // Visual tests should never retry due to snapshot comparison errors. Leaving as a shim
|
retries: 0, // Visual tests should never retry due to snapshot comparison errors. Leaving as a shim
|
||||||
@ -10,7 +10,6 @@ const config = {
|
|||||||
workers: 1, //Lower stress on Circle CI Agent for Visual tests https://github.com/percy/cli/discussions/1067
|
workers: 1, //Lower stress on Circle CI Agent for Visual tests https://github.com/percy/cli/discussions/1067
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npm run start:coverage',
|
command: 'npm run start:coverage',
|
||||||
cwd: fileURLToPath(new URL('../', import.meta.url)), // Provide cwd for the root of the project
|
|
||||||
url: 'http://localhost:8080/#',
|
url: 'http://localhost:8080/#',
|
||||||
timeout: 200 * 1000,
|
timeout: 200 * 1000,
|
||||||
reuseExistingServer: !process.env.CI
|
reuseExistingServer: !process.env.CI
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// playwright.config.js
|
// playwright.config.js
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
import { devices } from '@playwright/test';
|
import { devices } from '@playwright/test';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
@ -10,7 +11,6 @@ const config = {
|
|||||||
timeout: 60 * 1000,
|
timeout: 60 * 1000,
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npm run start', //Start in dev mode for hot reloading
|
command: 'npm run start', //Start in dev mode for hot reloading
|
||||||
cwd: fileURLToPath(new URL('../', import.meta.url)), // Provide cwd for the root of the project
|
|
||||||
url: 'http://localhost:8080/#',
|
url: 'http://localhost:8080/#',
|
||||||
timeout: 200 * 1000,
|
timeout: 200 * 1000,
|
||||||
reuseExistingServer: true //This was originally disabled to prevent differences in local debugging vs. CI. However, it significantly speeds up local debugging.
|
reuseExistingServer: true //This was originally disabled to prevent differences in local debugging vs. CI. However, it significantly speeds up local debugging.
|
||||||
|
@ -31,8 +31,8 @@ import { createDomainObjectWithDefaults } from '../../appActions.js';
|
|||||||
import { expect, test } from '../../pluginFixtures.js';
|
import { expect, test } from '../../pluginFixtures.js';
|
||||||
|
|
||||||
const TEST_FOLDER = 'test folder';
|
const TEST_FOLDER = 'test folder';
|
||||||
const jsonFilePath = 'test-data/ExampleLayouts.json';
|
const jsonFilePath = 'e2e/test-data/ExampleLayouts.json';
|
||||||
const imageFilePath = 'test-data/rick.jpg';
|
const imageFilePath = 'e2e/test-data/rick.jpg';
|
||||||
|
|
||||||
test.describe('Form Validation Behavior', () => {
|
test.describe('Form Validation Behavior', () => {
|
||||||
test('Required Field indicators appear if title is empty and can be corrected', async ({
|
test('Required Field indicators appear if title is empty and can be corrected', async ({
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
|
import { getPreciseDuration } from '../../../../src/utils/duration.js';
|
||||||
import { createDomainObjectWithDefaults, createPlanFromJSON } from '../../../appActions.js';
|
import { createDomainObjectWithDefaults, createPlanFromJSON } from '../../../appActions.js';
|
||||||
import {
|
import {
|
||||||
assertPlanActivities,
|
assertPlanActivities,
|
||||||
@ -131,58 +132,3 @@ test.describe('Gantt Chart', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const ONE_SECOND = 1000;
|
|
||||||
const ONE_MINUTE = 60 * ONE_SECOND;
|
|
||||||
const ONE_HOUR = ONE_MINUTE * 60;
|
|
||||||
const ONE_DAY = ONE_HOUR * 24;
|
|
||||||
|
|
||||||
function normalizeAge(num) {
|
|
||||||
const hundredtized = num * 100;
|
|
||||||
const isWhole = hundredtized % 100 === 0;
|
|
||||||
|
|
||||||
return isWhole ? hundredtized / 100 : num;
|
|
||||||
}
|
|
||||||
|
|
||||||
function padLeadingZeros(num, numOfLeadingZeros) {
|
|
||||||
return num.toString().padStart(numOfLeadingZeros, '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
function toDoubleDigits(num) {
|
|
||||||
return padLeadingZeros(num, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toTripleDigits(num) {
|
|
||||||
return padLeadingZeros(num, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPreciseDuration(value, { excludeMilliSeconds, useDayFormat } = {}) {
|
|
||||||
let preciseDuration;
|
|
||||||
const ms = value || 0;
|
|
||||||
|
|
||||||
const duration = [
|
|
||||||
Math.floor(normalizeAge(ms / ONE_DAY)),
|
|
||||||
toDoubleDigits(Math.floor(normalizeAge((ms % ONE_DAY) / ONE_HOUR))),
|
|
||||||
toDoubleDigits(Math.floor(normalizeAge((ms % ONE_HOUR) / ONE_MINUTE))),
|
|
||||||
toDoubleDigits(Math.floor(normalizeAge((ms % ONE_MINUTE) / ONE_SECOND)))
|
|
||||||
];
|
|
||||||
if (!excludeMilliSeconds) {
|
|
||||||
duration.push(toTripleDigits(Math.floor(normalizeAge(ms % ONE_SECOND))));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useDayFormat) {
|
|
||||||
// Format days as XD
|
|
||||||
const days = duration.shift();
|
|
||||||
if (days > 0) {
|
|
||||||
preciseDuration = `${days}D ${duration.join(':')}`;
|
|
||||||
} else {
|
|
||||||
preciseDuration = duration.join(':');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const days = toDoubleDigits(duration.shift());
|
|
||||||
duration.unshift(days);
|
|
||||||
preciseDuration = duration.join(':');
|
|
||||||
}
|
|
||||||
|
|
||||||
return preciseDuration;
|
|
||||||
}
|
|
||||||
|
@ -34,7 +34,7 @@ TODO:
|
|||||||
|
|
||||||
import { expect, test } from '@playwright/test';
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
const filePath = 'test-data/PerformanceDisplayLayout.json';
|
const filePath = 'e2e/test-data/PerformanceDisplayLayout.json';
|
||||||
|
|
||||||
test.describe('Performance tests', () => {
|
test.describe('Performance tests', () => {
|
||||||
test.beforeEach(async ({ page, browser }, testInfo) => {
|
test.beforeEach(async ({ page, browser }, testInfo) => {
|
||||||
|
@ -33,7 +33,7 @@ TODO:
|
|||||||
|
|
||||||
import { expect, test } from '@playwright/test';
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
const notebookFilePath = 'test-data/PerformanceNotebook.json';
|
const notebookFilePath = 'e2e/test-data/PerformanceNotebook.json';
|
||||||
|
|
||||||
test.describe('Performance tests', () => {
|
test.describe('Performance tests', () => {
|
||||||
test.beforeEach(async ({ page, browser }, testInfo) => {
|
test.beforeEach(async ({ page, browser }, testInfo) => {
|
||||||
|
@ -33,7 +33,7 @@ test.describe('Visual - Inspector @ally @clock', () => {
|
|||||||
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
test.use({
|
test.use({
|
||||||
storageState: 'test-data/overlay_plot_with_delay_storage.json',
|
storageState: './e2e/test-data/overlay_plot_with_delay_storage.json',
|
||||||
clockOptions: {
|
clockOptions: {
|
||||||
now: MISSION_TIME,
|
now: MISSION_TIME,
|
||||||
shouldAdvanceTime: true
|
shouldAdvanceTime: true
|
||||||
|
@ -35,7 +35,7 @@ test.describe('Visual - Controlled Clock @clock', () => {
|
|||||||
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
test.use({
|
test.use({
|
||||||
storageState: 'test-data/overlay_plot_with_delay_storage.json',
|
storageState: './e2e/test-data/overlay_plot_with_delay_storage.json',
|
||||||
clockOptions: {
|
clockOptions: {
|
||||||
now: MISSION_TIME,
|
now: MISSION_TIME,
|
||||||
shouldAdvanceTime: false //Don't advance the clock
|
shouldAdvanceTime: false //Don't advance the clock
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
/*
|
/*
|
||||||
Collection of Visual Tests set to run in a default context with default Plugins. The tests within this suite
|
Collection of Visual Tests set to run in a default context with default Plugins. The tests within this suite
|
||||||
are only meant to run against openmct's app.js started by `npm run start` within the
|
are only meant to run against openmct's app.js started by `npm run start` within the
|
||||||
`playwright-visual.config.js` file.
|
`./e2e/playwright-visual.config.js` file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import percySnapshot from '@percy/playwright';
|
import percySnapshot from '@percy/playwright';
|
||||||
|
@ -24,13 +24,13 @@
|
|||||||
const loadWebpackConfig = async () => {
|
const loadWebpackConfig = async () => {
|
||||||
if (process.env.KARMA_DEBUG) {
|
if (process.env.KARMA_DEBUG) {
|
||||||
return {
|
return {
|
||||||
config: (await import('./.webpack/webpack.dev.mjs')).default,
|
config: (await import('./.webpack/webpack.dev.js')).default,
|
||||||
browsers: ['ChromeDebugging'],
|
browsers: ['ChromeDebugging'],
|
||||||
singleRun: false
|
singleRun: false
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
config: (await import('./.webpack/webpack.coverage.mjs')).default,
|
config: (await import('./.webpack/webpack.coverage.js')).default,
|
||||||
browsers: ['ChromeHeadless'],
|
browsers: ['ChromeHeadless'],
|
||||||
singleRun: true
|
singleRun: true
|
||||||
};
|
};
|
||||||
|
42
package-lock.json
generated
42
package-lock.json
generated
@ -8,12 +8,13 @@
|
|||||||
"name": "openmct",
|
"name": "openmct",
|
||||||
"version": "4.0.0-next",
|
"version": "4.0.0-next",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"workspaces": [
|
|
||||||
"e2e"
|
|
||||||
],
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@axe-core/playwright": "4.8.5",
|
||||||
"@babel/eslint-parser": "7.23.3",
|
"@babel/eslint-parser": "7.23.3",
|
||||||
"@braintree/sanitize-url": "6.0.4",
|
"@braintree/sanitize-url": "6.0.4",
|
||||||
|
"@percy/cli": "1.27.4",
|
||||||
|
"@percy/playwright": "1.0.4",
|
||||||
|
"@playwright/test": "1.42.1",
|
||||||
"@types/d3-axis": "3.0.6",
|
"@types/d3-axis": "3.0.6",
|
||||||
"@types/d3-scale": "4.0.8",
|
"@types/d3-scale": "4.0.8",
|
||||||
"@types/d3-selection": "3.0.10",
|
"@types/d3-selection": "3.0.10",
|
||||||
@ -21,6 +22,7 @@
|
|||||||
"@types/eventemitter3": "1.2.0",
|
"@types/eventemitter3": "1.2.0",
|
||||||
"@types/jasmine": "5.1.2",
|
"@types/jasmine": "5.1.2",
|
||||||
"@types/lodash": "4.17.0",
|
"@types/lodash": "4.17.0",
|
||||||
|
"@types/sinonjs__fake-timers": "8.1.5",
|
||||||
"@vue/compiler-sfc": "3.4.3",
|
"@vue/compiler-sfc": "3.4.3",
|
||||||
"babel-loader": "9.1.0",
|
"babel-loader": "9.1.0",
|
||||||
"babel-plugin-istanbul": "6.1.1",
|
"babel-plugin-istanbul": "6.1.1",
|
||||||
@ -79,6 +81,7 @@
|
|||||||
"sanitize-html": "2.12.1",
|
"sanitize-html": "2.12.1",
|
||||||
"sass": "1.71.1",
|
"sass": "1.71.1",
|
||||||
"sass-loader": "14.1.1",
|
"sass-loader": "14.1.1",
|
||||||
|
"sinon": "17.0.0",
|
||||||
"style-loader": "3.3.3",
|
"style-loader": "3.3.3",
|
||||||
"terser-webpack-plugin": "5.3.9",
|
"terser-webpack-plugin": "5.3.9",
|
||||||
"tiny-emitter": "2.1.0",
|
"tiny-emitter": "2.1.0",
|
||||||
@ -96,19 +99,6 @@
|
|||||||
"node": ">=18.14.2 <22"
|
"node": ">=18.14.2 <22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"e2e": {
|
|
||||||
"name": "openmct-e2e",
|
|
||||||
"version": "4.0.0-next",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"devDependencies": {
|
|
||||||
"@axe-core/playwright": "4.8.5",
|
|
||||||
"@percy/cli": "1.27.4",
|
|
||||||
"@percy/playwright": "1.0.4",
|
|
||||||
"@playwright/test": "1.42.1",
|
|
||||||
"@types/sinonjs__fake-timers": "8.1.5",
|
|
||||||
"sinon": "17.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@aashutoshrathi/word-wrap": {
|
"node_modules/@aashutoshrathi/word-wrap": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
|
||||||
@ -1506,9 +1496,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@percy/sdk-utils": {
|
"node_modules/@percy/sdk-utils": {
|
||||||
"version": "1.28.2",
|
"version": "1.28.1",
|
||||||
"resolved": "https://registry.npmjs.org/@percy/sdk-utils/-/sdk-utils-1.28.2.tgz",
|
"resolved": "https://registry.npmjs.org/@percy/sdk-utils/-/sdk-utils-1.28.1.tgz",
|
||||||
"integrity": "sha512-cMFz8AjZ2KunN0dVwzA+Wosk4B+6G9dUkh2YPhYvqs0KLcCyYs3s91IzOQmtBOYwAUVja/W/u6XmBHw0jaxg0A==",
|
"integrity": "sha512-joS3i5wjFYXRSVL/NbUvip+bB7ErgwNjoDcID31l61y/QaSYUVCOxl/Fy4nvePJtHVyE1hpV0O7XO3tkoG908g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
@ -1939,6 +1929,16 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/yauzl": {
|
||||||
|
"version": "2.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
||||||
|
"integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ungap/structured-clone": {
|
"node_modules/@ungap/structured-clone": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
||||||
@ -8549,10 +8549,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/openmct-e2e": {
|
|
||||||
"resolved": "e2e",
|
|
||||||
"link": true
|
|
||||||
},
|
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.3",
|
"version": "0.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
|
||||||
|
66
package.json
66
package.json
@ -2,21 +2,15 @@
|
|||||||
"name": "openmct",
|
"name": "openmct",
|
||||||
"version": "4.0.0-next",
|
"version": "4.0.0-next",
|
||||||
"description": "The Open MCT core platform",
|
"description": "The Open MCT core platform",
|
||||||
"module": "dist/openmct.js",
|
"type": "module",
|
||||||
"main": "dist/openmct.js",
|
"main": "dist/openmct.js",
|
||||||
"types": "dist/types/index.d.ts",
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"import": "./dist/openmct.js",
|
|
||||||
"require": "./dist/openmct.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workspaces": [
|
|
||||||
"e2e"
|
|
||||||
],
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@axe-core/playwright": "4.8.5",
|
||||||
"@babel/eslint-parser": "7.23.3",
|
"@babel/eslint-parser": "7.23.3",
|
||||||
"@braintree/sanitize-url": "6.0.4",
|
"@braintree/sanitize-url": "6.0.4",
|
||||||
|
"@percy/cli": "1.27.4",
|
||||||
|
"@percy/playwright": "1.0.4",
|
||||||
|
"@playwright/test": "1.42.1",
|
||||||
"@types/d3-axis": "3.0.6",
|
"@types/d3-axis": "3.0.6",
|
||||||
"@types/d3-scale": "4.0.8",
|
"@types/d3-scale": "4.0.8",
|
||||||
"@types/d3-selection": "3.0.10",
|
"@types/d3-selection": "3.0.10",
|
||||||
@ -24,6 +18,7 @@
|
|||||||
"@types/eventemitter3": "1.2.0",
|
"@types/eventemitter3": "1.2.0",
|
||||||
"@types/jasmine": "5.1.2",
|
"@types/jasmine": "5.1.2",
|
||||||
"@types/lodash": "4.17.0",
|
"@types/lodash": "4.17.0",
|
||||||
|
"@types/sinonjs__fake-timers": "8.1.5",
|
||||||
"@vue/compiler-sfc": "3.4.3",
|
"@vue/compiler-sfc": "3.4.3",
|
||||||
"babel-loader": "9.1.0",
|
"babel-loader": "9.1.0",
|
||||||
"babel-plugin-istanbul": "6.1.1",
|
"babel-plugin-istanbul": "6.1.1",
|
||||||
@ -82,6 +77,7 @@
|
|||||||
"sanitize-html": "2.12.1",
|
"sanitize-html": "2.12.1",
|
||||||
"sass": "1.71.1",
|
"sass": "1.71.1",
|
||||||
"sass-loader": "14.1.1",
|
"sass-loader": "14.1.1",
|
||||||
|
"sinon": "17.0.0",
|
||||||
"style-loader": "3.3.3",
|
"style-loader": "3.3.3",
|
||||||
"terser-webpack-plugin": "5.3.9",
|
"terser-webpack-plugin": "5.3.9",
|
||||||
"tiny-emitter": "2.1.0",
|
"tiny-emitter": "2.1.0",
|
||||||
@ -97,38 +93,38 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rm -rf ./dist ./node_modules ./coverage ./html-test-results ./test-results ./.nyc_output ",
|
"clean": "rm -rf ./dist ./node_modules ./coverage ./html-test-results ./test-results ./.nyc_output ",
|
||||||
"start": "npx webpack serve --config ./.webpack/webpack.dev.mjs",
|
"start": "npx webpack serve --config ./.webpack/webpack.dev.js",
|
||||||
"start:prod": "npx webpack serve --config ./.webpack/webpack.prod.mjs",
|
"start:prod": "npx webpack serve --config ./.webpack/webpack.prod.js",
|
||||||
"start:coverage": "npx webpack serve --config ./.webpack/webpack.coverage.mjs",
|
"start:coverage": "npx webpack serve --config ./.webpack/webpack.coverage.js",
|
||||||
"lint:js": "eslint \"example/**/*.js\" \"src/**/*.js\" \"e2e/**/*.js\" \"openmct.js\" --max-warnings=0",
|
"lint:js": "eslint \"example/**/*.js\" \"src/**/*.js\" \"e2e/**/*.js\" \"openmct.js\" --max-warnings=0",
|
||||||
"lint:vue": "eslint \"src/**/*.vue\"",
|
"lint:vue": "eslint \"src/**/*.vue\"",
|
||||||
"lint:spelling": "cspell \"**/*.{js,md,vue}\" --show-context --gitignore --quiet",
|
"lint:spelling": "cspell \"**/*.{js,md,vue}\" --show-context --gitignore --quiet",
|
||||||
"lint": "run-p \"lint:js -- {1}\" \"lint:vue -- {1}\" \"lint:spelling -- {1}\" --",
|
"lint": "run-p \"lint:js -- {1}\" \"lint:vue -- {1}\" \"lint:spelling -- {1}\" --",
|
||||||
"lint:fix": "eslint example src e2e --ext .js,.vue openmct.js --fix",
|
"lint:fix": "eslint example src e2e --ext .js,.vue openmct.js --fix",
|
||||||
"build:prod": "webpack --config ./.webpack/webpack.prod.mjs",
|
"build:prod": "webpack --config ./.webpack/webpack.prod.js",
|
||||||
"build:dev": "webpack --config ./.webpack/webpack.dev.mjs",
|
"build:dev": "webpack --config ./.webpack/webpack.dev.js",
|
||||||
"build:coverage": "webpack --config ./.webpack/webpack.coverage.mjs",
|
"build:coverage": "webpack --config ./.webpack/webpack.coverage.js",
|
||||||
"build:watch": "webpack --config ./.webpack/webpack.dev.mjs --watch",
|
"build:watch": "webpack --config ./.webpack/webpack.dev.js --watch",
|
||||||
"info": "npx envinfo --system --browsers --npmPackages --binaries --languages --markdown",
|
"info": "npx envinfo --system --browsers --npmPackages --binaries --languages --markdown",
|
||||||
"test": "karma start karma.conf.cjs",
|
"test": "karma start karma.conf.cjs",
|
||||||
"test:debug": "KARMA_DEBUG=true karma start karma.conf.cjs",
|
"test:debug": "KARMA_DEBUG=true karma start karma.conf.cjs",
|
||||||
"test:e2e": "npm test --workspace e2e",
|
"test:e2e": "npx playwright test",
|
||||||
"test:e2e:a11y": "npm test --workspace e2e -- --config=playwright-visual-a11y.config.js --project=chrome --grep @a11y",
|
"test:e2e:a11y": "npx playwright test --config=e2e/playwright-visual-a11y.config.js --project=chrome --grep @a11y",
|
||||||
"test:e2e:mobile": "npm test --workspace e2e -- --config=playwright-mobile.config.js",
|
"test:e2e:mobile": "npx playwright test --config=e2e/playwright-mobile.config.js",
|
||||||
"test:e2e:couchdb": "npm test --workspace e2e -- --config=playwright-ci.config.js --project=chrome --grep @couchdb --workers=1",
|
"test:e2e:couchdb": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep @couchdb --workers=1",
|
||||||
"test:e2e:stable": "npm test --workspace e2e -- --config=playwright-ci.config.js --project=chrome --grep-invert \"@unstable|@couchdb|@generatedata\"",
|
"test:e2e:stable": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep-invert \"@unstable|@couchdb|@generatedata\"",
|
||||||
"test:e2e:unstable": "npm test --workspace e2e -- --config=playwright-ci.config.js --project=chrome --grep @unstable",
|
"test:e2e:unstable": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep @unstable",
|
||||||
"test:e2e:local": "npm test --workspace e2e -- --config=playwright-local.config.js --project=chrome",
|
"test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome",
|
||||||
"test:e2e:generatedata": "npm test --workspace e2e -- --config=playwright-ci.config.js --project=chrome --grep @generatedata",
|
"test:e2e:generatedata": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep @generatedata",
|
||||||
"test:e2e:checksnapshots": "npm test --workspace e2e -- --config=playwright-ci.config.js --project=chrome --grep @snapshot --retries=0",
|
"test:e2e:checksnapshots": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep @snapshot --retries=0",
|
||||||
"test:e2e:updatesnapshots": "npm test --workspace e2e -- --config=playwright-ci.config.js --project=chrome --grep @snapshot --update-snapshots",
|
"test:e2e:updatesnapshots": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep @snapshot --update-snapshots",
|
||||||
"test:e2e:visual:ci": "npm run test:visual --workspace e2e -- --config .percy.ci.yml --partial -- npx playwright test --config=playwright-visual-a11y.config.js --project=chrome --grep-invert @unstable",
|
"test:e2e:visual:ci": "percy exec --config ./e2e/.percy.ci.yml --partial -- npx playwright test --config=e2e/playwright-visual-a11y.config.js --project=chrome --grep-invert @unstable",
|
||||||
"test:e2e:visual:full": "npm run test:visual --workspace e2e -- --config .percy.nightly.yml -- npx playwright test --config=playwright-visual-a11y.config.js --grep-invert @unstable",
|
"test:e2e:visual:full": "percy exec --config ./e2e/.percy.nightly.yml -- npx playwright test --config=e2e/playwright-visual-a11y.config.js --grep-invert @unstable",
|
||||||
"test:e2e:full": "npm test --workspace e2e -- --config=playwright-ci.config.js --grep-invert @couchdb",
|
"test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js --grep-invert @couchdb",
|
||||||
"test:e2e:watch": "npm test --workspace e2e -- --ui --config=playwright-watch.config.js",
|
"test:e2e:watch": "npx playwright test --ui --config=e2e/playwright-watch.config.js",
|
||||||
"test:perf:contract": "npm test --workspace e2e -- --config=playwright-performance-dev.config.js",
|
"test:perf:contract": "npx playwright test --config=e2e/playwright-performance-dev.config.js",
|
||||||
"test:perf:localhost": "npm test --workspace e2e -- --config=playwright-performance-prod.config.js --project=chrome",
|
"test:perf:localhost": "npx playwright test --config=e2e/playwright-performance-prod.config.js --project=chrome",
|
||||||
"test:perf:memory": "npm test --workspace e2e -- --config=playwright-performance-prod.config.js --project=chrome-memory",
|
"test:perf:memory": "npx playwright test --config=e2e/playwright-performance-prod.config.js --project=chrome-memory",
|
||||||
"update-about-dialog-copyright": "perl -pi -e 's/20\\d\\d\\-202\\d/2014\\-2023/gm' ./src/ui/layout/AboutDialog.vue",
|
"update-about-dialog-copyright": "perl -pi -e 's/20\\d\\d\\-202\\d/2014\\-2023/gm' ./src/ui/layout/AboutDialog.vue",
|
||||||
"update-copyright-date": "npm run update-about-dialog-copyright && grep -lr --null --include=*.{js,scss,vue,ts,sh,html,md,frag} 'Copyright (c) 20' . | xargs -r0 perl -pi -e 's/Copyright\\s\\(c\\)\\s20\\d\\d\\-20\\d\\d/Copyright \\(c\\)\\ 2014\\-2024/gm'",
|
"update-copyright-date": "npm run update-about-dialog-copyright && grep -lr --null --include=*.{js,scss,vue,ts,sh,html,md,frag} 'Copyright (c) 20' . | xargs -r0 perl -pi -e 's/Copyright\\s\\(c\\)\\s20\\d\\d\\-20\\d\\d/Copyright \\(c\\)\\ 2014\\-2024/gm'",
|
||||||
"cov:e2e:report": "nyc report --reporter=lcovonly --report-dir=./coverage/e2e",
|
"cov:e2e:report": "nyc report --reporter=lcovonly --report-dir=./coverage/e2e",
|
||||||
|
@ -22,10 +22,6 @@
|
|||||||
|
|
||||||
import TimeContext from './TimeContext.js';
|
import TimeContext from './TimeContext.js';
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('./TimeAPI').TimeConductorBounds} TimeConductorBounds
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The GlobalContext handles getting and setting time of the openmct application in general.
|
* The GlobalContext handles getting and setting time of the openmct application in general.
|
||||||
* Views will use this context unless they specify an alternate/independent time context
|
* Views will use this context unless they specify an alternate/independent time context
|
||||||
@ -42,10 +38,12 @@ class GlobalTimeContext extends TimeContext {
|
|||||||
* Get or set the start and end time of the time conductor. Basic validation
|
* Get or set the start and end time of the time conductor. Basic validation
|
||||||
* of bounds is performed.
|
* of bounds is performed.
|
||||||
*
|
*
|
||||||
* @param {TimeConductorBounds} newBounds
|
* @param {module:openmct.TimeAPI~TimeConductorBounds} newBounds
|
||||||
* @throws {Error} Validation error
|
* @throws {Error} Validation error
|
||||||
* @returns {TimeConductorBounds}
|
* @fires module:openmct.TimeAPI~bounds
|
||||||
* @override
|
* @returns {module:openmct.TimeAPI~TimeConductorBounds}
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method bounds
|
||||||
*/
|
*/
|
||||||
bounds(newBounds) {
|
bounds(newBounds) {
|
||||||
if (arguments.length > 0) {
|
if (arguments.length > 0) {
|
||||||
@ -63,9 +61,9 @@ class GlobalTimeContext extends TimeContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update bounds based on provided time and current offsets
|
* Update bounds based on provided time and current offsets
|
||||||
|
* @private
|
||||||
* @param {number} timestamp A time from which bounds will be calculated
|
* @param {number} timestamp A time from which bounds will be calculated
|
||||||
* using current offsets.
|
* using current offsets.
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
tick(timestamp) {
|
tick(timestamp) {
|
||||||
super.tick.call(this, ...arguments);
|
super.tick.call(this, ...arguments);
|
||||||
@ -83,8 +81,11 @@ class GlobalTimeContext extends TimeContext {
|
|||||||
* be manipulated by the user from the time conductor or from other views.
|
* be manipulated by the user from the time conductor or from other views.
|
||||||
* The time of interest can effectively be unset by assigning a value of
|
* The time of interest can effectively be unset by assigning a value of
|
||||||
* 'undefined'.
|
* 'undefined'.
|
||||||
|
* @fires module:openmct.TimeAPI~timeOfInterest
|
||||||
* @param newTOI
|
* @param newTOI
|
||||||
* @returns {number} the current time of interest
|
* @returns {number} the current time of interest
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method timeOfInterest
|
||||||
*/
|
*/
|
||||||
timeOfInterest(newTOI) {
|
timeOfInterest(newTOI) {
|
||||||
if (arguments.length > 0) {
|
if (arguments.length > 0) {
|
||||||
@ -92,7 +93,8 @@ class GlobalTimeContext extends TimeContext {
|
|||||||
/**
|
/**
|
||||||
* The Time of Interest has moved.
|
* The Time of Interest has moved.
|
||||||
* @event timeOfInterest
|
* @event timeOfInterest
|
||||||
* @property {number} timeOfInterest time of interest
|
* @memberof module:openmct.TimeAPI~
|
||||||
|
* @property {number} Current time of interest
|
||||||
*/
|
*/
|
||||||
this.emit('timeOfInterest', this.toi);
|
this.emit('timeOfInterest', this.toi);
|
||||||
}
|
}
|
||||||
|
@ -23,36 +23,19 @@
|
|||||||
import { MODES, REALTIME_MODE_KEY, TIME_CONTEXT_EVENTS } from './constants.js';
|
import { MODES, REALTIME_MODE_KEY, TIME_CONTEXT_EVENTS } from './constants.js';
|
||||||
import TimeContext from './TimeContext.js';
|
import TimeContext from './TimeContext.js';
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('./TimeAPI.js').default} TimeAPI
|
|
||||||
* @typedef {import('./GlobalTimeContext.js').default} GlobalTimeContext
|
|
||||||
* @typedef {import('./TimeAPI.js').TimeSystem} TimeSystem
|
|
||||||
* @typedef {import('./TimeContext.js').Mode} Mode
|
|
||||||
* @typedef {import('./TimeContext.js').TimeConductorBounds} TimeConductorBounds
|
|
||||||
* @typedef {import('./TimeAPI.js').ClockOffsets} ClockOffsets
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IndependentTimeContext handles getting and setting time of the openmct application in general.
|
* The IndependentTimeContext handles getting and setting time of the openmct application in general.
|
||||||
* Views will use the GlobalTimeContext unless they specify an alternate/independent time context here.
|
* Views will use the GlobalTimeContext unless they specify an alternate/independent time context here.
|
||||||
*/
|
*/
|
||||||
class IndependentTimeContext extends TimeContext {
|
class IndependentTimeContext extends TimeContext {
|
||||||
/**
|
|
||||||
* @param {import('openmct').OpenMCT} openmct - The Open MCT application instance.
|
|
||||||
* @param {TimeAPI & GlobalTimeContext} globalTimeContext - The global time context.
|
|
||||||
* @param {import('openmct').ObjectPath} objectPath - The path of objects.
|
|
||||||
*/
|
|
||||||
constructor(openmct, globalTimeContext, objectPath) {
|
constructor(openmct, globalTimeContext, objectPath) {
|
||||||
super();
|
super();
|
||||||
/** @type {any} */
|
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
/** @type {Function[]} */
|
|
||||||
this.unlisteners = [];
|
this.unlisteners = [];
|
||||||
/** @type {TimeAPI & GlobalTimeContext | undefined} */
|
|
||||||
this.globalTimeContext = globalTimeContext;
|
this.globalTimeContext = globalTimeContext;
|
||||||
/** @type {TimeAPI & GlobalTimeContext | undefined} */
|
// We always start with the global time context.
|
||||||
|
// This upstream context will be undefined when an independent time context is added later.
|
||||||
this.upstreamTimeContext = this.globalTimeContext;
|
this.upstreamTimeContext = this.globalTimeContext;
|
||||||
/** @type {Array<any>} */
|
|
||||||
this.objectPath = objectPath;
|
this.objectPath = objectPath;
|
||||||
this.refreshContext = this.refreshContext.bind(this);
|
this.refreshContext = this.refreshContext.bind(this);
|
||||||
this.resetContext = this.resetContext.bind(this);
|
this.resetContext = this.resetContext.bind(this);
|
||||||
@ -64,10 +47,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
this.globalTimeContext.on('removeOwnContext', this.removeIndependentContext);
|
this.globalTimeContext.on('removeOwnContext', this.removeIndependentContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
bounds() {
|
bounds() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
return this.upstreamTimeContext.bounds(...arguments);
|
return this.upstreamTimeContext.bounds(...arguments);
|
||||||
@ -76,9 +55,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
getBounds() {
|
getBounds() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
return this.upstreamTimeContext.getBounds();
|
return this.upstreamTimeContext.getBounds();
|
||||||
@ -87,9 +63,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
setBounds() {
|
setBounds() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
return this.upstreamTimeContext.setBounds(...arguments);
|
return this.upstreamTimeContext.setBounds(...arguments);
|
||||||
@ -98,9 +71,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
tick() {
|
tick() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
return this.upstreamTimeContext.tick(...arguments);
|
return this.upstreamTimeContext.tick(...arguments);
|
||||||
@ -109,9 +79,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
clockOffsets() {
|
clockOffsets() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
return this.upstreamTimeContext.clockOffsets(...arguments);
|
return this.upstreamTimeContext.clockOffsets(...arguments);
|
||||||
@ -120,9 +87,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
getClockOffsets() {
|
getClockOffsets() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
return this.upstreamTimeContext.getClockOffsets();
|
return this.upstreamTimeContext.getClockOffsets();
|
||||||
@ -131,9 +95,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
setClockOffsets() {
|
setClockOffsets() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
return this.upstreamTimeContext.setClockOffsets(...arguments);
|
return this.upstreamTimeContext.setClockOffsets(...arguments);
|
||||||
@ -142,24 +103,12 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {number} newTOI
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
timeOfInterest(newTOI) {
|
timeOfInterest(newTOI) {
|
||||||
return this.globalTimeContext.timeOfInterest(...arguments);
|
return this.globalTimeContext.timeOfInterest(...arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {TimeSystem | string} timeSystemOrKey
|
|
||||||
* @param {TimeConductorBounds} bounds
|
|
||||||
* @returns {TimeSystem}
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
timeSystem(timeSystemOrKey, bounds) {
|
timeSystem(timeSystemOrKey, bounds) {
|
||||||
return this.globalTimeContext.setTimeSystem(...arguments);
|
return this.globalTimeContext.timeSystem(...arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,7 +116,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
* @returns {TimeSystem} The currently applied time system
|
* @returns {TimeSystem} The currently applied time system
|
||||||
* @memberof module:openmct.TimeAPI#
|
* @memberof module:openmct.TimeAPI#
|
||||||
* @method getTimeSystem
|
* @method getTimeSystem
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
getTimeSystem() {
|
getTimeSystem() {
|
||||||
return this.globalTimeContext.getTimeSystem();
|
return this.globalTimeContext.getTimeSystem();
|
||||||
@ -298,7 +246,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
/**
|
/**
|
||||||
* Get the current mode.
|
* Get the current mode.
|
||||||
* @return {Mode} the current mode;
|
* @return {Mode} the current mode;
|
||||||
* @override
|
|
||||||
*/
|
*/
|
||||||
getMode() {
|
getMode() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
@ -312,8 +259,9 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
* Set the mode to either fixed or realtime.
|
* Set the mode to either fixed or realtime.
|
||||||
*
|
*
|
||||||
* @param {Mode} mode The mode to activate
|
* @param {Mode} mode The mode to activate
|
||||||
* @param {TimeConductorBounds | ClockOffsets} offsetsOrBounds A time window of a fixed width
|
* @param {TimeBounds | ClockOffsets} offsetsOrBounds A time window of a fixed width
|
||||||
* @return {Mode | undefined} the currently active mode;
|
* @fires module:openmct.TimeAPI~clock
|
||||||
|
* @return {Mode} the currently active mode;
|
||||||
*/
|
*/
|
||||||
setMode(mode, offsetsOrBounds) {
|
setMode(mode, offsetsOrBounds) {
|
||||||
if (!mode) {
|
if (!mode) {
|
||||||
@ -351,10 +299,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
return this.mode;
|
return this.mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {boolean}
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
isRealTime() {
|
isRealTime() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
return this.upstreamTimeContext.isRealTime(...arguments);
|
return this.upstreamTimeContext.isRealTime(...arguments);
|
||||||
@ -363,10 +307,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {number}
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
now() {
|
now() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
return this.upstreamTimeContext.now(...arguments);
|
return this.upstreamTimeContext.now(...arguments);
|
||||||
@ -403,9 +343,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
this.unlisteners = [];
|
this.unlisteners = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the time context to the global time context
|
|
||||||
*/
|
|
||||||
resetContext() {
|
resetContext() {
|
||||||
if (this.upstreamTimeContext) {
|
if (this.upstreamTimeContext) {
|
||||||
this.stopFollowingTimeContext();
|
this.stopFollowingTimeContext();
|
||||||
@ -415,7 +352,6 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the time context, following any upstream time contexts as necessary
|
* Refresh the time context, following any upstream time contexts as necessary
|
||||||
* @param {string} [viewKey] The key of the view to refresh
|
|
||||||
*/
|
*/
|
||||||
refreshContext(viewKey) {
|
refreshContext(viewKey) {
|
||||||
const key = this.openmct.objects.makeKeyString(this.objectPath[0].identifier);
|
const key = this.openmct.objects.makeKeyString(this.objectPath[0].identifier);
|
||||||
@ -434,17 +370,10 @@ class IndependentTimeContext extends TimeContext {
|
|||||||
this.emit(TIME_CONTEXT_EVENTS.boundsChanged, this.getBounds());
|
this.emit(TIME_CONTEXT_EVENTS.boundsChanged, this.getBounds());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {boolean} True if this time context has an independent context, false otherwise
|
|
||||||
*/
|
|
||||||
hasOwnContext() {
|
hasOwnContext() {
|
||||||
return this.upstreamTimeContext === undefined;
|
return this.upstreamTimeContext === undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the upstream time context of this time context
|
|
||||||
* @returns {TimeAPI & GlobalTimeContext | undefined} The upstream time context
|
|
||||||
*/
|
|
||||||
getUpstreamContext() {
|
getUpstreamContext() {
|
||||||
// If a view has an independent context, don't return an upstream context
|
// If a view has an independent context, don't return an upstream context
|
||||||
// Be aware that when a new independent time context is created, we assign the global context as default
|
// Be aware that when a new independent time context is created, we assign the global context as default
|
||||||
|
@ -26,16 +26,30 @@ import IndependentTimeContext from '@/api/time/IndependentTimeContext';
|
|||||||
import GlobalTimeContext from './GlobalTimeContext.js';
|
import GlobalTimeContext from './GlobalTimeContext.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('./TimeContext.js').default} TimeContext
|
* The public API for setting and querying the temporal state of the
|
||||||
*/
|
* application. The concept of time is integral to Open MCT, and at least
|
||||||
|
* one {@link TimeSystem}, as well as some default time bounds must be
|
||||||
/**
|
* registered and enabled via {@link TimeAPI.addTimeSystem} and
|
||||||
* @typedef {import('./TimeContext.js').TimeConductorBounds} TimeConductorBounds
|
* {@link TimeAPI.timeSystem} respectively for Open MCT to work.
|
||||||
*/
|
*
|
||||||
|
* Time-sensitive views will typically respond to changes to bounds or other
|
||||||
/**
|
* properties of the time conductor and update the data displayed based on
|
||||||
* @typedef {import('./TimeContext.js').ClockOffsets} ClockOffsets
|
* the temporal state of the application. The current time bounds are also
|
||||||
|
* used in queries for historical data.
|
||||||
|
*
|
||||||
|
* The TimeAPI extends the GlobalTimeContext which in turn extends the TimeContext/EventEmitter class. A number of events are
|
||||||
|
* fired when properties of the time conductor change, which are documented
|
||||||
|
* below.
|
||||||
|
*
|
||||||
|
* @interface
|
||||||
|
* @memberof module:openmct
|
||||||
*/
|
*/
|
||||||
|
class TimeAPI extends GlobalTimeContext {
|
||||||
|
constructor(openmct) {
|
||||||
|
super();
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.independentContexts = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A TimeSystem provides meaning to the values returned by the TimeAPI. Open
|
* A TimeSystem provides meaning to the values returned by the TimeAPI. Open
|
||||||
@ -60,35 +74,10 @@ import GlobalTimeContext from './GlobalTimeContext.js';
|
|||||||
* displaying a duration or relative span of time in this time system.
|
* displaying a duration or relative span of time in this time system.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* The public API for setting and querying the temporal state of the
|
|
||||||
* application. The concept of time is integral to Open MCT, and at least
|
|
||||||
* one {@link TimeSystem}, as well as some default time bounds must be
|
|
||||||
* registered and enabled via {@link TimeAPI.addTimeSystem} and
|
|
||||||
* {@link TimeAPI.timeSystem} respectively for Open MCT to work.
|
|
||||||
*
|
|
||||||
* Time-sensitive views will typically respond to changes to bounds or other
|
|
||||||
* properties of the time conductor and update the data displayed based on
|
|
||||||
* the temporal state of the application. The current time bounds are also
|
|
||||||
* used in queries for historical data.
|
|
||||||
*
|
|
||||||
* The TimeAPI extends the GlobalTimeContext which in turn extends the TimeContext/EventEmitter class. A number of events are
|
|
||||||
* fired when properties of the time conductor change, which are documented
|
|
||||||
* below.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends {GlobalTimeContext}
|
|
||||||
*/
|
|
||||||
class TimeAPI extends GlobalTimeContext {
|
|
||||||
constructor(openmct) {
|
|
||||||
super();
|
|
||||||
this.openmct = openmct;
|
|
||||||
this.independentContexts = new Map();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new time system. Once registered it can activated using
|
* Register a new time system. Once registered it can activated using
|
||||||
* {@link TimeAPI.timeSystem}, and can be referenced via its key in [Time Conductor configuration](@link https://github.com/nasa/openmct/blob/master/API.md#time-conductor).
|
* {@link TimeAPI.timeSystem}, and can be referenced via its key in [Time Conductor configuration](@link https://github.com/nasa/openmct/blob/master/API.md#time-conductor).
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
* @param {TimeSystem} timeSystem A time system object.
|
* @param {TimeSystem} timeSystem A time system object.
|
||||||
*/
|
*/
|
||||||
addTimeSystem(timeSystem) {
|
addTimeSystem(timeSystem) {
|
||||||
@ -120,6 +109,7 @@ class TimeAPI extends GlobalTimeContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new Clock.
|
* Register a new Clock.
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
* @param {Clock} clock
|
* @param {Clock} clock
|
||||||
*/
|
*/
|
||||||
addClock(clock) {
|
addClock(clock) {
|
||||||
@ -127,7 +117,9 @@ class TimeAPI extends GlobalTimeContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
* @returns {Clock[]}
|
* @returns {Clock[]}
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
*/
|
*/
|
||||||
getAllClocks() {
|
getAllClocks() {
|
||||||
return Array.from(this.clocks.values());
|
return Array.from(this.clocks.values());
|
||||||
@ -136,9 +128,11 @@ class TimeAPI extends GlobalTimeContext {
|
|||||||
/**
|
/**
|
||||||
* Get or set an independent time context which follows the TimeAPI timeSystem,
|
* Get or set an independent time context which follows the TimeAPI timeSystem,
|
||||||
* but with different offsets for a given domain object
|
* but with different offsets for a given domain object
|
||||||
* @param {string} key The identifier key of the domain object these offsets are set for
|
* @param {key | string} key The identifier key of the domain object these offsets are set for
|
||||||
* @param {ClockOffsets | TimeConductorBounds} value This maintains a sliding time window of a fixed width that automatically updates
|
* @param {ClockOffsets | TimeBounds} value This maintains a sliding time window of a fixed width that automatically updates
|
||||||
* @param {key | string} clockKey the real time clock key currently in use
|
* @param {key | string} clockKey the real time clock key currently in use
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method addIndependentTimeContext
|
||||||
*/
|
*/
|
||||||
addIndependentContext(key, value, clockKey) {
|
addIndependentContext(key, value, clockKey) {
|
||||||
let timeContext = this.getIndependentContext(key);
|
let timeContext = this.getIndependentContext(key);
|
||||||
@ -165,8 +159,9 @@ class TimeAPI extends GlobalTimeContext {
|
|||||||
/**
|
/**
|
||||||
* Get the independent time context which follows the TimeAPI timeSystem,
|
* Get the independent time context which follows the TimeAPI timeSystem,
|
||||||
* but with different offsets.
|
* but with different offsets.
|
||||||
* @param {string} key The identifier key of the domain object these offsets
|
* @param {key | string} key The identifier key of the domain object these offsets
|
||||||
* @returns {IndependentTimeContext} The independent time context
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method getIndependentTimeContext
|
||||||
*/
|
*/
|
||||||
getIndependentContext(key) {
|
getIndependentContext(key) {
|
||||||
return this.independentContexts.get(key);
|
return this.independentContexts.get(key);
|
||||||
@ -176,7 +171,8 @@ class TimeAPI extends GlobalTimeContext {
|
|||||||
* Get the a timeContext for a view based on it's objectPath. If there is any object in the objectPath with an independent time context, it will be returned.
|
* Get the a timeContext for a view based on it's objectPath. If there is any object in the objectPath with an independent time context, it will be returned.
|
||||||
* Otherwise, the global time context will be returned.
|
* Otherwise, the global time context will be returned.
|
||||||
* @param { Array } objectPath The view's objectPath
|
* @param { Array } objectPath The view's objectPath
|
||||||
* @returns {TimeContext | GlobalTimeContext} The time context
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method getContextForView
|
||||||
*/
|
*/
|
||||||
getContextForView(objectPath) {
|
getContextForView(objectPath) {
|
||||||
if (!objectPath || !Array.isArray(objectPath)) {
|
if (!objectPath || !Array.isArray(objectPath)) {
|
||||||
|
@ -24,85 +24,22 @@ import EventEmitter from 'EventEmitter';
|
|||||||
|
|
||||||
import { FIXED_MODE_KEY, MODES, REALTIME_MODE_KEY, TIME_CONTEXT_EVENTS } from './constants.js';
|
import { FIXED_MODE_KEY, MODES, REALTIME_MODE_KEY, TIME_CONTEXT_EVENTS } from './constants.js';
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('../../utils/clock/DefaultClock.js').default} Clock
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('./TimeAPI.js').TimeSystem} TimeSystem
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} TimeConductorBounds
|
|
||||||
* @property {number } start The start time displayed by the time conductor
|
|
||||||
* in ms since epoch. Epoch determined by currently active time system
|
|
||||||
* @property {number} end The end time displayed by the time conductor in ms
|
|
||||||
* since epoch.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clock offsets are used to calculate temporal bounds when the system is
|
|
||||||
* ticking on a clock source.
|
|
||||||
*
|
|
||||||
* @typedef {Object} ClockOffsets
|
|
||||||
* @property {number} start A time span relative to the current value of the
|
|
||||||
* ticking clock, from which start bounds will be calculated. This value must
|
|
||||||
* be < 0. When a clock is active, bounds will be calculated automatically
|
|
||||||
* based on the value provided by the clock, and the defined clock offsets.
|
|
||||||
* @property {number} end A time span relative to the current value of the
|
|
||||||
* ticking clock, from which end bounds will be calculated. This value must
|
|
||||||
* be >= 0.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} ValidationResult
|
|
||||||
* @property {boolean} valid Result of the validation - true or false.
|
|
||||||
* @property {string} message An error message if valid is false.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {'fixed' | 'realtime'} Mode The time conductor mode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class TimeContext
|
|
||||||
* @extends EventEmitter
|
|
||||||
*/
|
|
||||||
class TimeContext extends EventEmitter {
|
class TimeContext extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
/**
|
//The Time System
|
||||||
* The time systems available to the TimeAPI.
|
|
||||||
* @type {Map<string, TimeSystem>}
|
|
||||||
*/
|
|
||||||
this.timeSystems = new Map();
|
this.timeSystems = new Map();
|
||||||
|
|
||||||
/**
|
|
||||||
* The currently applied time system.
|
|
||||||
* @type {TimeSystem | undefined}
|
|
||||||
*/
|
|
||||||
this.system = undefined;
|
this.system = undefined;
|
||||||
|
|
||||||
/**
|
|
||||||
* The clocks available to the TimeAPI.
|
|
||||||
* @type {Map<string, import('../../utils/clock/DefaultClock.js').default>}
|
|
||||||
*/
|
|
||||||
this.clocks = new Map();
|
this.clocks = new Map();
|
||||||
|
|
||||||
/**
|
|
||||||
* The current bounds of the time conductor.
|
|
||||||
* @type {TimeConductorBounds}
|
|
||||||
*/
|
|
||||||
this.boundsVal = {
|
this.boundsVal = {
|
||||||
start: undefined,
|
start: undefined,
|
||||||
end: undefined
|
end: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* The currently active clock.
|
|
||||||
* @type {Clock | undefined}
|
|
||||||
*/
|
|
||||||
this.activeClock = undefined;
|
this.activeClock = undefined;
|
||||||
this.offsets = undefined;
|
this.offsets = undefined;
|
||||||
this.mode = undefined;
|
this.mode = undefined;
|
||||||
@ -114,9 +51,11 @@ class TimeContext extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Get or set the time system of the TimeAPI.
|
* Get or set the time system of the TimeAPI.
|
||||||
* @param {TimeSystem | string} timeSystemOrKey
|
* @param {TimeSystem | string} timeSystemOrKey
|
||||||
* @param {TimeConductorBounds} bounds
|
* @param {module:openmct.TimeAPI~TimeConductorBounds} bounds
|
||||||
|
* @fires module:openmct.TimeAPI~timeSystem
|
||||||
* @returns {TimeSystem} The currently applied time system
|
* @returns {TimeSystem} The currently applied time system
|
||||||
* @deprecated This method is deprecated. Use "getTimeSystem" and "setTimeSystem" instead.
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method timeSystem
|
||||||
*/
|
*/
|
||||||
timeSystem(timeSystemOrKey, bounds) {
|
timeSystem(timeSystemOrKey, bounds) {
|
||||||
this.#warnMethodDeprecated('"timeSystem"', '"getTimeSystem" and "setTimeSystem"');
|
this.#warnMethodDeprecated('"timeSystem"', '"getTimeSystem" and "setTimeSystem"');
|
||||||
@ -162,8 +101,11 @@ class TimeContext extends EventEmitter {
|
|||||||
* The time system used by the time
|
* The time system used by the time
|
||||||
* conductor has changed. A change in Time System will always be
|
* conductor has changed. A change in Time System will always be
|
||||||
* followed by a bounds event specifying new query bounds.
|
* followed by a bounds event specifying new query bounds.
|
||||||
* @type {TimeSystem}
|
*
|
||||||
*/
|
* @event module:openmct.TimeAPI~timeSystem
|
||||||
|
* @property {TimeSystem} The value of the currently applied
|
||||||
|
* Time System
|
||||||
|
* */
|
||||||
const system = this.#copy(this.system);
|
const system = this.#copy(this.system);
|
||||||
this.emit('timeSystem', system);
|
this.emit('timeSystem', system);
|
||||||
this.emit(TIME_CONTEXT_EVENTS.timeSystemChanged, system);
|
this.emit(TIME_CONTEXT_EVENTS.timeSystemChanged, system);
|
||||||
@ -176,11 +118,21 @@ class TimeContext extends EventEmitter {
|
|||||||
return this.system;
|
return this.system;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clock offsets are used to calculate temporal bounds when the system is
|
||||||
|
* ticking on a clock source.
|
||||||
|
*
|
||||||
|
* @typedef {Object} ValidationResult
|
||||||
|
* @property {boolean} valid Result of the validation - true or false.
|
||||||
|
* @property {string} message An error message if valid is false.
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* Validate the given bounds. This can be used for pre-validation of bounds,
|
* Validate the given bounds. This can be used for pre-validation of bounds,
|
||||||
* for example by views validating user inputs.
|
* for example by views validating user inputs.
|
||||||
* @param {TimeConductorBounds} bounds The start and end time of the conductor.
|
* @param {TimeBounds} bounds The start and end time of the conductor.
|
||||||
* @returns {ValidationResult} A validation error, or true if valid
|
* @returns {ValidationResult} A validation error, or true if valid
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method validateBounds
|
||||||
*/
|
*/
|
||||||
validateBounds(bounds) {
|
validateBounds(bounds) {
|
||||||
if (
|
if (
|
||||||
@ -210,10 +162,12 @@ class TimeContext extends EventEmitter {
|
|||||||
* Get or set the start and end time of the time conductor. Basic validation
|
* Get or set the start and end time of the time conductor. Basic validation
|
||||||
* of bounds is performed.
|
* of bounds is performed.
|
||||||
*
|
*
|
||||||
* @param {TimeConductorBounds} [newBounds] The new bounds to set. If not provided, current bounds will be returned.
|
* @param {module:openmct.TimeAPI~TimeConductorBounds} newBounds
|
||||||
* @throws {Error} Validation error
|
* @throws {Error} Validation error
|
||||||
* @returns {TimeConductorBounds} The current bounds of the time conductor.
|
* @fires module:openmct.TimeAPI~bounds
|
||||||
* @deprecated This method is deprecated. Use "getBounds" and "setBounds" instead.
|
* @returns {module:openmct.TimeAPI~TimeConductorBounds}
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method bounds
|
||||||
*/
|
*/
|
||||||
bounds(newBounds) {
|
bounds(newBounds) {
|
||||||
this.#warnMethodDeprecated('"bounds"', '"getBounds" and "setBounds"');
|
this.#warnMethodDeprecated('"bounds"', '"getBounds" and "setBounds"');
|
||||||
@ -229,6 +183,7 @@ class TimeContext extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* The start time, end time, or both have been updated.
|
* The start time, end time, or both have been updated.
|
||||||
* @event bounds
|
* @event bounds
|
||||||
|
* @memberof module:openmct.TimeAPI~
|
||||||
* @property {TimeConductorBounds} bounds The newly updated bounds
|
* @property {TimeConductorBounds} bounds The newly updated bounds
|
||||||
* @property {boolean} [tick] `true` if the bounds update was due to
|
* @property {boolean} [tick] `true` if the bounds update was due to
|
||||||
* a "tick" event (ie. was an automatic update), false otherwise.
|
* a "tick" event (ie. was an automatic update), false otherwise.
|
||||||
@ -246,6 +201,8 @@ class TimeContext extends EventEmitter {
|
|||||||
* offsets, for example by views validating user inputs.
|
* offsets, for example by views validating user inputs.
|
||||||
* @param {ClockOffsets} offsets The start and end offsets from a 'now' value.
|
* @param {ClockOffsets} offsets The start and end offsets from a 'now' value.
|
||||||
* @returns { ValidationResult } A validation error, and true/false if valid or not
|
* @returns { ValidationResult } A validation error, and true/false if valid or not
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method validateOffsets
|
||||||
*/
|
*/
|
||||||
validateOffsets(offsets) {
|
validateOffsets(offsets) {
|
||||||
if (
|
if (
|
||||||
@ -271,13 +228,34 @@ class TimeContext extends EventEmitter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} TimeBounds
|
||||||
|
* @property {number} start The start time displayed by the time conductor
|
||||||
|
* in ms since epoch. Epoch determined by currently active time system
|
||||||
|
* @property {number} end The end time displayed by the time conductor in ms
|
||||||
|
* since epoch.
|
||||||
|
* @memberof module:openmct.TimeAPI~
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clock offsets are used to calculate temporal bounds when the system is
|
||||||
|
* ticking on a clock source.
|
||||||
|
*
|
||||||
|
* @typedef {Object} ClockOffsets
|
||||||
|
* @property {number} start A time span relative to the current value of the
|
||||||
|
* ticking clock, from which start bounds will be calculated. This value must
|
||||||
|
* be < 0. When a clock is active, bounds will be calculated automatically
|
||||||
|
* based on the value provided by the clock, and the defined clock offsets.
|
||||||
|
* @property {number} end A time span relative to the current value of the
|
||||||
|
* ticking clock, from which end bounds will be calculated. This value must
|
||||||
|
* be >= 0.
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* Get or set the currently applied clock offsets. If no parameter is provided,
|
* Get or set the currently applied clock offsets. If no parameter is provided,
|
||||||
* the current value will be returned. If provided, the new value will be
|
* the current value will be returned. If provided, the new value will be
|
||||||
* used as the new clock offsets.
|
* used as the new clock offsets.
|
||||||
* @param {ClockOffsets} [offsets] The new clock offsets to set. If not provided, current offsets will be returned.
|
* @param {ClockOffsets} offsets
|
||||||
* @returns {ClockOffsets} The current clock offsets.
|
* @returns {ClockOffsets}
|
||||||
* @deprecated This method is deprecated. Use "getClockOffsets" and "setClockOffsets" instead.
|
|
||||||
*/
|
*/
|
||||||
clockOffsets(offsets) {
|
clockOffsets(offsets) {
|
||||||
this.#warnMethodDeprecated('"clockOffsets"', '"getClockOffsets" and "setClockOffsets"');
|
this.#warnMethodDeprecated('"clockOffsets"', '"getClockOffsets" and "setClockOffsets"');
|
||||||
@ -315,7 +293,6 @@ class TimeContext extends EventEmitter {
|
|||||||
* Stop following the currently active clock. This will
|
* Stop following the currently active clock. This will
|
||||||
* revert all views to showing a static time frame defined by the current
|
* revert all views to showing a static time frame defined by the current
|
||||||
* bounds.
|
* bounds.
|
||||||
* @deprecated This method is deprecated.
|
|
||||||
*/
|
*/
|
||||||
stopClock() {
|
stopClock() {
|
||||||
this.#warnMethodDeprecated('"stopClock"');
|
this.#warnMethodDeprecated('"stopClock"');
|
||||||
@ -327,14 +304,12 @@ class TimeContext extends EventEmitter {
|
|||||||
* Set the active clock. Tick source will be immediately subscribed to
|
* Set the active clock. Tick source will be immediately subscribed to
|
||||||
* and ticking will begin. Offsets from 'now' must also be provided.
|
* and ticking will begin. Offsets from 'now' must also be provided.
|
||||||
*
|
*
|
||||||
* @param {string|Clock} keyOrClock The clock to activate, or its key
|
* @param {Clock || string} keyOrClock The clock to activate, or its key
|
||||||
* @param {ClockOffsets} offsets on each tick these will be used to calculate
|
* @param {ClockOffsets} offsets on each tick these will be used to calculate
|
||||||
* the start and end bounds. This maintains a sliding time window of a fixed
|
* the start and end bounds. This maintains a sliding time window of a fixed
|
||||||
* width that automatically updates.
|
* width that automatically updates.
|
||||||
* (Legacy) Emits a "clock" event with the new clock.
|
* @fires module:openmct.TimeAPI~clock
|
||||||
* Emits a "clockChanged" event with the new clock.
|
* @return {Clock} the currently active clock;
|
||||||
* @return {Clock|undefined} the currently active clock; undefined if in fixed mode
|
|
||||||
* @deprecated This method is deprecated. Use "getClock" and "setClock" instead.
|
|
||||||
*/
|
*/
|
||||||
clock(keyOrClock, offsets) {
|
clock(keyOrClock, offsets) {
|
||||||
this.#warnMethodDeprecated('"clock"', '"getClock" and "setClock"');
|
this.#warnMethodDeprecated('"clock"', '"getClock" and "setClock"');
|
||||||
@ -364,6 +339,7 @@ class TimeContext extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* The active clock has changed.
|
* The active clock has changed.
|
||||||
* @event clock
|
* @event clock
|
||||||
|
* @memberof module:openmct.TimeAPI~
|
||||||
* @property {Clock} clock The newly activated clock, or undefined
|
* @property {Clock} clock The newly activated clock, or undefined
|
||||||
* if the system is no longer following a clock source
|
* if the system is no longer following a clock source
|
||||||
*/
|
*/
|
||||||
@ -385,7 +361,7 @@ class TimeContext extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update bounds based on provided time and current offsets.
|
* Update bounds based on provided time and current offsets
|
||||||
* @param {number} timestamp A time from which bounds will be calculated
|
* @param {number} timestamp A time from which bounds will be calculated
|
||||||
* using current offsets.
|
* using current offsets.
|
||||||
*/
|
*/
|
||||||
@ -409,6 +385,8 @@ class TimeContext extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Get the timestamp of the current clock
|
* Get the timestamp of the current clock
|
||||||
* @returns {number} current timestamp of current clock regardless of mode
|
* @returns {number} current timestamp of current clock regardless of mode
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method now
|
||||||
*/
|
*/
|
||||||
|
|
||||||
now() {
|
now() {
|
||||||
@ -418,6 +396,8 @@ class TimeContext extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Get the time system of the TimeAPI.
|
* Get the time system of the TimeAPI.
|
||||||
* @returns {TimeSystem} The currently applied time system
|
* @returns {TimeSystem} The currently applied time system
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method getTimeSystem
|
||||||
*/
|
*/
|
||||||
getTimeSystem() {
|
getTimeSystem() {
|
||||||
return this.system;
|
return this.system;
|
||||||
@ -425,9 +405,12 @@ class TimeContext extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the time system of the TimeAPI.
|
* Set the time system of the TimeAPI.
|
||||||
* Emits a "timeSystem" event with the new time system.
|
|
||||||
* @param {TimeSystem | string} timeSystemOrKey
|
* @param {TimeSystem | string} timeSystemOrKey
|
||||||
* @param {TimeConductorBounds} bounds
|
* @param {module:openmct.TimeAPI~TimeConductorBounds} bounds
|
||||||
|
* @fires module:openmct.TimeAPI~timeSystem
|
||||||
|
* @returns {TimeSystem} The currently applied time system
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method setTimeSystem
|
||||||
*/
|
*/
|
||||||
setTimeSystem(timeSystemOrKey, bounds) {
|
setTimeSystem(timeSystemOrKey, bounds) {
|
||||||
if (timeSystemOrKey === undefined) {
|
if (timeSystemOrKey === undefined) {
|
||||||
@ -458,6 +441,7 @@ class TimeContext extends EventEmitter {
|
|||||||
* conductor has changed. A change in Time System will always be
|
* conductor has changed. A change in Time System will always be
|
||||||
* followed by a bounds event specifying new query bounds.
|
* followed by a bounds event specifying new query bounds.
|
||||||
*
|
*
|
||||||
|
* @event module:openmct.TimeAPI~timeSystem
|
||||||
* @property {TimeSystem} The value of the currently applied
|
* @property {TimeSystem} The value of the currently applied
|
||||||
* Time System
|
* Time System
|
||||||
* */
|
* */
|
||||||
@ -472,7 +456,9 @@ class TimeContext extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Get the start and end time of the time conductor. Basic validation
|
* Get the start and end time of the time conductor. Basic validation
|
||||||
* of bounds is performed.
|
* of bounds is performed.
|
||||||
* @returns {TimeConductorBounds} The current bounds of the time conductor.
|
* @returns {module:openmct.TimeAPI~TimeConductorBounds}
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method bounds
|
||||||
*/
|
*/
|
||||||
getBounds() {
|
getBounds() {
|
||||||
//Return a copy to prevent direct mutation of time conductor bounds.
|
//Return a copy to prevent direct mutation of time conductor bounds.
|
||||||
@ -483,8 +469,12 @@ class TimeContext extends EventEmitter {
|
|||||||
* Set the start and end time of the time conductor. Basic validation
|
* Set the start and end time of the time conductor. Basic validation
|
||||||
* of bounds is performed.
|
* of bounds is performed.
|
||||||
*
|
*
|
||||||
* @param {TimeConductorBounds} newBounds The new bounds to set.
|
* @param {module:openmct.TimeAPI~TimeConductorBounds} newBounds
|
||||||
* @throws {Error} Validation error if bounds are invalid
|
* @throws {Error} Validation error
|
||||||
|
* @fires module:openmct.TimeAPI~bounds
|
||||||
|
* @returns {module:openmct.TimeAPI~TimeConductorBounds}
|
||||||
|
* @memberof module:openmct.TimeAPI#
|
||||||
|
* @method bounds
|
||||||
*/
|
*/
|
||||||
setBounds(newBounds) {
|
setBounds(newBounds) {
|
||||||
const validationResult = this.validateBounds(newBounds);
|
const validationResult = this.validateBounds(newBounds);
|
||||||
@ -497,6 +487,7 @@ class TimeContext extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* The start time, end time, or both have been updated.
|
* The start time, end time, or both have been updated.
|
||||||
* @event bounds
|
* @event bounds
|
||||||
|
* @memberof module:openmct.TimeAPI~
|
||||||
* @property {TimeConductorBounds} bounds The newly updated bounds
|
* @property {TimeConductorBounds} bounds The newly updated bounds
|
||||||
* @property {boolean} [tick] `true` if the bounds update was due to
|
* @property {boolean} [tick] `true` if the bounds update was due to
|
||||||
* a "tick" event (i.e. was an automatic update), false otherwise.
|
* a "tick" event (i.e. was an automatic update), false otherwise.
|
||||||
@ -507,7 +498,7 @@ class TimeContext extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the active clock.
|
* Get the active clock.
|
||||||
* @return {Clock|undefined} the currently active clock; undefined if in fixed mode.
|
* @return {Clock} the currently active clock;
|
||||||
*/
|
*/
|
||||||
getClock() {
|
getClock() {
|
||||||
return this.activeClock;
|
return this.activeClock;
|
||||||
@ -518,7 +509,9 @@ class TimeContext extends EventEmitter {
|
|||||||
* and the currently ticking will begin.
|
* and the currently ticking will begin.
|
||||||
* Offsets from 'now', if provided, will be used to set realtime mode offsets
|
* Offsets from 'now', if provided, will be used to set realtime mode offsets
|
||||||
*
|
*
|
||||||
* @param {string|Clock} keyOrClock The clock to activate, or its key
|
* @param {Clock || string} keyOrClock The clock to activate, or its key
|
||||||
|
* @fires module:openmct.TimeAPI~clock
|
||||||
|
* @return {Clock} the currently active clock;
|
||||||
*/
|
*/
|
||||||
setClock(keyOrClock) {
|
setClock(keyOrClock) {
|
||||||
let clock;
|
let clock;
|
||||||
@ -547,7 +540,7 @@ class TimeContext extends EventEmitter {
|
|||||||
* The active clock has changed.
|
* The active clock has changed.
|
||||||
* @event clock
|
* @event clock
|
||||||
* @memberof module:openmct.TimeAPI~
|
* @memberof module:openmct.TimeAPI~
|
||||||
* @property {TimeContext} clock The newly activated clock, or undefined
|
* @property {Clock} clock The newly activated clock, or undefined
|
||||||
* if the system is no longer following a clock source
|
* if the system is no longer following a clock source
|
||||||
*/
|
*/
|
||||||
this.emit(TIME_CONTEXT_EVENTS.clockChanged, this.activeClock);
|
this.emit(TIME_CONTEXT_EVENTS.clockChanged, this.activeClock);
|
||||||
@ -556,7 +549,7 @@ class TimeContext extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current mode.
|
* Get the current mode.
|
||||||
* @return {Mode} the current mode
|
* @return {Mode} the current mode;
|
||||||
*/
|
*/
|
||||||
getMode() {
|
getMode() {
|
||||||
return this.mode;
|
return this.mode;
|
||||||
@ -566,9 +559,9 @@ class TimeContext extends EventEmitter {
|
|||||||
* Set the mode to either fixed or realtime.
|
* Set the mode to either fixed or realtime.
|
||||||
*
|
*
|
||||||
* @param {Mode} mode The mode to activate
|
* @param {Mode} mode The mode to activate
|
||||||
* @param {TimeConductorBounds|ClockOffsets} offsetsOrBounds A time window of a fixed width
|
* @param {TimeBounds | ClockOffsets} offsetsOrBounds A time window of a fixed width
|
||||||
* @fires module:openmct.TimeAPI~clock
|
* @fires module:openmct.TimeAPI~clock
|
||||||
* @return {Mode | undefined} the currently active mode
|
* @return {Mode} the currently active mode;
|
||||||
*/
|
*/
|
||||||
setMode(mode, offsetsOrBounds) {
|
setMode(mode, offsetsOrBounds) {
|
||||||
if (!mode) {
|
if (!mode) {
|
||||||
@ -584,6 +577,7 @@ class TimeContext extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* The active mode has changed.
|
* The active mode has changed.
|
||||||
* @event modeChanged
|
* @event modeChanged
|
||||||
|
* @memberof module:openmct.TimeAPI~
|
||||||
* @property {Mode} mode The newly activated mode
|
* @property {Mode} mode The newly activated mode
|
||||||
*/
|
*/
|
||||||
this.emit(TIME_CONTEXT_EVENTS.modeChanged, this.#copy(this.mode));
|
this.emit(TIME_CONTEXT_EVENTS.modeChanged, this.#copy(this.mode));
|
||||||
@ -616,15 +610,18 @@ class TimeContext extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the currently applied clock offsets.
|
* Get the currently applied clock offsets.
|
||||||
* @returns {ClockOffsets} The current clock offsets.
|
* @returns {ClockOffsets}
|
||||||
*/
|
*/
|
||||||
getClockOffsets() {
|
getClockOffsets() {
|
||||||
return this.offsets;
|
return this.offsets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the currently applied clock offsets.
|
* Set the currently applied clock offsets. If no parameter is provided,
|
||||||
* @param {ClockOffsets} offsets The new clock offsets to set.
|
* the current value will be returned. If provided, the new value will be
|
||||||
|
* used as the new clock offsets.
|
||||||
|
* @param {ClockOffsets} offsets
|
||||||
|
* @returns {ClockOffsets}
|
||||||
*/
|
*/
|
||||||
setClockOffsets(offsets) {
|
setClockOffsets(offsets) {
|
||||||
const validationResult = this.validateOffsets(offsets);
|
const validationResult = this.validateOffsets(offsets);
|
||||||
@ -645,20 +642,13 @@ class TimeContext extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Event that is triggered when clock offsets change.
|
* Event that is triggered when clock offsets change.
|
||||||
* @event clockOffsets
|
* @event clockOffsets
|
||||||
|
* @memberof module:openmct.TimeAPI~
|
||||||
* @property {ClockOffsets} clockOffsets The newly activated clock
|
* @property {ClockOffsets} clockOffsets The newly activated clock
|
||||||
* offsets.
|
* offsets.
|
||||||
*/
|
*/
|
||||||
this.emit(TIME_CONTEXT_EVENTS.clockOffsetsChanged, this.#copy(offsets));
|
this.emit(TIME_CONTEXT_EVENTS.clockOffsetsChanged, this.#copy(offsets));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints a warning to the console when a deprecated method is used. Limits
|
|
||||||
* the number of times a warning is printed per unique method and newMethod
|
|
||||||
* combination.
|
|
||||||
* @param {string} method the deprecated method
|
|
||||||
* @param {string} [newMethod] the new method to use instead
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
#warnMethodDeprecated(method, newMethod) {
|
#warnMethodDeprecated(method, newMethod) {
|
||||||
const MAX_CALLS = 1; // Only warn once per unique method and newMethod combination
|
const MAX_CALLS = 1; // Only warn once per unique method and newMethod combination
|
||||||
|
|
||||||
@ -683,11 +673,6 @@ class TimeContext extends EventEmitter {
|
|||||||
console.warn(message);
|
console.warn(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Deep copy an object.
|
|
||||||
* @param {object} object The object to copy
|
|
||||||
* @returns {object} The copied object
|
|
||||||
*/
|
|
||||||
#copy(object) {
|
#copy(object) {
|
||||||
return JSON.parse(JSON.stringify(object));
|
return JSON.parse(JSON.stringify(object));
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ export default {
|
|||||||
|
|
||||||
this.openmct.time.on('timeSystem', this.updateTimeSystem);
|
this.openmct.time.on('timeSystem', this.updateTimeSystem);
|
||||||
|
|
||||||
this.timestampKey = this.openmct.time.getTimeSystem().key;
|
this.timestampKey = this.openmct.time.timeSystem().key;
|
||||||
|
|
||||||
this.valueMetadata = undefined;
|
this.valueMetadata = undefined;
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
getOptions() {
|
getOptions() {
|
||||||
const { start, end } = this.timeContext.getBounds();
|
const { start, end } = this.timeContext.bounds();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
end,
|
end,
|
||||||
@ -372,13 +372,13 @@ export default {
|
|||||||
this.setTrace(key, telemetryObject.name, axisMetadata, xValues, yValues);
|
this.setTrace(key, telemetryObject.name, axisMetadata, xValues, yValues);
|
||||||
},
|
},
|
||||||
isDataInTimeRange(datum, key, telemetryObject) {
|
isDataInTimeRange(datum, key, telemetryObject) {
|
||||||
const timeSystemKey = this.timeContext.getTimeSystem().key;
|
const timeSystemKey = this.timeContext.timeSystem().key;
|
||||||
const metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
const metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||||
let metadataValue = metadata.value(timeSystemKey) || { key: timeSystemKey };
|
let metadataValue = metadata.value(timeSystemKey) || { key: timeSystemKey };
|
||||||
|
|
||||||
let currentTimestamp = this.parse(key, metadataValue.key, datum);
|
let currentTimestamp = this.parse(key, metadataValue.key, datum);
|
||||||
|
|
||||||
return currentTimestamp && this.timeContext.getBounds().end >= currentTimestamp;
|
return currentTimestamp && this.timeContext.bounds().end >= currentTimestamp;
|
||||||
},
|
},
|
||||||
format(telemetryObjectKey, metadataKey, data) {
|
format(telemetryObjectKey, metadataKey, data) {
|
||||||
const formats = this.telemetryObjectFormats[telemetryObjectKey];
|
const formats = this.telemetryObjectFormats[telemetryObjectKey];
|
||||||
|
@ -306,7 +306,7 @@ export default {
|
|||||||
this.trace = [trace];
|
this.trace = [trace];
|
||||||
},
|
},
|
||||||
getTimestampForDatum(datum, key, telemetryObject) {
|
getTimestampForDatum(datum, key, telemetryObject) {
|
||||||
const timeSystemKey = this.timeContext.getTimeSystem().key;
|
const timeSystemKey = this.timeContext.timeSystem().key;
|
||||||
const metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
const metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||||
let metadataValue = metadata.value(timeSystemKey) || { format: timeSystemKey };
|
let metadataValue = metadata.value(timeSystemKey) || { format: timeSystemKey };
|
||||||
|
|
||||||
@ -327,7 +327,7 @@ export default {
|
|||||||
return formats[metadataKey].parse(datum);
|
return formats[metadataKey].parse(datum);
|
||||||
},
|
},
|
||||||
getOptions() {
|
getOptions() {
|
||||||
const { start, end } = this.timeContext.getBounds();
|
const { start, end } = this.timeContext.bounds();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
end,
|
end,
|
||||||
|
@ -245,7 +245,7 @@ export default class Condition extends EventEmitter {
|
|||||||
latestTimestamp,
|
latestTimestamp,
|
||||||
updatedCriterion.data,
|
updatedCriterion.data,
|
||||||
this.timeSystems,
|
this.timeSystems,
|
||||||
this.openmct.time.getTimeSystem()
|
this.openmct.time.timeSystem()
|
||||||
);
|
);
|
||||||
this.conditionManager.updateCurrentCondition(latestTimestamp);
|
this.conditionManager.updateCurrentCondition(latestTimestamp);
|
||||||
}
|
}
|
||||||
@ -309,7 +309,7 @@ export default class Condition extends EventEmitter {
|
|||||||
latestTimestamp,
|
latestTimestamp,
|
||||||
data,
|
data,
|
||||||
this.timeSystems,
|
this.timeSystems,
|
||||||
this.openmct.time.getTimeSystem()
|
this.openmct.time.timeSystem()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
{},
|
{},
|
||||||
{},
|
{},
|
||||||
this.timeSystems,
|
this.timeSystems,
|
||||||
this.openmct.time.getTimeSystem()
|
this.openmct.time.timeSystem()
|
||||||
);
|
);
|
||||||
this.updateConditionResults({ id: id });
|
this.updateConditionResults({ id: id });
|
||||||
this.updateCurrentCondition(latestTimestamp);
|
this.updateCurrentCondition(latestTimestamp);
|
||||||
@ -383,7 +383,7 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
latestTimestamp,
|
latestTimestamp,
|
||||||
data,
|
data,
|
||||||
this.timeSystems,
|
this.timeSystems,
|
||||||
this.openmct.time.getTimeSystem()
|
this.openmct.time.timeSystem()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
|||||||
return Promise.all(telemetryRequests).then((telemetryRequestsResults) => {
|
return Promise.all(telemetryRequests).then((telemetryRequestsResults) => {
|
||||||
let latestTimestamp;
|
let latestTimestamp;
|
||||||
const timeSystems = this.openmct.time.getAllTimeSystems();
|
const timeSystems = this.openmct.time.getAllTimeSystems();
|
||||||
const timeSystem = this.openmct.time.getTimeSystem();
|
const timeSystem = this.openmct.time.timeSystem();
|
||||||
|
|
||||||
telemetryRequestsResults.forEach((results, index) => {
|
telemetryRequestsResults.forEach((results, index) => {
|
||||||
const latestDatum =
|
const latestDatum =
|
||||||
|
@ -280,7 +280,7 @@ export default {
|
|||||||
await this.$nextTick();
|
await this.$nextTick();
|
||||||
},
|
},
|
||||||
formattedValueForCopy() {
|
formattedValueForCopy() {
|
||||||
const timeFormatterKey = this.openmct.time.getTimeSystem().key;
|
const timeFormatterKey = this.openmct.time.timeSystem().key;
|
||||||
const timeFormatter = this.formats[timeFormatterKey];
|
const timeFormatter = this.formats[timeFormatterKey];
|
||||||
const unit = this.unit ? ` ${this.unit}` : '';
|
const unit = this.unit ? ` ${this.unit}` : '';
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ export default {
|
|||||||
rangeLow: gaugeController.min,
|
rangeLow: gaugeController.min,
|
||||||
gaugeType: gaugeController.gaugeType,
|
gaugeType: gaugeController.gaugeType,
|
||||||
showUnits: gaugeController.showUnits,
|
showUnits: gaugeController.showUnits,
|
||||||
activeTimeSystem: this.openmct.time.getTimeSystem(),
|
activeTimeSystem: this.openmct.time.timeSystem(),
|
||||||
units: ''
|
units: ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -726,7 +726,7 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { start, end } = this.openmct.time.getBounds();
|
const { start, end } = this.openmct.time.bounds();
|
||||||
const parsedValue = this.timeFormatter.parse(this.datum);
|
const parsedValue = this.timeFormatter.parse(this.datum);
|
||||||
|
|
||||||
const beforeStartOfBounds = parsedValue < start;
|
const beforeStartOfBounds = parsedValue < start;
|
||||||
|
@ -49,7 +49,7 @@ export default {
|
|||||||
mixins: [imageryData],
|
mixins: [imageryData],
|
||||||
inject: ['openmct', 'domainObject', 'objectPath'],
|
inject: ['openmct', 'domainObject', 'objectPath'],
|
||||||
data() {
|
data() {
|
||||||
let timeSystem = this.openmct.time.getTimeSystem();
|
let timeSystem = this.openmct.time.timeSystem();
|
||||||
this.metadata = {};
|
this.metadata = {};
|
||||||
this.requestCount = 0;
|
this.requestCount = 0;
|
||||||
|
|
||||||
@ -148,10 +148,10 @@ export default {
|
|||||||
return clientWidth;
|
return clientWidth;
|
||||||
},
|
},
|
||||||
updateViewBounds(bounds, isTick) {
|
updateViewBounds(bounds, isTick) {
|
||||||
this.viewBounds = this.timeContext.getBounds();
|
this.viewBounds = this.timeContext.bounds();
|
||||||
|
|
||||||
if (this.timeSystem === undefined) {
|
if (this.timeSystem === undefined) {
|
||||||
this.timeSystem = this.timeContext.getTimeSystem();
|
this.timeSystem = this.timeContext.timeSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setScaleAndPlotImagery(this.timeSystem, !isTick);
|
this.setScaleAndPlotImagery(this.timeSystem, !isTick);
|
||||||
@ -216,7 +216,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timeSystem === undefined) {
|
if (timeSystem === undefined) {
|
||||||
timeSystem = this.timeContext.getTimeSystem();
|
timeSystem = this.timeContext.timeSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeSystem.isUTCBased) {
|
if (timeSystem.isUTCBased) {
|
||||||
|
@ -44,7 +44,7 @@ export default class RelatedTelemetry {
|
|||||||
this.keys = telemetryKeys;
|
this.keys = telemetryKeys;
|
||||||
|
|
||||||
this._timeFormatter = undefined;
|
this._timeFormatter = undefined;
|
||||||
this._timeSystemChange(this.timeContext.getTimeSystem());
|
this._timeSystemChange(this.timeContext.timeSystem());
|
||||||
|
|
||||||
// grab related telemetry metadata
|
// grab related telemetry metadata
|
||||||
for (let key of this.keys) {
|
for (let key of this.keys) {
|
||||||
@ -110,10 +110,10 @@ export default class RelatedTelemetry {
|
|||||||
// and set bounds.
|
// and set bounds.
|
||||||
ephemeralContext.resetContext();
|
ephemeralContext.resetContext();
|
||||||
const newBounds = {
|
const newBounds = {
|
||||||
start: this.timeContext.getBounds().start,
|
start: this.timeContext.bounds().start,
|
||||||
end: this._parseTime(datum)
|
end: this._parseTime(datum)
|
||||||
};
|
};
|
||||||
ephemeralContext.setBounds(newBounds);
|
ephemeralContext.bounds(newBounds);
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
start: newBounds.start,
|
start: newBounds.start,
|
||||||
|
@ -171,7 +171,7 @@ export default {
|
|||||||
this.bounds = bounds; // setting bounds for ImageryView watcher
|
this.bounds = bounds; // setting bounds for ImageryView watcher
|
||||||
},
|
},
|
||||||
timeSystemChanged() {
|
timeSystemChanged() {
|
||||||
this.timeSystem = this.timeContext.getTimeSystem();
|
this.timeSystem = this.timeContext.timeSystem();
|
||||||
this.timeKey = this.timeSystem.key;
|
this.timeKey = this.timeSystem.key;
|
||||||
this.timeFormatter = this.getFormatter(this.timeKey);
|
this.timeFormatter = this.getFormatter(this.timeKey);
|
||||||
this.durationFormatter = this.getFormatter(
|
this.durationFormatter = this.getFormatter(
|
||||||
|
@ -61,7 +61,7 @@ describe('The local time', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('can be set to be the main time system', () => {
|
it('can be set to be the main time system', () => {
|
||||||
expect(openmct.time.getTimeSystem().key).toBe(LOCAL_SYSTEM_KEY);
|
expect(openmct.time.timeSystem().key).toBe(LOCAL_SYSTEM_KEY);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses the local-format time format', () => {
|
it('uses the local-format time format', () => {
|
||||||
|
@ -680,7 +680,7 @@ export default {
|
|||||||
} else if (domainObjectData) {
|
} else if (domainObjectData) {
|
||||||
// plain domain object
|
// plain domain object
|
||||||
const objectPath = JSON.parse(domainObjectData);
|
const objectPath = JSON.parse(domainObjectData);
|
||||||
const bounds = this.openmct.time.getBounds();
|
const bounds = this.openmct.time.bounds();
|
||||||
const snapshotMeta = {
|
const snapshotMeta = {
|
||||||
bounds,
|
bounds,
|
||||||
link: null,
|
link: null,
|
||||||
|
@ -275,7 +275,7 @@ export default {
|
|||||||
}
|
}
|
||||||
const hash = this.embed.historicLink;
|
const hash = this.embed.historicLink;
|
||||||
|
|
||||||
const bounds = this.openmct.time.getBounds();
|
const bounds = this.openmct.time.bounds();
|
||||||
const isTimeBoundChanged =
|
const isTimeBoundChanged =
|
||||||
this.embed.bounds.start !== bounds.start || this.embed.bounds.end !== bounds.end;
|
this.embed.bounds.start !== bounds.start || this.embed.bounds.end !== bounds.end;
|
||||||
const isFixedTimespanMode = !this.openmct.time.clock();
|
const isFixedTimespanMode = !this.openmct.time.clock();
|
||||||
|
@ -369,7 +369,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async addNewEmbed(objectPath) {
|
async addNewEmbed(objectPath) {
|
||||||
const bounds = this.openmct.time.getBounds();
|
const bounds = this.openmct.time.bounds();
|
||||||
const snapshotMeta = {
|
const snapshotMeta = {
|
||||||
bounds,
|
bounds,
|
||||||
link: null,
|
link: null,
|
||||||
|
@ -123,7 +123,7 @@ export default {
|
|||||||
const objectPath = this.objectPath || this.openmct.router.path;
|
const objectPath = this.objectPath || this.openmct.router.path;
|
||||||
const link = this.isPreview ? this.getPreviewObjectLink() : window.location.hash;
|
const link = this.isPreview ? this.getPreviewObjectLink() : window.location.hash;
|
||||||
const snapshotMeta = {
|
const snapshotMeta = {
|
||||||
bounds: this.openmct.time.getBounds(),
|
bounds: this.openmct.time.bounds(),
|
||||||
link,
|
link,
|
||||||
objectPath,
|
objectPath,
|
||||||
openmct: this.openmct
|
openmct: this.openmct
|
||||||
|
@ -140,7 +140,7 @@ export function createNewImageEmbed(image, openmct, imageName = '') {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const embedMetaData = {
|
const embedMetaData = {
|
||||||
bounds: openmct.time.getBounds(),
|
bounds: openmct.time.bounds(),
|
||||||
link: null,
|
link: null,
|
||||||
objectPath: null,
|
objectPath: null,
|
||||||
openmct,
|
openmct,
|
||||||
|
@ -46,7 +46,7 @@ export default class PainterroInstance {
|
|||||||
this.config.id = this.elementId;
|
this.config.id = this.elementId;
|
||||||
this.config.saveHandler = this.saveHandler.bind(this);
|
this.config.saveHandler = this.saveHandler.bind(this);
|
||||||
|
|
||||||
this.painterro = Painterro(this.config);
|
this.painterro = Painterro.default(this.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
save(callback) {
|
save(callback) {
|
||||||
|
@ -710,7 +710,7 @@ class CouchObjectProvider {
|
|||||||
this.objectQueue[key].pending = true;
|
this.objectQueue[key].pending = true;
|
||||||
const queued = this.objectQueue[key].dequeue();
|
const queued = this.objectQueue[key].dequeue();
|
||||||
let couchDocument = new CouchDocument(key, queued.model);
|
let couchDocument = new CouchDocument(key, queued.model);
|
||||||
|
couchDocument.metadata.created = Date.now();
|
||||||
this.#enqueueForPersistence({
|
this.#enqueueForPersistence({
|
||||||
key,
|
key,
|
||||||
document: couchDocument
|
document: couchDocument
|
||||||
|
@ -196,7 +196,7 @@ export default {
|
|||||||
this.followTimeContext();
|
this.followTimeContext();
|
||||||
},
|
},
|
||||||
followTimeContext() {
|
followTimeContext() {
|
||||||
this.updateViewBounds(this.timeContext.getBounds());
|
this.updateViewBounds(this.timeContext.bounds());
|
||||||
|
|
||||||
this.timeContext.on('timeSystem', this.setScaleAndGenerateActivities);
|
this.timeContext.on('timeSystem', this.setScaleAndGenerateActivities);
|
||||||
this.timeContext.on('bounds', this.updateViewBounds);
|
this.timeContext.on('bounds', this.updateViewBounds);
|
||||||
@ -319,7 +319,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.timeSystem === null) {
|
if (this.timeSystem === null) {
|
||||||
this.timeSystem = this.openmct.time.getTimeSystem();
|
this.timeSystem = this.openmct.time.timeSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setScaleAndGenerateActivities();
|
this.setScaleAndGenerateActivities();
|
||||||
@ -344,7 +344,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!timeSystem) {
|
if (!timeSystem) {
|
||||||
timeSystem = this.openmct.time.getTimeSystem();
|
timeSystem = this.openmct.time.timeSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeSystem.isUTCBased) {
|
if (timeSystem.isUTCBased) {
|
||||||
|
@ -116,7 +116,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
setFormatters() {
|
setFormatters() {
|
||||||
let timeSystem = this.openmct.time.getTimeSystem();
|
let timeSystem = this.openmct.time.timeSystem();
|
||||||
this.timeFormatter = this.openmct.telemetry.getValueFormatter({
|
this.timeFormatter = this.openmct.telemetry.getValueFormatter({
|
||||||
format: timeSystem.timeFormat
|
format: timeSystem.timeFormat
|
||||||
}).formatter;
|
}).formatter;
|
||||||
|
@ -661,7 +661,7 @@ export default {
|
|||||||
this.offsetWidth = this.$parent.$refs.plotWrapper.offsetWidth;
|
this.offsetWidth = this.$parent.$refs.plotWrapper.offsetWidth;
|
||||||
|
|
||||||
this.startLoading();
|
this.startLoading();
|
||||||
const bounds = this.timeContext.getBounds();
|
const bounds = this.timeContext.bounds();
|
||||||
const options = {
|
const options = {
|
||||||
size: this.$parent.$refs.plotWrapper.offsetWidth,
|
size: this.$parent.$refs.plotWrapper.offsetWidth,
|
||||||
domain: this.config.xAxis.get('key'),
|
domain: this.config.xAxis.get('key'),
|
||||||
|
@ -614,7 +614,7 @@ export default {
|
|||||||
const yAxisId = series.get('yAxisId') || mainYAxisId;
|
const yAxisId = series.get('yAxisId') || mainYAxisId;
|
||||||
let offset = this.offset[yAxisId];
|
let offset = this.offset[yAxisId];
|
||||||
|
|
||||||
return new MCTChartAlarmLineSet(series, this, offset, this.openmct.time.getBounds());
|
return new MCTChartAlarmLineSet(series, this, offset, this.openmct.time.bounds());
|
||||||
},
|
},
|
||||||
pointSetForSeries(series) {
|
pointSetForSeries(series) {
|
||||||
const mainYAxisId = this.config.yAxis.get('id');
|
const mainYAxisId = this.config.yAxis.get('id');
|
||||||
|
@ -93,7 +93,7 @@ export default class XAxisModel extends Model {
|
|||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
defaultModel(options) {
|
defaultModel(options) {
|
||||||
const bounds = options.openmct.time.getBounds();
|
const bounds = options.openmct.time.bounds();
|
||||||
const timeSystem = options.openmct.time.getTimeSystem();
|
const timeSystem = options.openmct.time.getTimeSystem();
|
||||||
const format = options.openmct.telemetry.getFormatter(timeSystem.timeFormat);
|
const format = options.openmct.telemetry.getFormatter(timeSystem.timeFormat);
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ export default class RemoteClock extends DefaultClock {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_timeSystemChange() {
|
_timeSystemChange() {
|
||||||
let timeSystem = this.openmct.time.getTimeSystem();
|
let timeSystem = this.openmct.time.timeSystem();
|
||||||
let timeKey = timeSystem.key;
|
let timeKey = timeSystem.key;
|
||||||
let metadataValue = this.metadata.value(timeKey);
|
let metadataValue = this.metadata.value(timeKey);
|
||||||
let timeFormatter = this.openmct.telemetry.getValueFormatter(metadataValue);
|
let timeFormatter = this.openmct.telemetry.getValueFormatter(metadataValue);
|
||||||
@ -149,11 +149,13 @@ export default class RemoteClock extends DefaultClock {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for the clock to have a non-default tick value.
|
* Waits for the clock to have a non-default tick value.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
#waitForReady() {
|
#waitForReady() {
|
||||||
const waitForInitialTick = (resolve) => {
|
const waitForInitialTick = (resolve) => {
|
||||||
if (this.lastTick > 0) {
|
if (this.lastTick > 0) {
|
||||||
const offsets = this.openmct.time.getClockOffsets();
|
const offsets = this.openmct.time.clockOffsets();
|
||||||
resolve({
|
resolve({
|
||||||
start: this.lastTick + offsets.start,
|
start: this.lastTick + offsets.start,
|
||||||
end: this.lastTick + offsets.end
|
end: this.lastTick + offsets.end
|
||||||
|
@ -62,7 +62,7 @@ SummaryWidgetEvaluator.prototype.subscribe = function (callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const updateCallback = function () {
|
const updateCallback = function () {
|
||||||
const datum = this.evaluateState(realtimeStates, this.openmct.time.getTimeSystem().key);
|
const datum = this.evaluateState(realtimeStates, this.openmct.time.timeSystem().key);
|
||||||
if (datum) {
|
if (datum) {
|
||||||
callback(datum);
|
callback(datum);
|
||||||
}
|
}
|
||||||
|
@ -611,11 +611,11 @@ describe('The Mean Telemetry Provider', function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createMockTimeApi() {
|
function createMockTimeApi() {
|
||||||
return jasmine.createSpyObj('timeApi', ['getTimeSystem', 'setTimeSystem']);
|
return jasmine.createSpyObj('timeApi', ['timeSystem']);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTimeSystemTo(timeSystemKey) {
|
function setTimeSystemTo(timeSystemKey) {
|
||||||
mockApi.time.getTimeSystem.and.returnValue({
|
mockApi.time.timeSystem.and.returnValue({
|
||||||
key: timeSystemKey
|
key: timeSystemKey
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ TelemetryAverager.prototype.calculateMean = function () {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
TelemetryAverager.prototype.setDomainKeyAndFormatter = function () {
|
TelemetryAverager.prototype.setDomainKeyAndFormatter = function () {
|
||||||
const domainKey = this.timeAPI.getTimeSystem().key;
|
const domainKey = this.timeAPI.timeSystem().key;
|
||||||
if (domainKey !== this.domainKey) {
|
if (domainKey !== this.domainKey) {
|
||||||
this.domainKey = domainKey;
|
this.domainKey = domainKey;
|
||||||
this.domainFormatter = this.getFormatter(domainKey);
|
this.domainFormatter = this.getFormatter(domainKey);
|
||||||
|
@ -134,7 +134,7 @@ export default class TelemetryTable extends EventEmitter {
|
|||||||
|
|
||||||
//If no persisted sort order, default to sorting by time system, descending.
|
//If no persisted sort order, default to sorting by time system, descending.
|
||||||
sortOptions = sortOptions || {
|
sortOptions = sortOptions || {
|
||||||
key: this.openmct.time.getTimeSystem().key,
|
key: this.openmct.time.timeSystem().key,
|
||||||
direction: 'desc'
|
direction: 'desc'
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -171,10 +171,6 @@ export default class TelemetryTable extends EventEmitter {
|
|||||||
|
|
||||||
this.removeTelemetryCollection(keyString);
|
this.removeTelemetryCollection(keyString);
|
||||||
|
|
||||||
let sortOptions = this.configuration.getConfiguration().sortOptions;
|
|
||||||
requestOptions.order =
|
|
||||||
sortOptions?.direction ?? (this.telemetryMode === 'performance' ? 'desc' : 'asc');
|
|
||||||
|
|
||||||
if (this.telemetryMode === 'performance') {
|
if (this.telemetryMode === 'performance') {
|
||||||
requestOptions.size = this.rowLimit;
|
requestOptions.size = this.rowLimit;
|
||||||
requestOptions.enforceSize = true;
|
requestOptions.enforceSize = true;
|
||||||
|
@ -40,8 +40,6 @@ export default class TelemetryTableConfiguration extends EventEmitter {
|
|||||||
'configuration',
|
'configuration',
|
||||||
this.objectMutated
|
this.objectMutated
|
||||||
);
|
);
|
||||||
|
|
||||||
this.notPersistable = !this.openmct.objects.isPersistable(this.domainObject.identifier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfiguration() {
|
getConfiguration() {
|
||||||
@ -54,19 +52,14 @@ export default class TelemetryTableConfiguration extends EventEmitter {
|
|||||||
// anything that doesn't have a telemetryMode existed before the change and should
|
// anything that doesn't have a telemetryMode existed before the change and should
|
||||||
// take the properties of any passed in defaults or the defaults from the plugin
|
// take the properties of any passed in defaults or the defaults from the plugin
|
||||||
configuration.telemetryMode = configuration.telemetryMode ?? this.defaultOptions.telemetryMode;
|
configuration.telemetryMode = configuration.telemetryMode ?? this.defaultOptions.telemetryMode;
|
||||||
configuration.persistModeChange = this.notPersistable
|
configuration.persistModeChange =
|
||||||
? false
|
configuration.persistModeChange ?? this.defaultOptions.persistModeChange;
|
||||||
: configuration.persistModeChange ?? this.defaultOptions.persistModeChange;
|
|
||||||
configuration.rowLimit = configuration.rowLimit ?? this.defaultOptions.rowLimit;
|
configuration.rowLimit = configuration.rowLimit ?? this.defaultOptions.rowLimit;
|
||||||
|
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateConfiguration(configuration) {
|
updateConfiguration(configuration) {
|
||||||
if (this.notPersistable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.openmct.objects.mutate(this.domainObject, 'configuration', configuration);
|
this.openmct.objects.mutate(this.domainObject, 'configuration', configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +141,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
const bounds = this.openmct.time.getBounds();
|
const bounds = this.openmct.time.getBounds();
|
||||||
const timeSystem = this.openmct.time.getTimeSystem();
|
const timeSystem = this.openmct.time.getTimeSystem();
|
||||||
|
// const isFixed = this.openmct.time.isFixed();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
timeSystem,
|
timeSystem,
|
||||||
|
@ -173,16 +173,16 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
getBoundsForTimeSystem(timeSystem) {
|
getBoundsForTimeSystem(timeSystem) {
|
||||||
const currentBounds = this.timeContext.getBounds();
|
const currentBounds = this.timeContext.bounds();
|
||||||
|
|
||||||
//TODO: Some kind of translation via an offset? of current bounds to target timeSystem
|
//TODO: Some kind of translation via an offset? of current bounds to target timeSystem
|
||||||
return currentBounds;
|
return currentBounds;
|
||||||
},
|
},
|
||||||
updateViewBounds() {
|
updateViewBounds() {
|
||||||
const bounds = this.timeContext.getBounds();
|
const bounds = this.timeContext.bounds();
|
||||||
this.updateContentHeight();
|
this.updateContentHeight();
|
||||||
let currentTimeSystemIndex = this.timeSystems.findIndex(
|
let currentTimeSystemIndex = this.timeSystems.findIndex(
|
||||||
(item) => item.timeSystem.key === this.openmct.time.getTimeSystem().key
|
(item) => item.timeSystem.key === this.openmct.time.timeSystem().key
|
||||||
);
|
);
|
||||||
if (currentTimeSystemIndex > -1) {
|
if (currentTimeSystemIndex > -1) {
|
||||||
let currentTimeSystem = {
|
let currentTimeSystem = {
|
||||||
|
@ -97,7 +97,7 @@ const headerItems = [
|
|||||||
property: 'start',
|
property: 'start',
|
||||||
name: 'Start Time',
|
name: 'Start Time',
|
||||||
format: function (value, object, key, openmct, options = {}) {
|
format: function (value, object, key, openmct, options = {}) {
|
||||||
const timeFormat = openmct.time.getTimeSystem().timeFormat;
|
const timeFormat = openmct.time.timeSystem().timeFormat;
|
||||||
const timeFormatter = openmct.telemetry.getValueFormatter({ format: timeFormat }).formatter;
|
const timeFormatter = openmct.telemetry.getValueFormatter({ format: timeFormat }).formatter;
|
||||||
if (options.skipDateForToday) {
|
if (options.skipDateForToday) {
|
||||||
return timeFormatter.format(value, SAME_DAY_PRECISION_SECONDS);
|
return timeFormatter.format(value, SAME_DAY_PRECISION_SECONDS);
|
||||||
@ -112,7 +112,7 @@ const headerItems = [
|
|||||||
property: 'end',
|
property: 'end',
|
||||||
name: 'End Time',
|
name: 'End Time',
|
||||||
format: function (value, object, key, openmct, options = {}) {
|
format: function (value, object, key, openmct, options = {}) {
|
||||||
const timeFormat = openmct.time.getTimeSystem().timeFormat;
|
const timeFormat = openmct.time.timeSystem().timeFormat;
|
||||||
const timeFormatter = openmct.telemetry.getValueFormatter({ format: timeFormat }).formatter;
|
const timeFormatter = openmct.telemetry.getValueFormatter({ format: timeFormat }).formatter;
|
||||||
if (options.skipDateForToday) {
|
if (options.skipDateForToday) {
|
||||||
return timeFormatter.format(value, SAME_DAY_PRECISION_SECONDS);
|
return timeFormatter.format(value, SAME_DAY_PRECISION_SECONDS);
|
||||||
@ -425,14 +425,14 @@ export default {
|
|||||||
},
|
},
|
||||||
isActivityInBounds(activity) {
|
isActivityInBounds(activity) {
|
||||||
const startInBounds =
|
const startInBounds =
|
||||||
activity.start >= this.timeContext.getBounds()?.start &&
|
activity.start >= this.timeContext.bounds()?.start &&
|
||||||
activity.start <= this.timeContext.getBounds()?.end;
|
activity.start <= this.timeContext.bounds()?.end;
|
||||||
const endInBounds =
|
const endInBounds =
|
||||||
activity.end >= this.timeContext.getBounds()?.start &&
|
activity.end >= this.timeContext.bounds()?.start &&
|
||||||
activity.end <= this.timeContext.getBounds()?.end;
|
activity.end <= this.timeContext.bounds()?.end;
|
||||||
const middleInBounds =
|
const middleInBounds =
|
||||||
activity.start <= this.timeContext.getBounds()?.start &&
|
activity.start <= this.timeContext.bounds()?.start &&
|
||||||
activity.end >= this.timeContext.getBounds()?.end;
|
activity.end >= this.timeContext.bounds()?.end;
|
||||||
|
|
||||||
return startInBounds || endInBounds || middleInBounds;
|
return startInBounds || endInBounds || middleInBounds;
|
||||||
},
|
},
|
||||||
|
@ -33,7 +33,7 @@ $tabletItemH: floor(math.div($gridItemMobile, 3));
|
|||||||
$shellTimeConductorMobileH: 90px;
|
$shellTimeConductorMobileH: 90px;
|
||||||
|
|
||||||
/************************** MOBILE TREE MENU DIMENSIONS */
|
/************************** MOBILE TREE MENU DIMENSIONS */
|
||||||
$mobileTreeItemH: 35px;
|
$mobileTreeItemH: 30px;
|
||||||
$mobileTreeItemIndent: 15px;
|
$mobileTreeItemIndent: 15px;
|
||||||
$mobileTreeRightArrowW: 30px;
|
$mobileTreeRightArrowW: 30px;
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
></button>
|
></button>
|
||||||
</template>
|
</template>
|
||||||
<multipane type="vertical">
|
<multipane type="vertical">
|
||||||
<pane>
|
<pane class="l-pane__browse-tree">
|
||||||
<mct-tree
|
<mct-tree
|
||||||
ref="mctTree"
|
ref="mctTree"
|
||||||
:sync-tree-navigation="triggerSync"
|
:sync-tree-navigation="triggerSync"
|
||||||
@ -107,6 +107,7 @@
|
|||||||
</pane>
|
</pane>
|
||||||
<pane
|
<pane
|
||||||
handle="before"
|
handle="before"
|
||||||
|
class="l-pane__recently-viewed"
|
||||||
label="Recently Viewed"
|
label="Recently Viewed"
|
||||||
:persist-position="true"
|
:persist-position="true"
|
||||||
collapse-type="horizontal"
|
collapse-type="horizontal"
|
||||||
|
@ -26,11 +26,12 @@
|
|||||||
:class="isAlias"
|
:class="isAlias"
|
||||||
:aria-label="`${domainObject.name}`"
|
:aria-label="`${domainObject.name}`"
|
||||||
>
|
>
|
||||||
|
<div class="c-recentobjects-listitem__outerwrapper">
|
||||||
|
<div class="c-recentobjects-listitem__wrapper">
|
||||||
<div
|
<div
|
||||||
class="c-recentobjects-listitem__type-icon recent-object-icon"
|
class="c-recentobjects-listitem__type-icon recent-object-icon"
|
||||||
:class="resultTypeIcon"
|
:class="resultTypeIcon"
|
||||||
></div>
|
></div>
|
||||||
<div class="c-recentobjects-listitem__body">
|
|
||||||
<span
|
<span
|
||||||
ref="recentObjectName"
|
ref="recentObjectName"
|
||||||
class="c-recentobjects-listitem__title"
|
class="c-recentobjects-listitem__title"
|
||||||
@ -43,7 +44,8 @@
|
|||||||
>
|
>
|
||||||
{{ domainObject.name }}
|
{{ domainObject.name }}
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="c-recentobjects-listitem__object-path">
|
||||||
<ObjectPath
|
<ObjectPath
|
||||||
class="c-recentobjects-listitem__object-path"
|
class="c-recentobjects-listitem__object-path"
|
||||||
:read-only="false"
|
:read-only="false"
|
||||||
@ -51,6 +53,7 @@
|
|||||||
:object-path="objectPath"
|
:object-path="objectPath"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="c-recentobjects-listitem__target-button">
|
<div class="c-recentobjects-listitem__target-button">
|
||||||
<button
|
<button
|
||||||
class="c-icon-button icon-target"
|
class="c-icon-button icon-target"
|
||||||
|
@ -134,9 +134,8 @@
|
|||||||
background: linear-gradient(90deg, transparent 70%, rgba(black, 0.2) 99%, rgba(black, 0.3));
|
background: linear-gradient(90deg, transparent 70%, rgba(black, 0.2) 99%, rgba(black, 0.3));
|
||||||
|
|
||||||
.l-pane__header {
|
.l-pane__header {
|
||||||
// Hide all buttons except the collapse button
|
> :not(.l-pane__collapse-button) { // On default, show all the header icons.
|
||||||
> :not(.l-pane__collapse-button) {
|
display: block;
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +147,11 @@
|
|||||||
[class*='collapse-button'] {
|
[class*='collapse-button'] {
|
||||||
right: -8px;
|
right: -8px;
|
||||||
}
|
}
|
||||||
|
.l-pane__header{ // If pane is collapsed, hide all the icons except the collapse button, which gets replaced into the hamburger menu.
|
||||||
|
> :not(.l-pane__collapse-button) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,14 @@
|
|||||||
|
|
||||||
&--vertical {
|
&--vertical {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
body.mobile & {
|
||||||
|
gap: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .l-pane .l-pane__contents {
|
||||||
|
padding-right: $interiorMarginSm; // Fend off scrollbar
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +77,7 @@
|
|||||||
&[class*='--horizontal'] {
|
&[class*='--horizontal'] {
|
||||||
padding-left: $interiorMargin;
|
padding-left: $interiorMargin;
|
||||||
padding-right: $interiorMargin;
|
padding-right: $interiorMargin;
|
||||||
|
|
||||||
&.l-pane--collapsed {
|
&.l-pane--collapsed {
|
||||||
padding-left: 0 !important;
|
padding-left: 0 !important;
|
||||||
padding-right: 0 !important;
|
padding-right: 0 !important;
|
||||||
@ -79,6 +88,9 @@
|
|||||||
padding-top: $interiorMargin;
|
padding-top: $interiorMargin;
|
||||||
padding-bottom: $interiorMargin;
|
padding-bottom: $interiorMargin;
|
||||||
min-height: 30px; // For Recents holder
|
min-height: 30px; // For Recents holder
|
||||||
|
body.mobile & {
|
||||||
|
border-top: 2px solid $colorInteriorBorder; // Adds non-resizable splitter
|
||||||
|
}
|
||||||
|
|
||||||
&.l-pane--collapsed {
|
&.l-pane--collapsed {
|
||||||
padding-top: 0 !important;
|
padding-top: 0 !important;
|
||||||
@ -147,7 +159,6 @@
|
|||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
margin-bottom: $interiorMarginSm; // margin-bottom is needed for Tree and Inspector
|
margin-bottom: $interiorMarginSm; // margin-bottom is needed for Tree and Inspector
|
||||||
margin-right: $interiorMarginSm; // margin-right and margin-left are needed for Recent Objects
|
margin-right: $interiorMarginSm; // margin-right and margin-left are needed for Recent Objects
|
||||||
margin-left: $interiorMarginSm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -195,14 +206,24 @@
|
|||||||
&[class*='--collapsed'] { // For Recent Objects Button
|
&[class*='--collapsed'] { // For Recent Objects Button
|
||||||
&.collapse-horizontal {
|
&.collapse-horizontal {
|
||||||
[class*='expand-button'] {
|
[class*='expand-button'] {
|
||||||
display: block;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-top-right-radius: $controlCr;
|
border-top-right-radius: $controlCr;
|
||||||
border-top-left-radius: $controlCr;
|
border-top-left-radius: $controlCr;
|
||||||
|
border-bottom-right-radius: $controlCr;
|
||||||
|
border-bottom-left-radius: $controlCr;
|
||||||
|
padding: $interiorMarginSm $interiorMargin;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
font-size: 0.7em;
|
||||||
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[class*='expand-button'] {
|
[class*='expand-button'] {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -328,6 +349,8 @@
|
|||||||
$m: $interiorMarginLg;
|
$m: $interiorMarginLg;
|
||||||
margin-top: $m;
|
margin-top: $m;
|
||||||
padding-top: $m;
|
padding-top: $m;
|
||||||
|
padding-bottom: 0;
|
||||||
|
|
||||||
> .l-pane__handle {
|
> .l-pane__handle {
|
||||||
top: 0;
|
top: 0;
|
||||||
transform: translateY(floor(math.div($splitterHandleD, -1)));
|
transform: translateY(floor(math.div($splitterHandleD, -1)));
|
||||||
@ -359,5 +382,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // Ends .body.desktop
|
}
|
||||||
} // Ends .l-pane
|
|
||||||
|
// Ends .body.desktop
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ends .l-pane
|
||||||
|
|
||||||
|
body.mobile {
|
||||||
|
.l-pane__header {
|
||||||
|
> * {
|
||||||
|
@include ellipsize();
|
||||||
|
@include userSelectNone();
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-pane__label {
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-pane__recently-viewed {
|
||||||
|
height: 50% !important;
|
||||||
|
max-height: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,12 +43,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__outerwrapper{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__wrapper{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
&__object-path {
|
&__object-path {
|
||||||
padding: 0 $interiorMarginSm;
|
padding: 0 $interiorMarginLg;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__target-button {
|
&__target-button {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__type-icon,
|
&__type-icon,
|
||||||
@ -59,6 +70,11 @@
|
|||||||
&__type-icon {
|
&__type-icon {
|
||||||
color: $colorItemTreeIcon;
|
color: $colorItemTreeIcon;
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
|
height: 100%; // When pane is small, this avoids the alias icons from wrapping down
|
||||||
|
min-width: $treeTypeIconW;
|
||||||
|
body.mobile &{
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
// TEMP: uses object-label component, hide label part
|
// TEMP: uses object-label component, hide label part
|
||||||
.c-object-label__name {
|
.c-object-label__name {
|
||||||
@ -102,7 +118,8 @@
|
|||||||
border-radius: $basicCr;
|
border-radius: $basicCr;
|
||||||
color: $colorItemTreeFg;
|
color: $colorItemTreeFg;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: $interiorMarginSm;
|
padding: 2px $interiorMarginSm;
|
||||||
|
margin-left: $interiorMarginSm;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $colorItemTreeHoverBg;
|
background-color: $colorItemTreeHoverBg;
|
||||||
@ -117,3 +134,22 @@
|
|||||||
.c-recentobjects-listitem:hover .c-recentobjects-listitem__target-button {
|
.c-recentobjects-listitem:hover .c-recentobjects-listitem__target-button {
|
||||||
opacity: 100;
|
opacity: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.mobile {
|
||||||
|
.c-recentobjects-listitem__target-button{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.c-recentobjects-listitem__wrapper{
|
||||||
|
height: $mobileTreeItemH;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: $interiorMarginSm;
|
||||||
|
background: rgba(172, 172, 172, 0.1);
|
||||||
|
border-radius: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
.c-recentobjects-listitem{
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
.c-recentobjects-listitem__type-icon{
|
||||||
|
margin-left: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ export default class StalenessUtils {
|
|||||||
|
|
||||||
shouldUpdateStaleness(stalenessResponse, id) {
|
shouldUpdateStaleness(stalenessResponse, id) {
|
||||||
const stalenessResponseTime = this.parseTime(stalenessResponse);
|
const stalenessResponseTime = this.parseTime(stalenessResponse);
|
||||||
const { start } = this.openmct.time.getBounds();
|
const { start } = this.openmct.time.bounds();
|
||||||
const isStalenessInCurrentClock = stalenessResponseTime > start;
|
const isStalenessInCurrentClock = stalenessResponseTime > start;
|
||||||
|
|
||||||
if (stalenessResponseTime > this.lastStalenessResponseTime && isStalenessInCurrentClock) {
|
if (stalenessResponseTime > this.lastStalenessResponseTime && isStalenessInCurrentClock) {
|
||||||
|
@ -16,22 +16,14 @@
|
|||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"outFile": "dist/types/index.d.ts",
|
"outDir": "dist",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"target": "ES2015",
|
"target": "ES2015",
|
||||||
"paths": {
|
"paths": {
|
||||||
// matches the alias in webpack config, so that types for those imports are visible.
|
// matches the alias in webpack config, so that types for those imports are visible.
|
||||||
"@/*": [
|
"@/*": ["src/*"]
|
||||||
"src/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src/api/**/*.js"],
|
||||||
"src/api/**/*.js"
|
"exclude": ["node_modules", "dist", "**/*Spec.js"]
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
"dist",
|
|
||||||
"**/*Spec.js"
|
|
||||||
]
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user