diff --git a/.webpack/webpack.common.js b/.webpack/webpack.common.js index 925fcee4..551370c7 100644 --- a/.webpack/webpack.common.js +++ b/.webpack/webpack.common.js @@ -1,32 +1,37 @@ -const path = require('path'); -const packageDefinition = require('../package.json'); -const webpack = require('webpack'); -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +import { execSync } from 'node:child_process'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; +import pkg from '../package.json' with { type: 'json' }; -const { VueLoaderPlugin } = require('vue-loader'); +import webpack from 'webpack'; +import MiniCssExtractPlugin from 'mini-css-extract-plugin'; + +import { VueLoaderPlugin } from 'vue-loader'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); let gitRevision = 'error-retrieving-revision'; let gitBranch = 'error-retrieving-branch'; try { - gitRevision = require('child_process').execSync('git rev-parse HEAD').toString().trim(); - gitBranch = require('child_process') - .execSync('git rev-parse --abbrev-ref HEAD') - .toString() - .trim(); + gitRevision = execSync('git rev-parse HEAD').toString().trim(); + gitBranch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim(); } catch (err) { console.warn('Error retreiving git info', err); } /** @type {import('webpack').Configuration} */ const config = { - context: path.join(__dirname, '..'), + context: join(__dirname, '..'), entry: { - 'openmct-mcws': './loader.js' + 'openmct-mcws-plugin': './plugin.js', + 'legacy-index': './legacy-index.js' + }, + experiments: { + outputModule: true, // Enables the feature }, output: { library: { - name: 'openmctMCWS', - type: 'umd' + type: 'module' }, filename: '[name].js', hashFunction: 'xxhash64', @@ -38,54 +43,54 @@ const config = { * Open MCT Source Paths * TODO FIXME these rely on openmct core source paths becase we extend core code directly */ - '@': path.join(__dirname, '..', 'node_modules/openmct/src'), - objectUtils: path.join( + '@': join(__dirname, '..', 'node_modules/openmct/src'), + objectUtils: join( __dirname, '..', 'node_modules/openmct/src/api/objects/object-utils.js' ), - utils: path.join(__dirname, '..', 'node_modules/openmct/src/utils'), - 'openmct.views.FolderGridViewComponent': path.join( + utils: join(__dirname, '..', 'node_modules/openmct/src/utils'), + 'openmct.views.FolderGridViewComponent': join( __dirname, '..', 'node_modules/openmct/src/plugins/folderView/components/GridView.vue' ), - 'openmct.views.FolderListViewComponent': path.join( + 'openmct.views.FolderListViewComponent': join( __dirname, '..', 'node_modules/openmct/src/plugins/folderView/components/ListView.vue' ), - 'openmct.tables.TelemetryTable': path.join( + 'openmct.tables.TelemetryTable': join( __dirname, '..', 'node_modules/openmct/src/plugins/telemetryTable/TelemetryTable.js' ), - 'openmct.tables.TelemetryTableColumn': path.join( + 'openmct.tables.TelemetryTableColumn': join( __dirname, '..', 'node_modules/openmct/src/plugins/telemetryTable/TelemetryTableColumn.js' ), - 'openmct.tables.TelemetryTableRow': path.join( + 'openmct.tables.TelemetryTableRow': join( __dirname, '..', 'node_modules/openmct/src/plugins/telemetryTable/TelemetryTableRow.js' ), - 'openmct.tables.TelemetryTableConfiguration': path.join( + 'openmct.tables.TelemetryTableConfiguration': join( __dirname, '..', 'node_modules/openmct/src/plugins/telemetryTable/TelemetryTableConfiguration.js' ), - 'openmct.tables.collections.TableRowCollection': path.join( + 'openmct.tables.collections.TableRowCollection': join( __dirname, '..', 'node_modules/openmct/src/plugins/telemetryTable/collections/TableRowCollection.js' ), - 'openmct.tables.components.Table': path.join( + 'openmct.tables.components.Table': join( __dirname, '..', 'node_modules/openmct/src/plugins/telemetryTable/components/TableComponent.vue' ), - 'openmct.tables.components.TableConfiguration': path.join( + 'openmct.tables.components.TableConfiguration': join( __dirname, '..', 'node_modules/openmct/src/plugins/telemetryTable/components/TableConfiguration.vue' @@ -93,24 +98,24 @@ const config = { /** * Globals **/ - openmct: path.join(__dirname, '..', 'node_modules/openmct/dist/openmct.js'), + openmct: join(__dirname, '..', 'node_modules/openmct/dist/openmct.js'), saveAs: 'file-saver/src/FileSaver.js', bourbon: 'bourbon.scss', - printj: path.join(__dirname, '..', 'node_modules/printj/dist/printj.min.js'), + printj: join(__dirname, '..', 'node_modules/printj/dist/printj.min.js'), /** * OMM Paths **/ - types: path.join(__dirname, '..', 'src/types'), - services: path.join(__dirname, '..', 'src/services'), - lib: path.join(__dirname, '..', 'src/lib'), - tables: path.join(__dirname, '..', 'src/tables'), - ommUtils: path.join(__dirname, '..', 'src/utils'), + types: join(__dirname, '..', 'src/types'), + services: join(__dirname, '..', 'src/services'), + lib: join(__dirname, '..', 'src/lib'), + tables: join(__dirname, '..', 'src/tables'), + ommUtils: join(__dirname, '..', 'src/utils'), vue: 'vue/dist/vue.esm-bundler.js' } }, plugins: [ new webpack.DefinePlugin({ - __OMM_VERSION__: `'${packageDefinition.version}'`, + __OMM_VERSION__: `'${pkg.version}'`, __OMM_BUILD_DATE__: `'${new Date()}'`, __OMM_REVISION__: `'${gitRevision}'`, __OMM_BUILD_BRANCH__: `'${gitBranch}'`, @@ -182,4 +187,4 @@ const config = { stats: 'errors-warnings' }; -module.exports = config; +export default config; diff --git a/.webpack/webpack.dev.js b/.webpack/webpack.dev.js index 82aa5e33..1bfce10a 100644 --- a/.webpack/webpack.dev.js +++ b/.webpack/webpack.dev.js @@ -2,10 +2,13 @@ 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. */ -const CopyWebpackPlugin = require('copy-webpack-plugin'); -const { merge } = require('webpack-merge'); -const common = require('./webpack.common'); -const path = require('path'); +import CopyWebpackPlugin from 'copy-webpack-plugin'; +import { merge } from 'webpack-merge'; +import common from './webpack.common.js'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; +const __dirname = dirname(fileURLToPath(import.meta.url)); const proxyUrl = process.env.PROXY_URL || 'http://localhost:8080'; const apiUrl = process.env.API_URL ?? ''; @@ -14,10 +17,10 @@ if (process.env.COOKIE) { proxyHeaders.Cookie = process.env.COOKIE; } -module.exports = merge(common, { +export default merge(common, { mode: 'development', entry: { - config: './config.js' + 'legacy-index': './legacy-index.js' }, plugins: [ new CopyWebpackPlugin({ @@ -29,7 +32,8 @@ module.exports = merge(common, { return content.toString().replace(/"dist\//g, '"'); } }, - { from: './ExampleVenueDefinitions.json', to: 'ExampleVenueDefinitions.json' } + { from: './ExampleVenueDefinitions.json', to: 'ExampleVenueDefinitions.json' }, + { from: './config.js', to: 'config.js' } ] }) ], @@ -61,6 +65,11 @@ module.exports = merge(common, { publicPath: '/node_modules/openmct/dist', watch: false }, + { + directory: path.join(__dirname, '..', 'dist'), + publicPath: '/node_modules/openmct-mcws-plugin/dist', + watch: false + }, { directory: path.join(__dirname, '..', 'test_data'), publicPath: '/test_data', diff --git a/.webpack/webpack.prod.js b/.webpack/webpack.prod.js index 9a2e87ff..ff726ea1 100644 --- a/.webpack/webpack.prod.js +++ b/.webpack/webpack.prod.js @@ -3,10 +3,10 @@ This configuration should be used for production installs. It is the default webpack configuration. */ -const { merge } = require('webpack-merge'); -const common = require('./webpack.common'); +import { merge } from 'webpack-merge'; +import common from './webpack.common.js'; /** @type {import('webpack').Configuration} */ -module.exports = merge(common, { +export default merge(common, { mode: 'production' }); diff --git a/CONFIGURATION.md b/CONFIGURATION.md new file mode 100644 index 00000000..fc3e8e13 --- /dev/null +++ b/CONFIGURATION.md @@ -0,0 +1,359 @@ +# Plugin Options Recipe Example +When including the Open MCT for MCWS Plugin into your Open MCT project, the following are available configuration options. +```yaml +- openmct-mcws-plugin: + npmPackage: NASA-AMMOS/openmct-mcws#omm-plugin + options: + camUrl: '' + mcwsUrl: http://localhost:8090/mcws-test + namespaces: + - key: 'r50-dev' + name: 'R5.0 Shared' + url: '' + - userNamespace: true + key: 'r50-dev' + name: 'R5.0 Users' + url: '' + theme: 'Snow' + venueAware: + enabled: false + venues: 'ExampleVenueDefinitions.json' + taxonomy: + evrDefaultBackgroundColor: null + evrDefaultForegroundColor: null + evrBackgroundColorByLevel: + FATAL: '#ff0000' + WARNING_HI: '#ff7f24' + WARNING_LO: '#ffff00' + COMMAND: '#00bfff' + ACTIVITY_HI: '#6d6d6d' + ACTIVITY_LO: '#dcdcdc' + DIAGNOSTIC: '#00ff00' + EVR_UNKNOWN: '#00ff00' + FAULT: '#ff0000' + WARNING: '#ff7f24' + evrForegroundColorByLevel: + FATAL: '#ffffff' + WARNING_HI: '#000000' + WARNING_LO: '#000000' + COMMAND: '#ffffff' + ACTIVITY_HI: '#ffffff' + ACTIVITY_LO: '#000000' + DIAGNOSTIC: '#000000' + EVR_UNKNOWN: '#000000' + FAULT: '#ffffff' + WARNING: '#000000' + time: + defaultMode: 'fixed' + utcFormat: 'utc.day-of-year' + lmstEpoch: null + subscriptionMCWSFilterDelay: 100 + timeSystems: ['scet', 'ert'] + allowRealtime: true + allowLAD: true + records: 10 + maxResults: 10000 + sessionHistoricalMaxResults: 100 + batchHistoricalChannelQueries: false + disableSortParam: false + messageStreamUrl: '' + messageTypeFilters: [] + frameAccountabilityExpectedVcidList: [] + queryTimespanLimit: null + globalStalenessInterval: null + customFormatters: [] + sessions: + historicalSessionFilter: + disable: false + maxRecords: 100 + denyUnfilteredQueries: false + realtimeSession: + disable: false + globalFilters: [] + tablePerformanceOptions: + telemetryMode: 'unlimited' + persistModeChange: false + rowLimit: 50 + useDeveloperStorage: true + proxyUrl: 'http://localhost:8080/' + assetPath: 'node_modules/openmct/dist' +``` + +# Configuration Guide + +## Required Options + +#### `camUrl` +- **Type**: `string` +- **Required**: Yes +- **Description**: URL to the CAM server this instance uses for authentication. + +#### `mcwsUrl` +- **Type**: `string` +- **Required**: Yes +- **Description**: URL for MCWS root. + +#### `namespaces` +- **Type**: `array` +- **Required**: Yes +- **Description**: Each entry adds a root folder to the object tree. + +**Namespace Properties:** +- `key` (string, required): Unique key for this namespace. +- `name` (string, required): User-visible name for this namespace. +- `url` (string, required): URL to MCWS namespace which will store the contents of the namespace. +- `userNamespace` (boolean, optional, defaults to `false`): If `true`, this namespace will be used to create per-user folders. + + +## Basic Configuration + +### Theme + +#### `theme` +- **Type**: `string` +- **Default**: `'Snow'` +- **Options**: `'Snow'`, `'Espresso'`, or `'Maelstrom'` +- **Description**: Sets the theme for the Open MCT interface. + +### Venue Aware Configuration + +#### `venueAware` +- **Type**: `object` +- **Added in**: R4.0 +- **Description**: Options here enable venue aware mode and allow configuration of venue aware mode. Venue aware configuration allows pre-configuration with a list of venues and datasets such that users are prompted to select either an active venue or a historical session that they'd like to review. Enabling venue-aware mode disables manual creation of datasets. + +**Properties:** +- `enabled` (boolean): Enable or disable venue aware mode. Options: `true`, `false`. +- `venues` (string or array): Either a list of venue definitions or a URL for a JSON venue definition file. If a URL is provided, it will be queried at run time to determine the venues available. An example of a JSON venue definition file is provided in "ExampleVenueDefinitions.json". + +### Taxonomy Configuration + +#### `taxonomy` +- **Type**: `object` +- **Description**: Options here affect how various telemetry types are displayed. + +**Properties:** +- `evrDefaultBackgroundColor` (string or `null`): Default background color for EVRs. Set to `null` to use the theme default. Otherwise, specify a hex string for an RGB color, e.g. `#ababab`. +- `evrDefaultForegroundColor` (string or `null`): Default foreground color for EVRs. Set to `null` to use the theme default. Otherwise, specify a hex string for an RGB color, e.g. `#ababab`. +- `evrBackgroundColorByLevel` (object): Specify the background color of EVRs by level. If a level is not defined here, it will use the default specified above. Keys are specific EVR levels, and values must be a hex string for an RGB color, e.g. `#ababab`. + - Supported levels (FSW Specific): `FATAL`, `WARNING_HI`, `WARNING_LO`, `COMMAND`, `ACTIVITY_HI`, `ACTIVITY_LO`, `DIAGNOSTIC`, `EVR_UNKNOWN` + - Supported levels (SSE Specific): `FAULT`, `WARNING` +- `evrForegroundColorByLevel` (object): Specify the foreground color of EVRs by level. If a level is not defined here, it will use the default specified above. Keys are specific EVR levels, and values must be a hex string for an RGB color, e.g. `#ababab`. + - Supported levels (FSW Specific): `FATAL`, `WARNING_HI`, `WARNING_LO`, `COMMAND`, `ACTIVITY_HI`, `ACTIVITY_LO`, `DIAGNOSTIC`, `EVR_UNKNOWN` + - Supported levels (SSE Specific): `FAULT`, `WARNING` + +### Time Configuration + +#### `time` +- **Type**: `object` +- **Description**: Settings for time APIs and formats. + +**Properties:** +- `defaultMode` (string): Default conductor mode. Available options: + - `'fixed'`: Fixed time bounds. + - `'utc.local'`: Follow local UTC clock. Only available when `allowRealtime` is `true` and `scet` or `ert` timeSystems are available. + - `'scet.lad'`: Follow latest scet seen in telemetry data. Only available when `allowLAD` is `true` and `scet` timeSystem is enabled. + - `'ert.lad'`: Follow latest ert seen in telemetry data. Only available when `allowLAD` is `true` and `ert` timeSystem is enabled. + - `'sclk.lad'`: Follow latest sclk seen in telemetry data. Only available when `allowLAD` is `true` and `sclk` timeSystem is enabled. + - `'msl.sol.lad'`: Follow latest mslsol seen in telemetry data. Only available when `allowLAD` is `true` and `mslsol` timeSystem is enabled. +- `utcFormat` (string): Available options: + - `'utc.day-of-year'`: Format as `2015-015T12:34:56.999` + - `'utc'`: Format as `2015-01-15T12:34:56.999` +- `lmstEpoch` (number or `null`): Epoch date for LMST Time System. It has to be a Date.UTC instance, e.g. `Date.UTC(2020, 2, 18, 0, 0, 0)`. Note: In YAML, this would need to be converted to a timestamp number. +- `subscriptionMCWSFilterDelay` (number): Delay in milliseconds for combining filters for the same subscription endpoint connection. Smaller value = quicker display of realtime data (e.g., 10ms in a low latency environment). Higher value = avoids potentially creating and subsequently tearing down new websocket connections if filter changes are happening faster than server response times (e.g., 100ms+ in a high latency environment). +- `timeSystems` (array or array of objects): Specify the time systems to use. Options are `'scet'`, `'ert'`, `'sclk'`, `'msl.sol'` and `'lmst'`. + + **Basic Configuration**: Simple array of time system keys, e.g. `['scet', 'ert']`. + + **Advanced Configuration**: Array of objects with timeSystem-specific configurations: + - `key` (string, required): Time system. Options are `'scet'`, `'ert'`, `'sclk'`, `'msl.sol'` and `'lmst'`. + - `limit` (number, optional): Maximum duration between start and end bounds allowed (in milliseconds). + - `modeSettings` (object, optional): Presets for convenience. + - `fixed` (object, optional): Valid objects are `bounds` objects and `presets` array. + - `bounds` (object, optional): Start and end bounds for preset as numbers. `start` and `end` can be declared as a number or a function returning a number. + - `presets` (array, optional): Array of objects consisting of: + - `bounds` (object, required): Start and end bounds. + - `label` (string, required): Label for the preset. + - `realtime` (object, optional): Valid objects are `clockOffsets` and `presets` array. + - `clockOffsets` (object, optional): Start and end relative to active clock. `start` and `end` are numbers relative to active clock's 0. Start is negative, end is positive. + - `presets` (array, optional): Array of preset objects with `bounds` and `label`. + - `lad` (object, optional): Valid objects are `clockOffsets`. + - `clockOffsets` (object, optional): Start and end relative to active clock. `start` and `end` are numbers relative to active clock's 0. Start is negative, end is positive. +- `allowRealtime` (boolean): Whether or not to allow UTC-relative time conductor. +- `allowLAD` (boolean): Whether or not to allow latest data relative time conductor. **Note**: `allowRealtime` must be `true` to use this option. +- `records` (number): Number of previous bounds per timeSystem to save in time conductor history. + +### Query Configuration + +#### `maxResults` +- **Type**: `number` +- **Optional**: Yes +- **Description**: A maximum results limit for historical queries. + +#### `sessionHistoricalMaxResults` +- **Type**: `number` +- **Default**: `100` +- **Description**: A maximum results limit for historical session queries. + +#### `batchHistoricalChannelQueries` +- **Type**: `boolean` +- **Default**: `false` +- **Description**: Set to `true` to batch channel historical queries in telemetry tables. +- **Warning**: **USE WITH CAUTION** - You can more easily overwhelm the backend with a larger single query. + +#### `disableSortParam` +- **Type**: `boolean` +- **Default**: `false` +- **Description**: Enable to not send sort param in historical queries. Only set this configuration to `true` if you are certain you wish to disable backend sort. + +#### `queryTimespanLimit` +- **Type**: `number` or `null` +- **Default**: `null` +- **Description**: Use to warn the user and block historical query when the ert, scet or lmst based time-conductor timespan exceeds set limits. Units are in milliseconds. When set to `null`, user will not be warned and queries will not be blocked. + +### Message and Frame Configuration + +#### `messageStreamUrl` +- **Type**: `string` +- **Default**: `''` +- **Description**: URL used to listen to message stream for StartOfSession and EndOfSession messages. + +#### `messageTypeFilters` +- **Type**: `array` +- **Default**: `[]` +- **Description**: Use to set mission specific filters on messages by message type. + +**Filter Object Properties:** +- `value` (string): Message type code value. +- `label` (string): User-visible label for identifying this filter option. + +**Example:** +messageTypeFilters: + - value: 'LossOfSync' + label: 'Loss of Sync' + - value: 'InSync' + label: 'In Sync' + +#### `frameAccountabilityExpectedVcidList` +- **Type**: `array` +- **Default**: `[]` +- **Description**: Use to set up expected VCID's in the frame event stream. Frame Accountability View will highlight the unexpected VC's in orange. + +**Example:** +frameAccountabilityExpectedVcidList: + - 234223 + - 234234 + - 223423 + +### Staleness Configuration + +#### `globalStalenessInterval` +- **Type**: `number` or `null` +- **Default**: `null` +- **Description**: Time since last received realtime datum. Any datum that is received after the set timespan will have a stale (`isStale`) property set. Units are in milliseconds. When set to `null`, there will be no global staleness timespan set. + +### Custom Formatters + +#### `customFormatters` +- **Type**: `array` +- **Default**: `[]` +- **Description**: Register custom formatters for use in Telemetry View in Display Layout's. Custom Formatters need to be an object with a unique String `key` property and a `format` function that accepts a value and returns formatted value. Custom formatters can be accessed in Display Layout's format inspector view, with a pre-pended `&`, e.g. the `'hello-world'` formatter can be accessed by `&hello-world`. + +**Note**: In YAML, functions cannot be directly represented. You would need to define these in JavaScript code that processes the YAML configuration. + +**Example Structure:** +customFormatters: + - key: 'hello-world' + # format function would need to be defined in JavaScript + +### Session Configuration + +#### `sessions` +- **Type**: `object` +- **Description**: Use to set deployment specific session configuration. + +**Properties:** +- `historicalSessionFilter` (object): Configuration for historical session filtering. + - `disable` (boolean): To disable historical session filtering. + - `maxRecords` (number): A number greater than 0, for maximum historical session records to be returned. + - `denyUnfilteredQueries` (boolean): Whether to deny unfiltered queries. +- `realtimeSession` (object): Configuration for realtime sessions. + - `disable` (boolean): To disable realtime sessions. **Note**: This will disable all websocket connections. + +### Global Filters + +#### `globalFilters` +- **Type**: `array` +- **Optional**: Yes +- **Description**: Enable global filters for ALL telemetry requests that support the filter. Telemetry filters modify the `filter` field in queries to MCWS. + +**How to use:** +The global filters will be available from the Global Filters indicator. Enable a filter by selecting the desired filter from the dropdown and hitting update. Outgoing requests that use the `filter` parameter to MCWS will be modified with your filter. For example, selecting 'A side' will ensure that the filter parameter in MCWS includes: `vcid='1,2,3'`. Note that poorly formatted filters may not pass MCWS API validation. + +**Filter Object Properties:** +- `key` (string, required): Filter column, e.g. `vcid`. +- `name` (string, required): Identifier of the filter in the selection window. +- `icon` (string, optional): Icon identifier, e.g. `'icon-flag'`. Not implemented - potentially icon for minimized filter list. +- `filter` (object, required): Filter object to implement. + - `comparator` (string, required): Currently supports `'equals'`. + - `singleSelectionThreshold` (boolean, required): Currently supports `true` only. + - `defaultLabel` (string, optional): Defaults to `'None'`. Label to show if filter inactive. + - `possibleValues` (array, required): List of values and labels for filter. + - `label` (string, required): Label to show in filter selection dropdown. + - `value` (string, required): Value to set parameter to in filtered query. + +**Example:** +globalFilters: + - name: 'VCID' + key: 'vcid' + icon: 'icon-flag' + filter: + comparator: 'equals' + singleSelectionThreshold: true + defaultLabel: "A & B" + possibleValues: + - label: 'A Side' + value: '1,2,3' + - label: 'B Side' + value: '4,5,6' + - name: 'Realtime' + key: 'realtime' + filter: + comparator: 'equals' + singleSelectionThreshold: true + defaultLabel: "REC & RLT" + possibleValues: + - label: 'Realtime' + value: true + - label: 'Recorded' + value: false + +### Telemetry Table Performance Configuration + +#### `tablePerformanceOptions` +- **Type**: `object` +- **Description**: Table Performance Mode Configuration. Can increase performance by limiting the maximum rows retained and displayed by tables. Affects all bounded table types such as Telemetry and EVR tables. Does not affect latest available tables such as Channel tables. + +**Properties:** +- `telemetryMode` (string): Performance mode limits the maximum table rows. Options: `'performance'`, `'unlimited'`. +- `persistModeChange` (boolean): Whether changes in the UI are persisted with the table. +- `rowLimit` (number): The maximum number of rows in performance mode. + +### Developer Settings + +**Warning**: Do not modify these unless you know what they do! + +#### `proxyUrl` +- **Type**: `string` +- **Default**: `'http://localhost:8080/'` +- **Description**: Developer setting for proxy URL. + +#### `useDeveloperStorage` +- **Type**: `boolean` +- **Default**: `true` +- **Description**: Developer setting - enables developer storage mode. Do not modify unless you know what it does. + +#### `assetPath` +- **Type**: `string` +- **Default**: `'node_modules/openmct/dist'` +- **Description**: Developer setting for asset path. diff --git a/README.md b/README.md index e270fdf7..c531bf69 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,22 @@ -# Open MCT for MCWS -Open Mission Control Technologies for Mission Control Web Services (Open MCT for MCWS) is a next-generation web-based mission control framework for visualization of data on desktop and mobile devices. Open MCT for MCWS is built on the [Open MCT Framework](https://github.com/nasa/openmct), and includes adapter code for using MCWS as a telemetry and persistence provider. Open MCT is developed at NASA Ames Research Center in Silicon Valley, in collaboration with NASA AMMOS and the Jet Propulsion Laboratory, California Institute of Technology (under its contract with NASA, 80NM0018D0004). +# Open MCT for MCWS Plugin +Open Mission Control Technologies for Mission Control Web Services Plugin (Open MCT for MCWS) is used with Open MCT, a next-generation web-based mission control framework for visualization of data on desktop and mobile devices. Open MCT for MCWS Plugin is built for the [Open MCT Framework](https://github.com/nasa/openmct), and includes adapter code for using MCWS as a telemetry and persistence provider. Open MCT is developed at NASA Ames Research Center in Silicon Valley, in collaboration with NASA AMMOS and the Jet Propulsion Laboratory, California Institute of Technology (under its contract with NASA, 80NM0018D0004). ## Configuration -Various configurations and customizations are available by editing `config.js`. Descriptions of each configuration reside with the configuration in the file. +Various configurations and customizations are available by editing `recipes/default.yaml`. +Development configurations and customizations are available by editing `recipes/development.yaml`. ### AMMOS configurations 1. `camUrl`: The url to the CAM server, if CAM is to be used for authentication. 2. `mcwsUrl`: The url to the MCWS server. 3. In the `namespaces` configuration, `url`, the path to the MCWS persistence spaces, are required. +Further configuration documentation can be found in the `CONFIGURATION.md`. + ## Development +### Prerequisite +You will need to install the [Open MCT Configurator](https://github.com/akhenry/openmct-configurator) + ### 1. Install Open MCT for MCWS In a terminal, run this command to install Open MCT for MCWS and its dependencies. This may take a few minutes. @@ -20,24 +26,19 @@ If you've installed Open MCT for MCWS locally before, first run this command. npm run clean -### 2. Modify config.js -Uncomment the `proxyUrl` setting in `config.js`. It is located under Developer -Settings near the end of the file. - -### 3. Run Open MCT for MCWS locally +### 2. Modify development.yaml +If necessary, make any modifications to `development.yaml`, such as adding Open MCT core plugins or modifying settings for the Openmct for MCWS Plugin - npm start +### 3. Build Open MCT with the Open MCT for MCWS Plugin locally using Open MCT Configurator -With that running, browse to http://localhost:8080/ to access Open MCT for MCWS. + npm run build:prod + mct build --recipe recipes/development.yaml --instance development + npm run serve -### 4. Rebuilding SASS stylesheets - - npm run build:prod - -With the stylesheets rebuilt, you can reload your browser (assuming the server is running) to see the rebuilt CSS. +With that running, browse to http://localhost:8080/ to access Open MCT with the Open MCT for MCWS Plugin ## Development MCWS server -To connect Open MCT for MCWS to MCWS, either run a local mock server, run MCWS locally, or connect to a remote instance of MCWS. +To connect Open MCT to MCWS, either run a local mock server, run MCWS locally, or connect to a remote instance of MCWS. ## Running a mock MCWS server An example mock mcws server - https://github.com/davetsay/mcws-test-server @@ -50,6 +51,7 @@ Refer to MCWS documentation. Running a development server requires that you are on the JPL network so that you can access a development MCWS server. You'll need to retrieve an authentication cookie and make a small modification to your Open MCT for MCWS configuration; here's how. + ### 1. Get your CAM cookie To get past CAM, you will need to export an environment variable, `COOKIE`, that contains your CAM authentication cookie. Instructions for @@ -72,8 +74,10 @@ Running the tests creates a code coverage report in `target/coverage`. ## Building for production npm install - mvn clean install + npm run build:prod + mct build --recipe recipes/default.yaml --instance default +TODO: UPDATE THIS sentence, possibly with compressing the necessary files into a war. This will create a deployable artifact, `openmct_client.war` in the `target` directory. diff --git a/config.js b/config.js index 6d1720b4..bb73a1c1 100644 --- a/config.js +++ b/config.js @@ -378,15 +378,12 @@ /** * Enable/disable summary widgets. Added in R3.4.0. */ - SummaryWidget: { - enabled: false + summaryWidgets: { + enabled: true }, BarChart: { enabled: false }, - CorrelationTelemetry: { - enabled: false - }, ScatterPlot: { enabled: false }, @@ -608,8 +605,8 @@ * Developer Settings-- do not modify these unless you know what * they do! */ - // proxyUrl: 'http://localhost:8080/', - // useDeveloperStorage: true, + proxyUrl: 'http://localhost:8080/', + useDeveloperStorage: true, assetPath: 'node_modules/openmct/dist' }; diff --git a/index.html b/index.html index 490c8b12..e1c36da2 100644 --- a/index.html +++ b/index.html @@ -7,20 +7,8 @@ content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> - - - - - + { + const config = window.openmctMCWSConfig; + openmct.setAssetPath(config.assetPath || 'node_modules/openmct/dist'); + + //Optional Themes + if (config.theme) { + openmct.install(openmct.plugins[config.theme]()); + } else { + openmct.install(openmct.plugins.Snow()); + } + + if (config.useDeveloperStorage) { + openmct.install(openmct.plugins.LocalStorage()); + openmct.install(openmct.plugins.MyItems()); + } + + openmct.install( + openmct.plugins.Filters([ + 'vista.alarmsView', + 'telemetry.plot.overlay', + 'table', + 'vista.chanTableGroup', + 'vista.commandEventsView', + 'vista.messagesView', + 'vista.evrView' + ]) + ); + openmct.install(openmct.plugins.ObjectMigration()); + openmct.install( + openmct.plugins.DisplayLayout({ + showAsView: [ + 'summary-widget', + 'vista.packetSummaryEvents', + 'vista.dataProducts', + 'vista.packets', + 'vista.frameSummary', + 'vista.frameWatch' + ] + }) + ); + openmct.install( + openmct.plugins.ClearData( + [ + 'table', + 'telemetry.plot.overlay', + 'telemetry.plot.stacked', + 'vista.packetSummaryEvents', + 'vista.dataProducts', + 'vista.packets', + 'vista.frameSummary', + 'vista.frameWatch', + 'vista.chanTableGroup' + ], + { + indicator: false + } + ) + ); + openmct.install(openmct.plugins.UTCTimeSystem()); + openmct.install(openmct.plugins.Notebook()); + openmct.install(openmct.plugins.Clock({ useClockIndicator: false })); + + // install optional plugins, summary widget is handled separately as it was added long ago + if (config.plugins) { + if ( + config.plugins.summaryWidgets === true || + config.plugins.summaryWidgets?.enabled === true + ) { + openmct.install(openmct.plugins.SummaryWidget()); + } + + Object.entries(config.plugins).forEach(([plugin, pluginConfig]) => { + const pluginExists = openmct.plugins[plugin] || openmct.plugins.example[plugin]; + const pluginEnabled = pluginConfig?.enabled; + const isSummaryWidget = plugin === 'summaryWidgets'; + const installPlugin = pluginExists && pluginEnabled && !isSummaryWidget; + + if (installPlugin) { + openmct.install(openmct.plugins[plugin](...(pluginConfig.configuration ?? []))); + } else if (!pluginExists) { + console.warn(`Plugin ${plugin} does not exist. Check the plugin name and try again.`); + } + }); + } + + openmct.install(openmctMCWSPlugin(config)); + openmct.start(); +}, {once: true}); \ No newline at end of file diff --git a/loader.js b/loader.js deleted file mode 100644 index 687cc238..00000000 --- a/loader.js +++ /dev/null @@ -1,165 +0,0 @@ -define([ - 'openmct', - './src/AMMOSPlugins', - './src/styles/sass/vista.scss', - './src/commandEventsView/plugin', - './src/messagesView/plugin', - './src/product-status/plugin', - './about.html', - './src/metadataAction/plugin', - './src/clearDataIndicator/plugin', - './src/dictionaryView/plugin', - './src/packetSummary/plugin', - './src/containerView/plugin', - 'services/identity/MCWSIdentityProvider', - './src/persistence/plugin' -], function ( - openmct, - AMMOSPlugins, - VistaStyles /** Do not delete, needed for webpack to compile scss file*/, - CommandEventsViewPlugin, - MessagesPlugin, - ProductStatusPlugin, - AboutTemplate, - MetadataActionPlugin, - ClearDataIndicator, - DictionaryViewPlugin, - PacketSummaryPlugin, - ContainerViewPlugin, - IdentityProvider, - MCWSPersistenceProviderPlugin -) { - function loader(config) { - let persistenceLoaded; - const persistenceLoadedPromise = new Promise((resolve) => { - persistenceLoaded = resolve; - }); - openmct.setAssetPath(config.assetPath); - - //Optional Themes - if (config.theme) { - openmct.install(openmct.plugins[config.theme]()); - } else { - openmct.install(openmct.plugins.Snow()); - } - - openmct.install( - openmct.plugins.Filters([ - 'vista.alarmsView', - 'telemetry.plot.overlay', - 'table', - 'vista.chanTableGroup', - 'vista.commandEventsView', - 'vista.messagesView', - 'vista.evrView' - ]) - ); - openmct.install(openmct.plugins.ObjectMigration()); - openmct.install( - openmct.plugins.DisplayLayout({ - showAsView: [ - 'summary-widget', - 'vista.packetSummaryEvents', - 'vista.dataProducts', - 'vista.packets', - 'vista.frameSummary', - 'vista.frameWatch' - ] - }) - ); - openmct.install( - openmct.plugins.ClearData( - [ - 'table', - 'telemetry.plot.overlay', - 'telemetry.plot.stacked', - 'vista.packetSummaryEvents', - 'vista.dataProducts', - 'vista.packets', - 'vista.frameSummary', - 'vista.frameWatch', - 'vista.chanTableGroup' - ], - { - indicator: false - } - ) - ); - openmct.install(ClearDataIndicator.default(config.globalStalenessInterval)); - openmct.install(CommandEventsViewPlugin.default(config.tablePerformanceOptions)); - openmct.install(MessagesPlugin.default(config.tablePerformanceOptions)); - openmct.install(ProductStatusPlugin.default(config.tablePerformanceOptions)); - openmct.install(openmct.plugins.UTCTimeSystem()); - openmct.install(openmct.plugins.Notebook()); - openmct.install(MetadataActionPlugin.default()); - openmct.install(DictionaryViewPlugin.default(config.tablePerformanceOptions)); - openmct.install(PacketSummaryPlugin.default(config.tablePerformanceOptions)); - openmct.install(ContainerViewPlugin.default()); - openmct.install(openmct.plugins.Clock({ useClockIndicator: false })); - - openmct.install(new AMMOSPlugins(config)); - - openmct.user.setProvider(new IdentityProvider.default(openmct)); - - if (config.useDeveloperStorage) { - openmct.install(openmct.plugins.LocalStorage()); - openmct.install(openmct.plugins.MyItems()); - persistenceLoaded(); - } else { - const mcwsPersistenceProvider = MCWSPersistenceProviderPlugin.default(config.namespaces); - openmct.install(async (_openmct) => { - await mcwsPersistenceProvider(_openmct); - persistenceLoaded(); - }); - } - - // install optional plugins - if (config.plugins) { - Object.entries(config.plugins).forEach(([plugin, pluginConfig]) => { - const examplePluginExists = openmct.plugins.example[plugin]; - const pluginExists = openmct.plugins[plugin] || examplePluginExists; - const pluginEnabled = pluginConfig?.enabled; - const installPlugin = pluginExists && pluginEnabled; - - if (installPlugin) { - if (examplePluginExists) { - openmct.install(openmct.plugins.example[plugin](...(pluginConfig.configuration ?? []))); - } else { - openmct.install(openmct.plugins[plugin](...(pluginConfig.configuration ?? []))); - } - } else if (!pluginExists) { - console.warn(`Plugin ${plugin} does not exist. Check the plugin name and try again.`); - } - }); - } - - openmct.branding({ - aboutHtml: insertBuildInfo(AboutTemplate) - }); - - // do not show telemetry if it falls out of bounds - // even if there is no new telemetry - openmct.telemetry.greedyLAD(false); - - persistenceLoadedPromise.then(() => { - openmct.start(); - window.openmct = openmct; - }); - } - - /** - * Replaces placeholders in the HTML with build info provided by webpack. - * Build info is defined in webpack config, and is exposed as global - * JavaScript variables - * @param {*} markup - */ - function insertBuildInfo(markup) { - return markup - .replace(/\$\{project\.version\}/g, __OMM_VERSION__) - .replace(/\$\{timestamp\}/g, __OMM_BUILD_DATE__) - .replace(/\$\{buildNumber\}/g, __OMM_REVISION__) - .replace(/\$\{branch\}/g, __OMM_BUILD_BRANCH__); - } - - return loader; -}); diff --git a/package.json b/package.json index 99529efd..f4082abf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,9 @@ { - "name": "openmct-mcws", - "version": "v5.4.0-rc3", + "name": "openmct-mcws-plugin", + "version": "v1.0.0", "description": "Open MCT for MCWS", + "main": "dist/openmct-mcws-plugin.js", + "type": "module", "devDependencies": { "@babel/eslint-parser": "7.26.8", "@braintree/sanitize-url": "6.0.4", @@ -19,10 +21,12 @@ "eslint-plugin-prettier": "5.2.3", "eslint-plugin-vue": "9.32.0", "eventemitter3": "5.0.1", + "express": "^4.18.2", "file-saver": "2.0.5", "git-rev-sync": "3.0.2", "globals": "15.14.0", "html2canvas": "1.4.1", + "http-proxy-middleware": "^2.0.6", "imports-loader": "0.8.0", "jasmine-core": "5.1.1", "jshint": "^2.7.0", @@ -40,7 +44,6 @@ "mini-css-extract-plugin": "2.7.6", "moment": "2.30.1", "node-bourbon": "^4.2.3", - "openmct": "github:nasa/openmct#omm-r5.4.0-rc4", "prettier": "3.4.2", "printj": "1.3.1", "raw-loader": "^0.5.1", @@ -52,11 +55,14 @@ "vue": "3.4.24", "vue-eslint-parser": "^9.4.3", "vue-loader": "16.8.3", - "webpack": "5.94.0", - "webpack-cli": "5.1.1", + "webpack": "^5.94.0", + "webpack-cli": "^5.1.1", "webpack-dev-server": "5.0.2", "webpack-merge": "5.10.0" }, + "peerDependencies": { + "openmct": "^4.1.0 || ^4.1.0-next" + }, "scripts": { "clean": "npm cache clean --force;rm -rf ./dist ./node_modules ./target ./package-lock.json", "start": "npx webpack serve --config ./.webpack/webpack.dev.js", @@ -68,7 +74,7 @@ "build:watch": "webpack --config ./.webpack/webpack.dev.js --watch", "test": "karma start --single-run", "jshint": "jshint src/**/*.js || exit 0", - "prepare": "npm run build:prod" + "prepare": "node -e \"if (require('fs').existsSync('node_modules/webpack-cli')) { require('child_process').execSync('npm run build:prod', {stdio: 'inherit'}) }\" || true" }, "repository": { "type": "git", @@ -82,4 +88,4 @@ }, "author": "", "license": "Apache-2.0" -} \ No newline at end of file +} diff --git a/plugin.js b/plugin.js new file mode 100644 index 00000000..6a474d3f --- /dev/null +++ b/plugin.js @@ -0,0 +1,283 @@ +import AboutTemplate from './about.html'; +import VistaStyles from './src/styles/sass/vista.scss'; /** Do not delete, needed for webpack to compile scss file*/ +import CommandEventsViewPlugin from './src/commandEventsView/plugin.js'; +import TaxonomyPlugin from './src/taxonomy/plugin.js'; +import HistoricalTelemetryPlugin from './src/historical/plugin.js'; +import LinkPlugin from './src/link/plugin.js'; +import FormatPlugin from './src/formats/plugin.js'; +import MessagesPlugin from './src/messagesView/plugin.js'; +import ProductStatusPlugin from './src/product-status/plugin.js'; +import MetadataActionPlugin from './src/metadataAction/plugin.js'; +import ClearDataIndicatorPlugin from './src/clearDataIndicator/plugin.js'; +import DictionaryViewPlugin from './src/dictionaryView/plugin.js'; +import PacketSummaryPlugin from './src/packetSummary/plugin.js'; +import ContainerViewPlugin from './src/containerView/plugin.js'; +import IdentityProvider from './src/services/identity/MCWSIdentityProvider.js'; +import MCWSPersistenceProviderPlugin from './src/persistence/plugin.js'; +import DatasetCache from './src/services/dataset/DatasetCache.js'; +import SessionService from './src/services/session/SessionService.js'; +import GlobalStaleness from './src/services/globalStaleness/globalStaleness.js'; +import TypePlugin from './src/types/plugin.js'; +import TimePlugin from './src/time/plugin.js'; +import getVistaTime from './src/services/time/vistaTime.js'; +import RealtimeTelemetryPlugin from './src/realtime/plugin.js'; +import VenuePlugin from './src/venues/plugin.js'; +import mcwsClient from './src/services/mcws/MCWSClient.js'; +import UTCDayOfYearFormat from './src/formats/UTCDayOfYearFormat.js'; +import FrameWatchViewPlugin from './src/frameSummary/plugin.js'; +import FrameEventFilterViewPlugin from './src/frameEventFilterView/plugin.js'; +import ChannelTablePlugin from './src/channelTable/channelTablePlugin/plugin.js'; +import ChannelTableSetPlugin from './src/channelTable/channelTableSetPlugin/plugin.js'; +import ChannelLimitsPlugin from './src/channelLimits/plugin.js'; +import FrameAccountabilityPlugin from './src/frameAccountability/plugin.js'; +import AlarmsViewPlugin from './src/alarmsView/plugin.js'; +import EVRViewPlugin from './src/evrView/plugin.js'; +import CustomFormatterPlugin from './src/customFormatter/plugin.js'; +import CustomFormsPlugin from './src/customForms/plugin.js'; +import ActionModifiersPlugin from './src/actionModifiers/plugin.js'; +import RealtimeIndicatorPlugin from './src/realtimeIndicator/plugin.js'; +import PacketQueryPlugin from './src/packetQuery/plugin.js'; +import MCWSIndicatorPlugin from './src/mcwsIndicator/plugin.js'; +import MultipleHistoricalSessions from './src/multipleHistoricalSessions/plugin.js'; +import RealtimeSessions from './src/realtimeSessions/plugin.js'; +import GlobalFilters from './src/globalFilters/plugin.js'; +import ExportDataAction from './src/exportDataAction/plugin.js'; + +export default function openmctMCWSPlugin(options) { + return function install(openmct) { + const defaultConfig = { + venueAware: { + enabled: false, + venues: 'ExampleVenueDefinitions.json' + }, + taxonomy: { + evrDefaultBackgroundColor: undefined, + evrDefaultForegroundColor: undefined, + evrBackgroundColorByLevel: { + FATAL: '#ff0000', + WARNING_HI: '#ff7f24', + WARNING_LO: '#ffff00', + COMMAND: '#00bfff', + ACTIVITY_HI: '#6d6d6d', + ACTIVITY_LO: '#dcdcdc', + DIAGNOSTIC: '#00ff00', + EVR_UNKNOWN: '#00ff00', + FAULT: '#ff0000', + WARNING: '#ff7f24' + }, + evrForegroundColorByLevel: { + FATAL: '#ffffff', + WARNING_HI: '#000000', + WARNING_LO: '#000000', + COMMAND: '#ffffff', + ACTIVITY_HI: '#ffffff', + ACTIVITY_LO: '#000000', + DIAGNOSTIC: '#000000', + EVR_UNKNOWN: '#000000', + FAULT: '#ffffff', + WARNING: '#000000' + } + }, + time: { + defaultMode: 'fixed', + utcFormat: 'utc.day-of-year', + lmstEpoch: Date.UTC(2020, 2, 18, 0, 0, 0), + subscriptionMCWSFilterDelay: 100, + timeSystems: ['scet', 'ert'], + allowRealtime: true, + allowLAD: true, + records: 10 + }, + sessionHistoricalMaxResults: 100, + batchHistoricalChannelQueries: false, + disableSortParam: false, + messageStreamUrl: '', + messageTypeFilters: [], + frameAccountabilityExpectedVcidList: [], + queryTimespanLimit: undefined, + globalStalenessInterval: undefined, + customFormatters: [], + sessions: { + historicalSessionFilter: { + disable: false, + maxRecords: 100, + denyUnfilteredQueries: false + }, + realtimeSession: { + disable: false + } + }, + tablePerformanceOptions: { + telemetryMode: 'unlimited', + persistModeChange: false, + rowLimit: 50 + }, + assetPath: 'node_modules/openmct/dist', + mcwsPluginAssetPath: 'node_modules/openmct-mcws-plugin/dist' + }; + + // Deep merge function + function deepMerge(target, source) { + const output = Object.assign({}, target); + + if (isObject(target) && isObject(source)) { + Object.keys(source).forEach(key => { + if (isObject(source[key])) { + if (!(key in target)) { + Object.assign(output, { [key]: source[key] }); + } else { + output[key] = deepMerge(target[key], source[key]); + } + } else { + Object.assign(output, { [key]: source[key] }); + } + }); + } + + return output; + } + + function isObject(item) { + return item && typeof item === 'object' && !Array.isArray(item); + } + + const config = deepMerge(defaultConfig, options || {}); + + let persistenceLoaded; + const persistenceLoadedPromise = new Promise((resolve) => { + persistenceLoaded = resolve; + }); + + openmct.setAssetPath(config.assetPath); + openmct.install(ClearDataIndicatorPlugin(config.globalStalenessInterval)); + openmct.install(CommandEventsViewPlugin(config.tablePerformanceOptions)); + openmct.install(MessagesPlugin(config.tablePerformanceOptions)); + openmct.install(ProductStatusPlugin(config.tablePerformanceOptions)); + openmct.install(MetadataActionPlugin()); + openmct.install(DictionaryViewPlugin(config.tablePerformanceOptions)); + openmct.install(PacketSummaryPlugin(config.tablePerformanceOptions)); + openmct.install(ContainerViewPlugin()); + + // initialize session service, datasetCache service, global staleness + SessionService(openmct, config); + DatasetCache(openmct); + GlobalStaleness(openmct, config.globalStalenessInterval); + + openmct.install(new FormatPlugin(config)); + + const timePlugin = new TimePlugin(config.time); + + openmct.install(timePlugin); + + const formatKey = config.time.utcFormat; + const utcFormat = formatKey + ? openmct.telemetry.getFormatter(formatKey) + : new UTCDayOfYearFormat(); + const vistaTime = getVistaTime({ + options: timePlugin, + format: utcFormat + }); + openmct.install(RealtimeIndicatorPlugin(vistaTime, utcFormat)); + + mcwsClient.configure(config); + + openmct.install(MultipleHistoricalSessions(config.tablePerformanceOptions)); + openmct.install(RealtimeSessions()); + openmct.install(new HistoricalTelemetryPlugin(config)); + openmct.install(new RealtimeTelemetryPlugin(vistaTime, config)); + openmct.install(new TypePlugin()); + openmct.install(new TaxonomyPlugin(config.taxonomy)); + openmct.install(new LinkPlugin(config)); + openmct.install(new VenuePlugin(config)); + openmct.install(FrameWatchViewPlugin(config.tablePerformanceOptions)); + openmct.install(FrameEventFilterViewPlugin(config.tablePerformanceOptions)); + openmct.install(new ChannelTablePlugin(config.tablePerformanceOptions)); + openmct.install(new ChannelTableSetPlugin()); + openmct.install(new ChannelLimitsPlugin()); + openmct.install(new FrameAccountabilityPlugin(config)); + openmct.install(EVRViewPlugin(config)); + openmct.install(new AlarmsViewPlugin(config.tablePerformanceOptions)); + openmct.install(MCWSIndicatorPlugin()); + + if (config.messageStreamUrl && config.messageStreamUrl !== '') { + openmct.install( + new MessageStreamProcessor(config.messageStreamUrl, { + clearData: ['StartOfSession', 'EndOfSession'], + suspectChannels: ['SuspectChannels'] + }) + ); + } + + if (config.customFormatters.length) { + openmct.install(CustomFormatterPlugin(config.customFormatters)); + } + + openmct.install(CustomFormsPlugin()); + openmct.install( + new ExportDataAction([ + 'table', + 'telemetry.plot.overlay', + 'telemetry.plot.stacked', + 'vista.channel', + 'vista.channelGroup', + 'vista.chanTableGroup', + 'vista.evr', + 'vista.evrModule', + 'vista.evrSource', + 'vista.evrView' + ]) + ); + openmct.install(ActionModifiersPlugin()); + openmct.install(new PacketQueryPlugin()); + + if (config.globalFilters) { + openmct.install(new GlobalFilters(config.globalFilters)); + } + + openmct.user.setProvider(new IdentityProvider(openmct)); + + if (config.useDeveloperStorage) { + // plugins installed in recipe + persistenceLoaded(); + } else { + const mcwsPersistenceProvider = MCWSPersistenceProviderPlugin(config.namespaces); + + openmct.install(async (_openmct) => { + await mcwsPersistenceProvider(_openmct); + persistenceLoaded(); + }); + } + + + + openmct.branding({ aboutHtml: insertBuildInfo(AboutTemplate) }); + + // do not show telemetry if it falls out of bounds + // even if there is no new telemetry + openmct.telemetry.greedyLAD(false); + + persistenceLoadedPromise.then(() => { + window.openmctMCWSConfig = config; + }); + + // load the css file + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = `${config.mcwsPluginAssetPath}/openmct-mcws-plugin.css`; + document.head.appendChild(link); + } + + /** + * Replaces placeholders in the HTML with build info provided by webpack. + * Build info is defined in webpack config, and is exposed as global + * JavaScript variables + * @param {*} markup + */ + function insertBuildInfo(markup) { + return markup + .replace(/\$\{project\.version\}/g, __OMM_VERSION__) + .replace(/\$\{timestamp\}/g, __OMM_BUILD_DATE__) + .replace(/\$\{buildNumber\}/g, __OMM_REVISION__) + .replace(/\$\{branch\}/g, __OMM_BUILD_BRANCH__); + } +} diff --git a/pom.xml b/pom.xml index d32d6a9e..0e9278a9 100644 --- a/pom.xml +++ b/pom.xml @@ -5,8 +5,8 @@ 4.0.0 gov.nasa.arc.wtd openmct-client - Open MCT for MCWS Client - v5.4.0-rc3 + Open MCT for MCWS Plugin + v1.0.0 war @@ -19,9 +19,7 @@ - - org.apache.maven.plugins @@ -30,23 +28,11 @@ openmct_client - . index.html - openmct-mcws.js config.js - loader.js ExampleVenueDefinitions.json src/**/* dist/**/* @@ -86,48 +72,6 @@ - - - org.apache.tomcat.maven diff --git a/src/AMMOSPlugins.js b/src/AMMOSPlugins.js deleted file mode 100644 index b2c16428..00000000 --- a/src/AMMOSPlugins.js +++ /dev/null @@ -1,155 +0,0 @@ -define([ - 'services/dataset/DatasetCache', - 'services/session/SessionService', - 'services/globalStaleness/globalStaleness', - './types/plugin', - './taxonomy/plugin', - './time/plugin', - 'services/time/vistaTime', - './historical/plugin', - './realtime/plugin', - './link/plugin', - './formats/plugin', - './venues/plugin', - 'services/mcws/MCWSClient', - './formats/UTCDayOfYearFormat', - './frameSummary/plugin', - './frameEventFilterView/plugin', - './channelTable/channelTablePlugin/plugin', - './channelTable/channelTableSetPlugin/plugin', - './channelLimits/plugin', - './frameAccountability/plugin', - './alarmsView/plugin', - './messageStreamProcessor/plugin', - './evrView/plugin', - './customFormatter/plugin', - './customForms/plugin', - './actionModifiers/plugin', - './realtimeIndicator/plugin', - './packetQuery/plugin', - './mcwsIndicator/plugin', - './multipleHistoricalSessions/plugin', - './realtimeSessions/plugin', - './globalFilters/plugin', - './exportDataAction/plugin' -], function ( - DatasetCache, - SessionService, - GlobalStaleness, - TypePlugin, - TaxonomyPlugin, - TimePlugin, - getVistaTime, - HistoricalTelemetryPlugin, - RealtimeTelemetryPlugin, - LinkPlugin, - FormatPlugin, - VenuePlugin, - mcwsClient, - UTCDayOfYearFormat, - FrameWatchViewPlugin, - FrameEventFilterViewPlugin, - ChannelTablePlugin, - ChannelTableSetPlugin, - ChannelLimitsPlugin, - FrameAccountabilityPlugin, - AlarmsViewPlugin, - MessageStreamProcessor, - EVRViewPlugin, - CustomFormatterPlugin, - CustomFormsPlugin, - ActionModifiersPlugin, - RealtimeIndicatorPlugin, - PacketQueryPlugin, - MCWSIndicatorPlugin, - MultipleHistoricalSessions, - RealtimeSessions, - GlobalFilters, - ExportDataAction -) { - function AMMOSPlugins(options) { - return function install(openmct) { - // initialize session service, datasetCache service, global staleness - SessionService.default(openmct, options); - DatasetCache.default(openmct); - GlobalStaleness.default(openmct, options.globalStalenessInterval); - - openmct.install(new FormatPlugin(options)); - - const timePlugin = new TimePlugin.default(options.time); - openmct.install(timePlugin); - - const formatKey = options.time.utcFormat; - const utcFormat = formatKey - ? openmct.telemetry.getFormatter(formatKey) - : new UTCDayOfYearFormat.default(); - const vistaTime = getVistaTime.default({ - options: timePlugin, - format: utcFormat - }); - openmct.install(RealtimeIndicatorPlugin.default(vistaTime, utcFormat)); - - mcwsClient.default.configure(options); - - openmct.install(MultipleHistoricalSessions.default(options.tablePerformanceOptions)); - openmct.install(RealtimeSessions.default()); - - openmct.install(new HistoricalTelemetryPlugin(options)); - openmct.install(new RealtimeTelemetryPlugin.default(vistaTime, options)); - openmct.install(new TypePlugin.default()); - openmct.install(new TaxonomyPlugin(options.taxonomy)); - openmct.install(new LinkPlugin(options)); - openmct.install(new VenuePlugin.default(options)); - openmct.install(FrameWatchViewPlugin.default(options.tablePerformanceOptions)); - openmct.install(FrameEventFilterViewPlugin.default(options.tablePerformanceOptions)); - openmct.install(new ChannelTablePlugin.default(options.tablePerformanceOptions)); - openmct.install(new ChannelTableSetPlugin.default()); - openmct.install(new ChannelLimitsPlugin.default()); - openmct.install(new FrameAccountabilityPlugin.default(options)); - openmct.install(EVRViewPlugin.default(options)); - openmct.install(new AlarmsViewPlugin.default(options.tablePerformanceOptions)); - openmct.install(MCWSIndicatorPlugin.default()); - - if ( - window.openmctMCWSConfig.messageStreamUrl && - window.openmctMCWSConfig.messageStreamUrl !== '' - ) { - openmct.install( - new MessageStreamProcessor(window.openmctMCWSConfig.messageStreamUrl, { - clearData: ['StartOfSession', 'EndOfSession'], - suspectChannels: ['SuspectChannels'] - }) - ); - } - - if (options.customFormatters.length) { - openmct.install(CustomFormatterPlugin.default(options.customFormatters)); - } - - openmct.install(CustomFormsPlugin.default()); - - openmct.install(openmct.plugins.DefaultRootName('VISTA')); - openmct.install( - new ExportDataAction.default([ - 'table', - 'telemetry.plot.overlay', - 'telemetry.plot.stacked', - 'vista.channel', - 'vista.channelGroup', - 'vista.chanTableGroup', - 'vista.evr', - 'vista.evrModule', - 'vista.evrSource', - 'vista.evrView' - ]) - ); - openmct.install(ActionModifiersPlugin.default()); - openmct.install(new PacketQueryPlugin.default()); - if (options.globalFilters) { - openmct.install(new GlobalFilters.default(options.globalFilters)); - } - }; - } - - return AMMOSPlugins; -}); diff --git a/src/actionModifiers/ImageExport/ImageExportModifier.js b/src/actionModifiers/ImageExport/ImageExportModifier.js index 27370556..0bffd90e 100644 --- a/src/actionModifiers/ImageExport/ImageExportModifier.js +++ b/src/actionModifiers/ImageExport/ImageExportModifier.js @@ -1,5 +1,5 @@ -import SessionService from 'services/session/SessionService'; -import { formatNumberSequence } from 'ommUtils/strings'; +import SessionService from 'services/session/SessionService.js'; +import { formatNumberSequence } from 'ommUtils/strings.js'; function imageExportModifier(openmct) { const PNGImageExportAction = openmct.actions._allActions['export-as-png']; diff --git a/src/actionModifiers/ImportExportWithDatasets/importWithDatasetsModifier.js b/src/actionModifiers/ImportExportWithDatasets/importWithDatasetsModifier.js index ea98992a..5f8937ce 100644 --- a/src/actionModifiers/ImportExportWithDatasets/importWithDatasetsModifier.js +++ b/src/actionModifiers/ImportExportWithDatasets/importWithDatasetsModifier.js @@ -1,5 +1,5 @@ import ImportWithDatasetsFormComponent from './ImportWithDatasetsFormComponent.vue'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; import DatasetCache from 'services/dataset/DatasetCache'; import Types from 'types/types'; diff --git a/src/actionModifiers/MultipleDatasets/warnMultipleDatasetsOnDuplicateModifier.js b/src/actionModifiers/MultipleDatasets/warnMultipleDatasetsOnDuplicateModifier.js index 084a9a3d..1f3db72e 100644 --- a/src/actionModifiers/MultipleDatasets/warnMultipleDatasetsOnDuplicateModifier.js +++ b/src/actionModifiers/MultipleDatasets/warnMultipleDatasetsOnDuplicateModifier.js @@ -1,4 +1,4 @@ -import { MULTIPLE_DATASET_WARNING } from './constants'; +import { MULTIPLE_DATASET_WARNING } from './constants.js'; export default function warnMultipleDatasetsOnDuplicateModifier(openmct) { const duplicateAction = openmct.actions._allActions['duplicate']; diff --git a/src/actionModifiers/MultipleDatasets/warnMultipleDatasetsOnImportModifier.js b/src/actionModifiers/MultipleDatasets/warnMultipleDatasetsOnImportModifier.js index d1a24374..c8dfad7b 100644 --- a/src/actionModifiers/MultipleDatasets/warnMultipleDatasetsOnImportModifier.js +++ b/src/actionModifiers/MultipleDatasets/warnMultipleDatasetsOnImportModifier.js @@ -1,5 +1,5 @@ -import DatasetCache from 'services/dataset/DatasetCache'; -import { MULTIPLE_DATASET_WARNING } from './constants'; +import DatasetCache from 'services/dataset/DatasetCache.js'; +import { MULTIPLE_DATASET_WARNING } from './constants.js'; export default function warnMultipleDatasetsOnImportModifier(openmct) { const importAsJSONAction = openmct.actions._allActions['import.JSON']; diff --git a/src/actionModifiers/plugin.js b/src/actionModifiers/plugin.js index 4b42ec62..f0fb6c9a 100644 --- a/src/actionModifiers/plugin.js +++ b/src/actionModifiers/plugin.js @@ -1,7 +1,7 @@ -import preventImportIntoDatasetModifier from './preventImportIntoDatasetModifier'; -import importWithDatasetsModifier from './ImportExportWithDatasets/importWithDatasetsModifier'; -import warnMultipleDatasetsOnDuplicateModifier from './MultipleDatasets/warnMultipleDatasetsOnDuplicateModifier'; -import imageExportModifier from './ImageExport/ImageExportModifier'; +import preventImportIntoDatasetModifier from './preventImportIntoDatasetModifier.js'; +import importWithDatasetsModifier from './ImportExportWithDatasets/importWithDatasetsModifier.js'; +import warnMultipleDatasetsOnDuplicateModifier from './MultipleDatasets/warnMultipleDatasetsOnDuplicateModifier.js'; +import imageExportModifier from './ImageExport/ImageExportModifier.js'; /** * DEPENDENCY: These modifiers have a dependency on Open MCT action internals. diff --git a/src/alarmsView/AlarmsAutoclearViewProvider.js b/src/alarmsView/AlarmsAutoclearViewProvider.js index 666e3117..e0a052cb 100644 --- a/src/alarmsView/AlarmsAutoclearViewProvider.js +++ b/src/alarmsView/AlarmsAutoclearViewProvider.js @@ -1,4 +1,4 @@ -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; import AlarmsAutoclear from './AlarmsAutoclear.vue'; import TelemetryTableConfiguration from 'openmct.tables.TelemetryTableConfiguration'; diff --git a/src/alarmsView/AlarmsTable.js b/src/alarmsView/AlarmsTable.js index 24935d15..95d53243 100644 --- a/src/alarmsView/AlarmsTable.js +++ b/src/alarmsView/AlarmsTable.js @@ -1,7 +1,7 @@ import _ from 'lodash'; import TelemetryTable from 'openmct.tables.TelemetryTable'; -import AlarmsViewRowCollection from './AlarmsViewRowCollection'; -import AlarmsViewHistoricalContextTableRow from './AlarmsViewHistoricalContextTableRow'; +import AlarmsViewRowCollection from './AlarmsViewRowCollection.js'; +import AlarmsViewHistoricalContextTableRow from './AlarmsViewHistoricalContextTableRow.js'; export default class AlarmsTable extends TelemetryTable { initialize() { diff --git a/src/alarmsView/AlarmsViewProvider.js b/src/alarmsView/AlarmsViewProvider.js index cb9845e8..e34daee6 100644 --- a/src/alarmsView/AlarmsViewProvider.js +++ b/src/alarmsView/AlarmsViewProvider.js @@ -1,4 +1,4 @@ -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; import TableComponent from 'openmct.tables.components.Table'; import AlarmsTable from './AlarmsTable.js'; diff --git a/src/alarmsView/plugin.js b/src/alarmsView/plugin.js index 707316f9..0a5f3211 100644 --- a/src/alarmsView/plugin.js +++ b/src/alarmsView/plugin.js @@ -1,7 +1,7 @@ -import AlarmsViewProvider from './AlarmsViewProvider'; -import AlarmsAutoclearViewProvider from './AlarmsAutoclearViewProvider'; -import AlarmsViewActions from './AlarmsViewActions'; -import VistaTableConfigurationProvider from '../tables/VistaTableConfigurationProvider'; +import AlarmsViewProvider from './AlarmsViewProvider.js'; +import AlarmsAutoclearViewProvider from './AlarmsAutoclearViewProvider.js'; +import AlarmsViewActions from './AlarmsViewActions.js'; +import VistaTableConfigurationProvider from '../tables/VistaTableConfigurationProvider.js'; export default function AlarmsViewPlugin(options) { return function install(openmct) { diff --git a/src/channelLimits/plugin.js b/src/channelLimits/plugin.js index ed1b55ad..340c3f1e 100644 --- a/src/channelLimits/plugin.js +++ b/src/channelLimits/plugin.js @@ -1,4 +1,4 @@ -import ChannelLimitsProvider from './ChannelLimitsProvider'; +import ChannelLimitsProvider from './ChannelLimitsProvider.js'; export default function ChannelLimitsPlugin() { return function install(openmct) { diff --git a/src/channelLimits/pluginSpec.js b/src/channelLimits/pluginSpec.js index 4ef5c2fb..dba82d6d 100644 --- a/src/channelLimits/pluginSpec.js +++ b/src/channelLimits/pluginSpec.js @@ -1,4 +1,4 @@ -import ChannelLimitsProvider from './ChannelLimitsProvider'; +import ChannelLimitsProvider from './ChannelLimitsProvider.js'; describe('the channel limits provider', () => { let channelLimitsProvider; diff --git a/src/channelTable/channelTablePlugin/ChannelTable.js b/src/channelTable/channelTablePlugin/ChannelTable.js index 41a4a0d3..5fafa7fa 100644 --- a/src/channelTable/channelTablePlugin/ChannelTable.js +++ b/src/channelTable/channelTablePlugin/ChannelTable.js @@ -1,9 +1,9 @@ -import ChannelTableRowCollection from './ChannelTableRowCollection'; -import ChannelTableRow from './ChannelTableRow'; +import ChannelTableRowCollection from './ChannelTableRowCollection.js'; +import ChannelTableRow from './ChannelTableRow.js'; import TelemetryTable from 'openmct.tables.TelemetryTable'; import TelemetryTableColumn from 'openmct.tables.TelemetryTableColumn'; -import EmptyChannelTableRow from './EmptyChannelTableRow'; -import ObjectNameColumn from './ObjectNameColumn'; +import EmptyChannelTableRow from './EmptyChannelTableRow.js'; +import ObjectNameColumn from './ObjectNameColumn.js'; export default class ChannelTable extends TelemetryTable { constructor(domainObject, openmct, options) { diff --git a/src/channelTable/channelTablePlugin/ChannelTableFormatViewProvider.js b/src/channelTable/channelTablePlugin/ChannelTableFormatViewProvider.js index 37fe933f..14189ac4 100644 --- a/src/channelTable/channelTablePlugin/ChannelTableFormatViewProvider.js +++ b/src/channelTable/channelTablePlugin/ChannelTableFormatViewProvider.js @@ -1,6 +1,6 @@ import CellFormatConfigurationComponent from './CellFormatConfigurationComponent.vue'; import TelemetryTableConfiguration from 'openmct.tables.TelemetryTableConfiguration'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default function ChannelTableFormatViewProvider(openmct, options) { return { diff --git a/src/channelTable/channelTablePlugin/ChannelTableViewProvider.js b/src/channelTable/channelTablePlugin/ChannelTableViewProvider.js index acff3651..86172118 100644 --- a/src/channelTable/channelTablePlugin/ChannelTableViewProvider.js +++ b/src/channelTable/channelTablePlugin/ChannelTableViewProvider.js @@ -1,6 +1,6 @@ -import ChannelTable from './ChannelTable'; +import ChannelTable from './ChannelTable.js'; import TableComponent from 'openmct.tables.components.Table'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default class ChannelTableViewProvider { constructor(openmct, options) { diff --git a/src/channelTable/channelTablePlugin/ObjectNameColumn.js b/src/channelTable/channelTablePlugin/ObjectNameColumn.js index 7f0c8cd0..d83bb973 100644 --- a/src/channelTable/channelTablePlugin/ObjectNameColumn.js +++ b/src/channelTable/channelTablePlugin/ObjectNameColumn.js @@ -1,33 +1,31 @@ -define(function () { - class ObjectNameColumn { - constructor(objectName) { - this.objectName = objectName; - } +class ObjectNameColumn { + constructor(objectName) { + this.objectName = objectName; + } - getKey() { - return 'vista-lad-name'; - } + getKey() { + return 'vista-lad-name'; + } - getTitle() { - return 'Name'; - } + getTitle() { + return 'Name'; + } - getMetadatum() { - return {}; - } + getMetadatum() { + return {}; + } - hasValueForDatum() { - return true; - } + hasValueForDatum() { + return true; + } - getRawValue() { - return this.objectName; - } + getRawValue() { + return this.objectName; + } - getFormattedValue() { - return this.objectName; - } + getFormattedValue() { + return this.objectName; } +} - return ObjectNameColumn; -}); +export default ObjectNameColumn; diff --git a/src/channelTable/channelTablePlugin/plugin.js b/src/channelTable/channelTablePlugin/plugin.js index fee8d3be..6e8c061a 100644 --- a/src/channelTable/channelTablePlugin/plugin.js +++ b/src/channelTable/channelTablePlugin/plugin.js @@ -3,10 +3,10 @@ import { CHANNEL_TABLE_NAME, CHANNEL_TABLE_ICON, CHANNEL_KEY -} from '../constants'; -import ChannelTableViewProvider from './ChannelTableViewProvider'; -import ChannelTableFormatViewProvider from './ChannelTableFormatViewProvider'; -import VistaTableConfigurationProvider from '../../tables/VistaTableConfigurationProvider'; +} from '../constants.js'; +import ChannelTableViewProvider from './ChannelTableViewProvider.js'; +import ChannelTableFormatViewProvider from './ChannelTableFormatViewProvider.js'; +import VistaTableConfigurationProvider from '../../tables/VistaTableConfigurationProvider.js'; export default function install(options) { return function ChannelTablePlugin(openmct) { diff --git a/src/channelTable/channelTableSetPlugin/ChannelTableSetCompositionPolicy.js b/src/channelTable/channelTableSetPlugin/ChannelTableSetCompositionPolicy.js index 169f0159..b119f68b 100644 --- a/src/channelTable/channelTableSetPlugin/ChannelTableSetCompositionPolicy.js +++ b/src/channelTable/channelTableSetPlugin/ChannelTableSetCompositionPolicy.js @@ -1,4 +1,4 @@ -import { CHANNEL_TABLE_KEY, CHANNEL_TABLE_SET_KEY } from '../constants'; +import { CHANNEL_TABLE_KEY, CHANNEL_TABLE_SET_KEY } from '../constants.js'; export default function channelTableSetCompositionPolicy(openmct) { return function (parent, child) { diff --git a/src/channelTable/channelTableSetPlugin/ChannelTableSetView.js b/src/channelTable/channelTableSetPlugin/ChannelTableSetView.js index 2dd5d81d..051e0a18 100644 --- a/src/channelTable/channelTableSetPlugin/ChannelTableSetView.js +++ b/src/channelTable/channelTableSetPlugin/ChannelTableSetView.js @@ -1,5 +1,5 @@ import ChannelTableSet from './ChannelTableSet.vue'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default class ChannelTableSetView { constructor(openmct, domainObject, objectPath) { diff --git a/src/channelTable/channelTableSetPlugin/ChannelTableSetViewProvider.js b/src/channelTable/channelTableSetPlugin/ChannelTableSetViewProvider.js index d25cbd0c..2b3f76e3 100644 --- a/src/channelTable/channelTableSetPlugin/ChannelTableSetViewProvider.js +++ b/src/channelTable/channelTableSetPlugin/ChannelTableSetViewProvider.js @@ -3,7 +3,7 @@ import { CHANNEL_TABLE_SET_NAME, CHANNEL_TABLE_SET_VIEW_KEY, CHANNEL_TABLE_SET_KEY -} from '../constants'; +} from '../constants.js'; import ChannelTableSetView from './ChannelTableSetView.js'; export default class ChannelTableSetViewProvider { diff --git a/src/channelTable/channelTableSetPlugin/plugin.js b/src/channelTable/channelTableSetPlugin/plugin.js index 2ef53a66..575d07da 100644 --- a/src/channelTable/channelTableSetPlugin/plugin.js +++ b/src/channelTable/channelTableSetPlugin/plugin.js @@ -2,9 +2,9 @@ import { CHANNEL_TABLE_SET_ICON, CHANNEL_TABLE_SET_KEY, CHANNEL_TABLE_SET_NAME -} from '../constants'; -import ChannelTableSetViewProvider from './ChannelTableSetViewProvider'; -import channelTableSetCompositionPolicy from './ChannelTableSetCompositionPolicy'; +} from '../constants.js'; +import ChannelTableSetViewProvider from './ChannelTableSetViewProvider.js'; +import channelTableSetCompositionPolicy from './ChannelTableSetCompositionPolicy.js'; export default function ChannelTableSetPlugin() { return function install(openmct) { diff --git a/src/clearDataIndicator/plugin.js b/src/clearDataIndicator/plugin.js index 01d2f498..92d0ecfe 100644 --- a/src/clearDataIndicator/plugin.js +++ b/src/clearDataIndicator/plugin.js @@ -1,4 +1,4 @@ -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; import ClearDataIndicator from './ClearDataIndicator.vue'; export default function plugin(globalStalenessMs) { diff --git a/src/commandEventsView/CommandEventsViewProvider.js b/src/commandEventsView/CommandEventsViewProvider.js index ce387c74..0177e06d 100644 --- a/src/commandEventsView/CommandEventsViewProvider.js +++ b/src/commandEventsView/CommandEventsViewProvider.js @@ -1,6 +1,6 @@ import CommandEventsTable from './CommandEventsTable.js'; import TableComponent from 'openmct.tables.components.Table'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default class CommandEventsViewProvider { constructor(openmct, options) { diff --git a/src/constants.js b/src/constants.js index 6d85466a..7ae9e032 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,217 +1,215 @@ -define([], function () { - var CONSTANTS = { - DICTIONARY_PROPERTIES: [ - 'channelDictionaryUrl', - 'channelEnumerationDictionaryUrl', - 'eventRecordDictionaryUrl' - ], - /** - * An array of model properties that provide evrs. - */ - EVR_PROPERTIES: [ - 'eventRecordDictionaryUrl', - 'evrHistoricalUrl', - 'evrSimStreamUrl', - 'evrSimStreamDatatableUrl', - 'evrStreamUrl', - 'evrLADUrl' - ], - /** - * An array of model properties that provide channels. - */ - CHANNEL_PROPERTIES: ['channelDictionaryUrl'], +const CONSTANTS = { + DICTIONARY_PROPERTIES: [ + 'channelDictionaryUrl', + 'channelEnumerationDictionaryUrl', + 'eventRecordDictionaryUrl' + ], + /** + * An array of model properties that provide evrs. + */ + EVR_PROPERTIES: [ + 'eventRecordDictionaryUrl', + 'evrHistoricalUrl', + 'evrSimStreamUrl', + 'evrSimStreamDatatableUrl', + 'evrStreamUrl', + 'evrLADUrl' + ], + /** + * An array of model properties that provide channels. + */ + CHANNEL_PROPERTIES: ['channelDictionaryUrl'], - /** - * An array of model properties that provide different Types of channel - * telemetry. - */ - CHANNEL_TAXONOMY_PROPERTIES: [ - 'channelHistoricalUrl', - 'channelMinMaxUrl', - 'channelLADUrl', - 'channelSimStreamUrl', - 'channelSimStreamDatatableUrl', - 'channelStreamUrl' - ], + /** + * An array of model properties that provide different Types of channel + * telemetry. + */ + CHANNEL_TAXONOMY_PROPERTIES: [ + 'channelHistoricalUrl', + 'channelMinMaxUrl', + 'channelLADUrl', + 'channelSimStreamUrl', + 'channelSimStreamDatatableUrl', + 'channelStreamUrl' + ], - /** - * An array of model properties that provide data products. - */ - DATA_PRODUCT_PROPERTIES: ['dataProductUrl', 'dataProductContentUrl'], + /** + * An array of model properties that provide data products. + */ + DATA_PRODUCT_PROPERTIES: ['dataProductUrl', 'dataProductContentUrl'], - /** - * An array of model properties that provide packet metadata and contents. - * @type {string[]} - */ - PACKET_PROPERTIES: ['packetUrl', 'packetContentUrl'], + /** + * An array of model properties that provide packet metadata and contents. + * @type {string[]} + */ + PACKET_PROPERTIES: ['packetUrl', 'packetContentUrl'], - /** - * Ranges available on an EVR type. - */ - EVR_RANGES: [ - { - name: 'Record Type', - key: 'record_type', - format: 'string', - hints: {} - }, - { - name: 'Module', - key: 'module', - format: 'string', - hints: {} - }, - { - name: 'Level', - key: 'level', - format: 'string', - hints: {} - }, - { - name: 'EVR Name', - key: 'name', - format: 'string', - hints: {} - }, - { - name: 'Message', - key: 'message', - format: 'string', - hints: {} - }, - { - name: 'Metadata Values', - key: 'metadata_values', - format: 'string', - hints: {} - }, - { - name: 'Metadata keywords', - key: 'metadata_keywords', - format: 'string', - hints: {} - }, - { - name: 'Event ID', - key: 'event_id', - format: 'string', - hints: {} - }, - { - name: 'DSS ID', - key: 'dss_id', - format: 'integer', - hints: {} - }, - { - name: 'Realtime?', - key: 'realtime', - format: 'string', - hints: {}, - filters: [ - { - comparator: 'equals', - possibleValues: [ - { value: true, label: 'Realtime' }, - { value: false, label: 'Recorded' } - ] - } - ] - }, - { - name: 'Session ID', - key: 'session_id', - format: 'integer', - hints: {} - }, - { - name: 'Session Host', - key: 'session_host', - format: 'string', - hints: {} - }, - { - name: 'From SSE?', - key: 'from_sse', - format: 'string', - hints: {}, - filters: [ - { - comparator: 'equals', - possibleValues: [ - { value: true, label: 'SSE' }, - { value: false, label: 'FSW' } - ] - } - ] - }, - { - name: 'VCID', - key: 'vcid', - format: 'string', - hints: {} - }, - { - name: 'LST', - key: 'lst', - format: 'string', - hints: {} - }, - { - name: 'RCT', - key: 'rct', - format: 'string', - hints: {} - }, - { - key: 'isStale', - source: 'isStale', - name: 'Stale', - format: 'enum', - type: 'enum', - enumerations: [ - { - string: 'TRUE', - value: 1 - }, - { - string: 'FALSE', - value: 0 - } - ], - hints: { - range: 0 + /** + * Ranges available on an EVR type. + */ + EVR_RANGES: [ + { + name: 'Record Type', + key: 'record_type', + format: 'string', + hints: {} + }, + { + name: 'Module', + key: 'module', + format: 'string', + hints: {} + }, + { + name: 'Level', + key: 'level', + format: 'string', + hints: {} + }, + { + name: 'EVR Name', + key: 'name', + format: 'string', + hints: {} + }, + { + name: 'Message', + key: 'message', + format: 'string', + hints: {} + }, + { + name: 'Metadata Values', + key: 'metadata_values', + format: 'string', + hints: {} + }, + { + name: 'Metadata keywords', + key: 'metadata_keywords', + format: 'string', + hints: {} + }, + { + name: 'Event ID', + key: 'event_id', + format: 'string', + hints: {} + }, + { + name: 'DSS ID', + key: 'dss_id', + format: 'integer', + hints: {} + }, + { + name: 'Realtime?', + key: 'realtime', + format: 'string', + hints: {}, + filters: [ + { + comparator: 'equals', + possibleValues: [ + { value: true, label: 'Realtime' }, + { value: false, label: 'Recorded' } + ] } + ] + }, + { + name: 'Session ID', + key: 'session_id', + format: 'integer', + hints: {} + }, + { + name: 'Session Host', + key: 'session_host', + format: 'string', + hints: {} + }, + { + name: 'From SSE?', + key: 'from_sse', + format: 'string', + hints: {}, + filters: [ + { + comparator: 'equals', + possibleValues: [ + { value: true, label: 'SSE' }, + { value: false, label: 'FSW' } + ] + } + ] + }, + { + name: 'VCID', + key: 'vcid', + format: 'string', + hints: {} + }, + { + name: 'LST', + key: 'lst', + format: 'string', + hints: {} + }, + { + name: 'RCT', + key: 'rct', + format: 'string', + hints: {} + }, + { + key: 'isStale', + source: 'isStale', + name: 'Stale', + format: 'enum', + type: 'enum', + enumerations: [ + { + string: 'TRUE', + value: 1 + }, + { + string: 'FALSE', + value: 0 + } + ], + hints: { + range: 0 } - ], + } + ], - FRAME_EVENT_TYPES: { - BadTelemetryFrame: 'Bad Telemetry Frame', - InSync: 'In Sync.', - LossOfSync: 'Loss of Sync.', - FrameSequenceAnomaly: 'Frame Sequence Anomaly', - OutOfSyncData: 'Out Of Sync. Data' - }, + FRAME_EVENT_TYPES: { + BadTelemetryFrame: 'Bad Telemetry Frame', + InSync: 'In Sync.', + LossOfSync: 'Loss of Sync.', + FrameSequenceAnomaly: 'Frame Sequence Anomaly', + OutOfSyncData: 'Out Of Sync. Data' + }, - //Dataset fields that require websockets for realtime data - WEBSOCKET_STREAM_URL_KEYS: [ - 'channelStreamUrl', - 'dataProductStreamUrl', - 'evrStreamUrl', - 'messageStreamUrl', - 'frameSummaryStreamUrl', - 'alarmMessageStreamUrl', - 'frameEventStreamUrl' - ] - }; + //Dataset fields that require websockets for realtime data + WEBSOCKET_STREAM_URL_KEYS: [ + 'channelStreamUrl', + 'dataProductStreamUrl', + 'evrStreamUrl', + 'messageStreamUrl', + 'frameSummaryStreamUrl', + 'alarmMessageStreamUrl', + 'frameEventStreamUrl' + ] +}; - /** - * An array of model properties that is necessary to provide channel - * telemetry. - */ - CONSTANTS.CHANNEL_COPY_KEYS = CONSTANTS.CHANNEL_PROPERTIES.concat( - CONSTANTS.CHANNEL_TAXONOMY_PROPERTIES - ); +/** + * An array of model properties that is necessary to provide channel + * telemetry. + */ +CONSTANTS.CHANNEL_COPY_KEYS = CONSTANTS.CHANNEL_PROPERTIES.concat( + CONSTANTS.CHANNEL_TAXONOMY_PROPERTIES +); - return CONSTANTS; -}); +export default CONSTANTS; diff --git a/src/containerView/FolderGridViewProvider.js b/src/containerView/FolderGridViewProvider.js index 943e5263..76b154c3 100644 --- a/src/containerView/FolderGridViewProvider.js +++ b/src/containerView/FolderGridViewProvider.js @@ -1,5 +1,5 @@ import FolderGridViewComponent from 'openmct.views.FolderGridViewComponent'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default class FolderGridView { constructor(openmct, types) { diff --git a/src/containerView/FolderListViewProvider.js b/src/containerView/FolderListViewProvider.js index f21a4d7a..9d3f40d7 100644 --- a/src/containerView/FolderListViewProvider.js +++ b/src/containerView/FolderListViewProvider.js @@ -1,5 +1,5 @@ import FolderListViewComponent from 'openmct.views.FolderListViewComponent'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default class FolderListView { constructor(openmct, types) { diff --git a/src/containerView/plugin.js b/src/containerView/plugin.js index a959be55..fd53a601 100644 --- a/src/containerView/plugin.js +++ b/src/containerView/plugin.js @@ -1,6 +1,6 @@ -import FolderGridViewProvider from './FolderGridViewProvider'; -import FolderListViewProvider from './FolderListViewProvider'; -import BlankViewProvider from './BlankViewProvider'; +import FolderGridViewProvider from './FolderGridViewProvider.js'; +import FolderListViewProvider from './FolderListViewProvider.js'; +import BlankViewProvider from './BlankViewProvider.js'; const FOLDER_CONTAINER_TYPES = ['vista.dictionarySource']; diff --git a/src/customForms/UrlField/UrlFieldFormController.js b/src/customForms/UrlField/UrlFieldFormController.js index 45a0fae2..58523322 100644 --- a/src/customForms/UrlField/UrlFieldFormController.js +++ b/src/customForms/UrlField/UrlFieldFormController.js @@ -1,5 +1,5 @@ import UrlField from './UrlField.vue'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default function UrlFieldFormController(openmct) { let _destroy = null; diff --git a/src/customForms/plugin.js b/src/customForms/plugin.js index 2ec35e61..8fe9635d 100644 --- a/src/customForms/plugin.js +++ b/src/customForms/plugin.js @@ -1,4 +1,4 @@ -import UrlFieldFormController from './UrlField/UrlFieldFormController'; +import UrlFieldFormController from './UrlField/UrlFieldFormController.js'; export default function CustomFormsPlugin() { return function install(openmct) { diff --git a/src/dictionaryView/dictionaryViewProvider.js b/src/dictionaryView/dictionaryViewProvider.js index 8b29d6fb..3c617c39 100644 --- a/src/dictionaryView/dictionaryViewProvider.js +++ b/src/dictionaryView/dictionaryViewProvider.js @@ -1,6 +1,6 @@ import DictionaryView from './components/dictionaryView.vue'; import DictionaryViewTable from './dictionaryViewTable.js'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default class DictionaryViewProvider { constructor(openmct, options) { diff --git a/src/dictionaryView/dictionaryViewTable.js b/src/dictionaryView/dictionaryViewTable.js index df5482e8..b0b5ebd3 100644 --- a/src/dictionaryView/dictionaryViewTable.js +++ b/src/dictionaryView/dictionaryViewTable.js @@ -1,6 +1,6 @@ import TelemetryTable from 'openmct.tables.TelemetryTable'; import TelemetryTableRow from 'openmct.tables.TelemetryTableRow'; -import mcws from 'services/mcws/mcws'; +import mcws from 'services/mcws/mcws.js'; export default class DictionaryViewTable extends TelemetryTable { constructor(domainObject, openmct, options, metadata = []) { diff --git a/src/dictionaryView/plugin.js b/src/dictionaryView/plugin.js index b2daf050..945108dc 100644 --- a/src/dictionaryView/plugin.js +++ b/src/dictionaryView/plugin.js @@ -1,4 +1,4 @@ -import DictionaryViewProvider from './dictionaryViewProvider'; +import DictionaryViewProvider from './dictionaryViewProvider.js'; export default function plugin(options) { return function install(openmct) { diff --git a/src/evrView/EVRTable.js b/src/evrView/EVRTable.js index ca1625ab..73850f09 100644 --- a/src/evrView/EVRTable.js +++ b/src/evrView/EVRTable.js @@ -1,5 +1,5 @@ import TelemetryTable from 'openmct.tables.TelemetryTable'; -import EVRLevelIndicatorTableRow from './EVRLevelIndicatorTableRow'; +import EVRLevelIndicatorTableRow from './EVRLevelIndicatorTableRow.js'; export default class EVRTable extends TelemetryTable { initialize() { diff --git a/src/evrView/EVRViewLevelsConfigurationViewProvider.js b/src/evrView/EVRViewLevelsConfigurationViewProvider.js index cfe92102..36740363 100644 --- a/src/evrView/EVRViewLevelsConfigurationViewProvider.js +++ b/src/evrView/EVRViewLevelsConfigurationViewProvider.js @@ -1,5 +1,5 @@ import EVRViewLevelsConfigurationView from './EVRViewLevelsConfigurationView.vue'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default function EVRViewLevelsConfigurationViewProvider(openmct, options) { return { diff --git a/src/evrView/EVRViewProvider.js b/src/evrView/EVRViewProvider.js index c2c93742..379b2471 100644 --- a/src/evrView/EVRViewProvider.js +++ b/src/evrView/EVRViewProvider.js @@ -1,6 +1,6 @@ -import EVRTable from './EVRTable'; +import EVRTable from './EVRTable.js'; import TableComponent from 'openmct.tables.components.Table'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; const RESTRICTED_VIEWS = ['plot-single', 'table']; const EVR_SOURCES = ['evrHistoricalUrl', 'evrStreamUrl', 'evrLADUrl']; diff --git a/src/evrView/plugin.js b/src/evrView/plugin.js index b6d635cd..c0d0652f 100644 --- a/src/evrView/plugin.js +++ b/src/evrView/plugin.js @@ -1,6 +1,6 @@ -import EVRViewProvider from './EVRViewProvider'; -import EVRViewLevelsConfigurationViewProvider from './EVRViewLevelsConfigurationViewProvider'; -import VistaTableConfigurationProvider from '../tables/VistaTableConfigurationProvider'; +import EVRViewProvider from './EVRViewProvider.js'; +import EVRViewLevelsConfigurationViewProvider from './EVRViewLevelsConfigurationViewProvider.js'; +import VistaTableConfigurationProvider from '../tables/VistaTableConfigurationProvider.js'; export default function EVRViewPlugin(options) { const { taxonomy, tablePerformanceOptions } = options; diff --git a/src/exportDataAction/ExportDataAction.js b/src/exportDataAction/ExportDataAction.js index 976ab523..e25c3e89 100644 --- a/src/exportDataAction/ExportDataAction.js +++ b/src/exportDataAction/ExportDataAction.js @@ -1,6 +1,6 @@ -import ExportDataTask from './ExportDataTask'; -import SessionService from 'services/session/SessionService'; -import { formatNumberSequence } from 'ommUtils/strings'; +import ExportDataTask from './ExportDataTask.js'; +import SessionService from 'services/session/SessionService.js'; +import { formatNumberSequence } from 'ommUtils/strings.js'; /** * Implements the "Export Data" action, allowing data for Channels, EVRs, diff --git a/src/exportDataAction/plugin.js b/src/exportDataAction/plugin.js index 32777a45..9688f83c 100644 --- a/src/exportDataAction/plugin.js +++ b/src/exportDataAction/plugin.js @@ -1,4 +1,4 @@ -import ExportDataAction from './ExportDataAction'; +import ExportDataAction from './ExportDataAction.js'; export default function (validTypes) { return function (openmct) { diff --git a/src/formats/JSONStringFormat.js b/src/formats/JSONStringFormat.js index 2705a24a..9b46010b 100644 --- a/src/formats/JSONStringFormat.js +++ b/src/formats/JSONStringFormat.js @@ -1,27 +1,26 @@ -define(['lodash'], function (_) { - /** - * Format embedded JavaScript objects as JSON strings for debugging - * - * @implements {Format} - * @constructor - */ - function JSONStringFormat() { +/** + * Format embedded JavaScript objects as JSON strings for debugging + * + * @implements {Format} + */ +class JSONStringFormat { + constructor() { this.key = 'jsonString'; } - JSONStringFormat.prototype.format = function (value) { + format(value) { return JSON.stringify(value); - }; + } - JSONStringFormat.prototype.parse = function (stringValue) { + parse(stringValue) { if (typeof stringValue === 'string') { return JSON.parse(stringValue); } else { return stringValue; } - }; + } - JSONStringFormat.prototype.validate = function (stringValue) { + validate(stringValue) { try { JSON.parse(stringValue); return true; @@ -29,7 +28,7 @@ define(['lodash'], function (_) { console.error('Failed to parse %s', stringValue, error); return false; } - }; + } +} - return JSONStringFormat; -}); +export default JSONStringFormat; diff --git a/src/formats/LMSTFormat.js b/src/formats/LMSTFormat.js index c51afb8b..26851e91 100644 --- a/src/formats/LMSTFormat.js +++ b/src/formats/LMSTFormat.js @@ -1,61 +1,58 @@ -define(['moment'], function (moment) { - var MSL_EPOCH = moment.utc(Date.UTC(2012, 7, 5, 13, 49, 59)), - MARS_SECONDS_PER_EARTH_SECOND = 1.02749125; +import moment from 'moment'; - /** - * The LMSTDate formatter takes UTC dates and converts them to the correct - * martian sol. - * - * Martian sols are longer than earth days, so to simplify this and not - * break every currently existing time library and package, we consider a - * martian sol to be 24 hours, but the seconds are longer. - * - * Additionally, the martian epoch is defined differently for each mission. - * This formatter defines the martian epoch according to that set by the - * MSL team for Curiosity. - * - * Thus, it is assumed the numerical form of a SOL is a UTC date time, - * and the string form of a SOL is a string specific to a SOL. Any - * intermediate forms should not be trusted. - * - * The basic translation path for UTC -> SOL is: - * 1. Calculate earth seconds elapsed since SOL0 - * 2. Convert earth seconds elapsed to mars seconds elapsed - * 3. Convert mars seconds elapsed to SOL text format. - * - * Converting from a SOL -> UTC is done as follows: - * 1. Parse special SOL format string to determine mars seconds elapsed - * 2. Convert mars seconds elapsed to earth seconds elapsed. - * 3. Calculate UTC value by adding SOL0 to earth seconds elapsed. - * - * @implements {Format} - * @constructor - */ - function LMST(epoch) { - this.key = 'lmst'; - this.epoch = moment.utc(epoch) || MSL_EPOCH; +const MSL_EPOCH = moment.utc(Date.UTC(2012, 7, 5, 13, 49, 59)); +const MARS_SECONDS_PER_EARTH_SECOND = 1.02749125; - this.format = this.format.bind(this); - this.parse = this.parse.bind(this); - } - - LMST.prototype.FORMAT = '[SOL]-DDD[M]HH:mm:ss.SSS'; - LMST.prototype.TIME_FORMAT = '[M]HH:mm:ss.SSS'; - LMST.prototype.TIME_FORMATS = [ - LMST.prototype.TIME_FORMAT, +/** + * The LMSTDate formatter takes UTC dates and converts them to the correct + * martian sol. + * + * Martian sols are longer than earth days, so to simplify this and not + * break every currently existing time library and package, we consider a + * martian sol to be 24 hours, but the seconds are longer. + * + * Additionally, the martian epoch is defined differently for each mission. + * This formatter defines the martian epoch according to that set by the + * MSL team for Curiosity. + * + * Thus, it is assumed the numerical form of a SOL is a UTC date time, + * and the string form of a SOL is a string specific to a SOL. Any + * intermediate forms should not be trusted. + * + * The basic translation path for UTC -> SOL is: + * 1. Calculate earth seconds elapsed since SOL0 + * 2. Convert earth seconds elapsed to mars seconds elapsed + * 3. Convert mars seconds elapsed to SOL text format. + * + * Converting from a SOL -> UTC is done as follows: + * 1. Parse special SOL format string to determine mars seconds elapsed + * 2. Convert mars seconds elapsed to earth seconds elapsed. + * 3. Calculate UTC value by adding SOL0 to earth seconds elapsed. + * + * @implements {Format} + */ +class LMST { + static FORMAT = '[SOL]-DDD[M]HH:mm:ss.SSS'; + static TIME_FORMAT = '[M]HH:mm:ss.SSS'; + static TIME_FORMATS = [ + '[M]HH:mm:ss.SSS', '[M]HH:mm:ss.SSS', '[M]HH:mm:ss', '[M]HH:mm', '[M]HH' ]; + static PATTERN = /SOL-(\d+)([M]\d{2}:\d{2}:\d{2}\.\d{0,4})?/; - LMST.prototype.PATTERN = /SOL-(\d+)([M]\d{2}:\d{2}:\d{2}\.\d{0,4})?/; + constructor(epoch) { + this.key = 'lmst'; + this.epoch = moment.utc(epoch) || MSL_EPOCH; + } /** * @param {Number} utcValue a numerical representation of a utc date. * @returns {String} the utc date as a string representing MSL-SOL time. */ - LMST.prototype.format = function (utcValue) { + format(utcValue) { if (!utcValue) { return ''; } @@ -64,50 +61,50 @@ define(['moment'], function (moment) { return utcValue; } - var earthTimeElapsed = moment.utc(utcValue) - this.epoch, - marsTimeElapsed = earthTimeElapsed / MARS_SECONDS_PER_EARTH_SECOND, - solDecimal = marsTimeElapsed / moment.utc(0).add(1, 'day'), - sol = Math.floor(solDecimal), - timeDecimal = solDecimal - sol, - time = moment.utc(timeDecimal * moment.utc(0).add(1, 'day')); + const earthTimeElapsed = moment.utc(utcValue) - this.epoch; + const marsTimeElapsed = earthTimeElapsed / MARS_SECONDS_PER_EARTH_SECOND; + const solDecimal = marsTimeElapsed / moment.utc(0).add(1, 'day'); + const sol = Math.floor(solDecimal); + const timeDecimal = solDecimal - sol; + const time = moment.utc(timeDecimal * moment.utc(0).add(1, 'day')); - sol = String(sol); - while (sol.length < 4) { - sol = '0' + sol; + let solString = String(sol); + while (solString.length < 4) { + solString = '0' + solString; } - return 'SOL-' + sol + time.format(this.TIME_FORMAT); - }; + return 'SOL-' + solString + time.format(LMST.TIME_FORMAT); + } /** * * @param {String} solDate a string sol date e.g. SOL-0000T12:00:00. * @returns {Number} the utc datetime equivalent of the sol. */ - LMST.prototype.parse = function (text) { + parse(text) { if (!this.validate(text)) { return undefined; } - var matches = this.PATTERN.exec(text), - sol = matches[1], - time = matches[2], - solValue = moment.utc(0).add(sol, 'days'), - timeValue = time ? moment.utc(time, this.TIME_FORMATS) : moment.utc(0), - marsTimeElapsed = solValue.add({ - hours: timeValue.hours(), - minutes: timeValue.minutes(), - seconds: timeValue.seconds(), - milliseconds: timeValue.milliseconds() - }), - earthTimeElapsed = marsTimeElapsed * MARS_SECONDS_PER_EARTH_SECOND, - value = this.epoch + Math.round(earthTimeElapsed); + const matches = LMST.PATTERN.exec(text); + const sol = matches[1]; + const time = matches[2]; + const solValue = moment.utc(0).add(sol, 'days'); + const timeValue = time ? moment.utc(time, LMST.TIME_FORMATS) : moment.utc(0); + const marsTimeElapsed = solValue.add({ + hours: timeValue.hours(), + minutes: timeValue.minutes(), + seconds: timeValue.seconds(), + milliseconds: timeValue.milliseconds() + }); + const earthTimeElapsed = marsTimeElapsed * MARS_SECONDS_PER_EARTH_SECOND; + const value = this.epoch + Math.round(earthTimeElapsed); return value; - }; + } - LMST.prototype.validate = function (text) { - return this.PATTERN.test(text); - }; + validate(text) { + return LMST.PATTERN.test(text); + } +} - return LMST; -}); +export default LMST; diff --git a/src/formats/MSLSOLFormat.js b/src/formats/MSLSOLFormat.js index 7e0bcd56..147e50c4 100644 --- a/src/formats/MSLSOLFormat.js +++ b/src/formats/MSLSOLFormat.js @@ -1,6 +1,7 @@ -define(['moment'], function (moment) { - var MSL_EPOCH = moment.utc(Date.UTC(2012, 7, 5, 13, 49, 59)), - MARS_SECONDS_PER_EARTH_SECOND = 1.02749125; +import moment from 'moment'; + +const MSL_EPOCH = moment.utc(Date.UTC(2012, 7, 5, 13, 49, 59)); +const MARS_SECONDS_PER_EARTH_SECOND = 1.02749125; /** * The MSLSolDate formatter takes UTC dates and converts them to the correct @@ -29,29 +30,28 @@ define(['moment'], function (moment) { * 3. Calculate UTC value by adding SOL0 to earth seconds elapsed. * * @implements {Format} - * @constructor */ - function MSLSOLFormat() { - this.key = 'msl.sol'; - } - - MSLSOLFormat.prototype.FORMAT = '[SOL]-DDD[M]HH:mm:ss.SSS'; - MSLSOLFormat.prototype.TIME_FORMAT = '[M]HH:mm:ss.SSS'; - MSLSOLFormat.prototype.TIME_FORMATS = [ - MSLSOLFormat.prototype.TIME_FORMAT, +class MSLSOLFormat { + static FORMAT = '[SOL]-DDD[M]HH:mm:ss.SSS'; + static TIME_FORMAT = '[M]HH:mm:ss.SSS'; + static TIME_FORMATS = [ + '[M]HH:mm:ss.SSS', '[M]HH:mm:ss.SSS', '[M]HH:mm:ss', '[M]HH:mm', '[M]HH' ]; + static PATTERN = /SOL-(\d+)([M]\d{2}:\d{2}:\d{2}\.\d{0,4})?/; - MSLSOLFormat.prototype.PATTERN = /SOL-(\d+)([M]\d{2}:\d{2}:\d{2}\.\d{0,4})?/; + constructor() { + this.key = 'msl.sol'; + } /** * @param {Number} utcValue a numerical representation of a utc date. * @returns {String} the utc date as a string representing MSL-SOL time. */ - MSLSOLFormat.prototype.format = function (utcValue) { + format(utcValue) { if (!utcValue) { return ''; } @@ -60,50 +60,50 @@ define(['moment'], function (moment) { return utcValue; } - var earthTimeElapsed = moment.utc(utcValue) - MSL_EPOCH, - marsTimeElapsed = earthTimeElapsed / MARS_SECONDS_PER_EARTH_SECOND, - solDecimal = marsTimeElapsed / moment.utc(0).add(1, 'day'), - sol = Math.floor(solDecimal), - timeDecimal = solDecimal - sol, - time = moment.utc(timeDecimal * moment.utc(0).add(1, 'day')); + const earthTimeElapsed = moment.utc(utcValue) - MSL_EPOCH; + const marsTimeElapsed = earthTimeElapsed / MARS_SECONDS_PER_EARTH_SECOND; + const solDecimal = marsTimeElapsed / moment.utc(0).add(1, 'day'); + const sol = Math.floor(solDecimal); + const timeDecimal = solDecimal - sol; + const time = moment.utc(timeDecimal * moment.utc(0).add(1, 'day')); - sol = String(sol); - while (sol.length < 4) { - sol = '0' + sol; + let solString = String(sol); + while (solString.length < 4) { + solString = '0' + solString; } - return 'SOL-' + sol + time.format(this.TIME_FORMAT); - }; + return 'SOL-' + solString + time.format(MSLSOLFormat.TIME_FORMAT); + } /** * * @param {String} solDate a string sol date e.g. SOL-0000T12:00:00. * @returns {Number} the utc datetime equivalent of the sol. */ - MSLSOLFormat.prototype.parse = function (text) { + parse(text) { if (!this.validate(text)) { return undefined; } - var matches = this.PATTERN.exec(text), - sol = matches[1], - time = matches[2], - solValue = moment.utc(0).add(sol, 'days'), - timeValue = time ? moment.utc(time, this.TIME_FORMATS) : moment.utc(0), - marsTimeElapsed = solValue.add({ + const matches = MSLSOLFormat.PATTERN.exec(text); + const sol = matches[1]; + const time = matches[2]; + const solValue = moment.utc(0).add(sol, 'days'); + const timeValue = time ? moment.utc(time, MSLSOLFormat.TIME_FORMATS) : moment.utc(0); + const marsTimeElapsed = solValue.add({ hours: timeValue.hours(), minutes: timeValue.minutes(), seconds: timeValue.seconds(), milliseconds: timeValue.milliseconds() - }), - earthTimeElapsed = marsTimeElapsed * MARS_SECONDS_PER_EARTH_SECOND, - value = MSL_EPOCH + Math.round(earthTimeElapsed); + }); + const earthTimeElapsed = marsTimeElapsed * MARS_SECONDS_PER_EARTH_SECOND; + const value = MSL_EPOCH + Math.round(earthTimeElapsed); return value; - }; + } - MSLSOLFormat.prototype.validate = function (text) { - return this.PATTERN.test(text); - }; + validate(text) { + return MSLSOLFormat.PATTERN.test(text); + } +} - return MSLSOLFormat; -}); +export default MSLSOLFormat; diff --git a/src/formats/SCLKFloat64Format.js b/src/formats/SCLKFloat64Format.js index a76d9d85..f8ccc691 100644 --- a/src/formats/SCLKFloat64Format.js +++ b/src/formats/SCLKFloat64Format.js @@ -1,26 +1,26 @@ -define(['lodash'], function (_) { - /** - * Format for SCLK values as 64 bit float. - * - * @implements {Format} - * @constructor - */ - function SCLKFloat64Format() { +/** + * Format for SCLK values as 64 bit float. + * + * @implements {Format} + */ +class SCLKFloat64Format { + constructor() { this.key = 'sclk.float64'; } - SCLKFloat64Format.prototype.format = function (value) { + format(value) { return value && value.toString ? value.toString() : ''; - }; + } - SCLKFloat64Format.prototype.parse = function (stringValue) { + parse(stringValue) { return parseFloat(stringValue); - }; + } - SCLKFloat64Format.prototype.validate = function (stringValue) { - var floatValue = this.parse(stringValue); - return !_.isNaN(floatValue); - }; + validate(stringValue) { + const floatValue = this.parse(stringValue); + + return !Number.isNaN(floatValue); + } +} - return SCLKFloat64Format; -}); +export default SCLKFloat64Format; diff --git a/src/formats/UTCDayOfYearFormat.js b/src/formats/UTCDayOfYearFormat.js index 2ed1c320..f884a9c1 100644 --- a/src/formats/UTCDayOfYearFormat.js +++ b/src/formats/UTCDayOfYearFormat.js @@ -1,5 +1,5 @@ import moment from 'moment'; -import { DOY_PATTERN, inlineParseDOYString } from './utils/DOY'; +import { DOY_PATTERN, inlineParseDOYString } from './utils/DOY.js'; /** * Returns an appropriate time format based on the provided value and diff --git a/src/formats/UTCFormat.js b/src/formats/UTCFormat.js index e27bc213..932b17f4 100644 --- a/src/formats/UTCFormat.js +++ b/src/formats/UTCFormat.js @@ -1,5 +1,5 @@ import moment from 'moment'; -import { DOY_PATTERN, inlineParseDOYString } from './utils/DOY'; +import { DOY_PATTERN, inlineParseDOYString } from './utils/DOY.js'; /** * Returns an appropriate time format based on the provided value and diff --git a/src/formats/plugin.js b/src/formats/plugin.js index 840049ad..5dcc0639 100644 --- a/src/formats/plugin.js +++ b/src/formats/plugin.js @@ -1,28 +1,19 @@ -define([ - './MSLSOLFormat', - './LMSTFormat', - './SCLKFloat64Format', - './UTCDayOfYearFormat', - './UTCFormat', - './JSONStringFormat' -], function ( - MSLSOLFormat, - LMSTFormat, - SCLKFloat64Format, - UTCDayOfYearFormat, - UTCFormat, - JSONStringFormat -) { - function FormatPlugin(options) { - return function install(openmct) { - openmct.telemetry.addFormat(new UTCDayOfYearFormat.default()); - openmct.telemetry.addFormat(new UTCFormat.default()); - openmct.telemetry.addFormat(new MSLSOLFormat()); - openmct.telemetry.addFormat(new LMSTFormat()); - openmct.telemetry.addFormat(new SCLKFloat64Format()); - openmct.telemetry.addFormat(new JSONStringFormat()); - }; - } +import MSLSOLFormat from './MSLSOLFormat.js'; +import LMSTFormat from './LMSTFormat.js'; +import SCLKFloat64Format from './SCLKFloat64Format.js'; +import UTCDayOfYearFormat from './UTCDayOfYearFormat.js'; +import UTCFormat from './UTCFormat.js'; +import JSONStringFormat from './JSONStringFormat.js'; - return FormatPlugin; -}); +function FormatPlugin(options) { + return function install(openmct) { + openmct.telemetry.addFormat(new UTCDayOfYearFormat()); + openmct.telemetry.addFormat(new UTCFormat()); + openmct.telemetry.addFormat(new MSLSOLFormat()); + openmct.telemetry.addFormat(new LMSTFormat()); + openmct.telemetry.addFormat(new SCLKFloat64Format()); + openmct.telemetry.addFormat(new JSONStringFormat()); + }; +} + +export default FormatPlugin; diff --git a/src/frameEventFilterView/FrameEventFilterViewProvider.js b/src/frameEventFilterView/FrameEventFilterViewProvider.js index 2dc72382..30a840e3 100644 --- a/src/frameEventFilterView/FrameEventFilterViewProvider.js +++ b/src/frameEventFilterView/FrameEventFilterViewProvider.js @@ -1,6 +1,6 @@ import FrameEventFilterTable from './FrameEventFilterTable.js'; import TableComponent from 'openmct.tables.components.Table'; -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; export default class FrameEventFilterViewProvider { constructor(openmct, options) { diff --git a/src/frameaccountability/components/frameAccountability.js b/src/frameaccountability/components/frameAccountability.js index cab1534a..b91a0565 100644 --- a/src/frameaccountability/components/frameAccountability.js +++ b/src/frameaccountability/components/frameAccountability.js @@ -1,230 +1,222 @@ -define([ - './res/frameAccountability.html', - './frameAccountabilityNode', - './frameAccountabilityBadFrames.vue', - '../sortedEventsCollection', - 'saveAs' -], function ( - FrameAccountabilityTemplate, - frameAccountabilityNode, - frameAccountabilityBadFrames, - SortedEventsCollection, - saveAsObject -) { - return { - template: FrameAccountabilityTemplate, - inject: ['openmct', 'domainObject', 'table', 'FLAG_COLORS', 'expectedVcidList'], - components: { - frameAccountabilityNode, - frameAccountabilityBadFrames: frameAccountabilityBadFrames.default - }, - data() { - return { - vcids: [], - vcidsWithBadFrames: {}, - events: {}, - subscriptions: {}, - badFrames: [], - sortedEventsCollections: {}, - vcid: undefined, - frameEventValueMetadatas: undefined, - commandEventValueMetadatas: undefined, - unexpectedVcids: {} - }; +import FrameAccountabilityTemplate from './res/frameAccountability.html'; +import frameAccountabilityNode from './frameAccountabilityNode.js'; +import frameAccountabilityBadFrames from './frameAccountabilityBadFrames.vue'; +import SortedEventsCollection from '../sortedEventsCollection.js'; +import { saveAs } from 'file-saver'; + +export default { + template: FrameAccountabilityTemplate, + inject: ['openmct', 'domainObject', 'table', 'FLAG_COLORS', 'expectedVcidList'], + components: { + frameAccountabilityNode, + frameAccountabilityBadFrames: frameAccountabilityBadFrames + }, + data() { + return { + vcids: [], + vcidsWithBadFrames: {}, + events: {}, + subscriptions: {}, + badFrames: [], + sortedEventsCollections: {}, + vcid: undefined, + frameEventValueMetadatas: undefined, + commandEventValueMetadatas: undefined, + unexpectedVcids: {} + }; + }, + methods: { + addEvents(domainObject) { + if (domainObject.type === 'vista.frameEvent') { + this.addFrameEvents(domainObject); + } else if (domainObject.type === 'vista.commandEvents') { + this.addCommandEvents(domainObject); + } }, - methods: { - addEvents(domainObject) { - if (domainObject.type === 'vista.frameEvent') { - this.addFrameEvents(domainObject); - } else if (domainObject.type === 'vista.commandEvents') { - this.addCommandEvents(domainObject); - } - }, - removeEvents(identifier) { - const keyString = this.openmct.objects.makeKeyString(identifier); + removeEvents(identifier) { + const keyString = this.openmct.objects.makeKeyString(identifier); - if (this.subscriptions[keyString] && typeof this.subscriptions[keyString] === 'function') { - this.subscriptions[keyString](); - delete this.subscriptions[keyString]; - } - }, - addCommandEvents(domainObject) { - if (!this.commandEventMetadata || !this.commandEventFormats) { - this.commandEventMetadata = this.openmct.telemetry.getMetadata(domainObject); - this.commandEventFormats = this.openmct.telemetry.getFormatMap(this.commandEventMetadata); - this.commandEventValueMetadatas = this.commandEventMetadata.valueMetadatas; - } - - const unsubscribe = this.openmct.telemetry.subscribe( - domainObject, - this.processRealtimeDatum('commandEvent') - ); - const keyString = this.openmct.objects.makeKeyString(domainObject.identifier); - - this.subscriptions[keyString] = unsubscribe; - }, - addFrameEvents(domainObject) { - if (!this.frameEventMetadata || !this.frameEventFormats) { - this.frameEventMetadata = this.openmct.telemetry.getMetadata(domainObject); - this.frameEventFormats = this.openmct.telemetry.getFormatMap(this.frameEventMetadata); - this.frameEventValueMetadatas = this.frameEventMetadata.valueMetadatas; - - this.table.metadata = this.frameEventValueMetadatas; - this.table.addColumnsForObject(domainObject); - } + if (this.subscriptions[keyString] && typeof this.subscriptions[keyString] === 'function') { + this.subscriptions[keyString](); + delete this.subscriptions[keyString]; + } + }, + addCommandEvents(domainObject) { + if (!this.commandEventMetadata || !this.commandEventFormats) { + this.commandEventMetadata = this.openmct.telemetry.getMetadata(domainObject); + this.commandEventFormats = this.openmct.telemetry.getFormatMap(this.commandEventMetadata); + this.commandEventValueMetadatas = this.commandEventMetadata.valueMetadatas; + } - const unsubscribe = this.openmct.telemetry.subscribe( - domainObject, - this.processRealtimeDatum('frameEvent') - ); - const keyString = this.openmct.objects.makeKeyString(domainObject.identifier); - - this.subscriptions[keyString] = unsubscribe; - }, - processRealtimeDatum(eventType) { - return (datum) => { - let event = this.standardizeEvent(eventType, datum); - - if (eventType === 'frameEvent') { - this.processFrameEvent(event); - } else if (eventType === 'commandEvent') { - this.processCommandEvent(event); - } - }; - }, - standardizeEvent(eventType, datum) { - let event = { type: eventType }; + const unsubscribe = this.openmct.telemetry.subscribe( + domainObject, + this.processRealtimeDatum('commandEvent') + ); + const keyString = this.openmct.objects.makeKeyString(domainObject.identifier); - this[`${eventType}ValueMetadatas`].forEach((valueMetadata) => { - const key = valueMetadata.key; - const source = valueMetadata.source; + this.subscriptions[keyString] = unsubscribe; + }, + addFrameEvents(domainObject) { + if (!this.frameEventMetadata || !this.frameEventFormats) { + this.frameEventMetadata = this.openmct.telemetry.getMetadata(domainObject); + this.frameEventFormats = this.openmct.telemetry.getFormatMap(this.frameEventMetadata); + this.frameEventValueMetadatas = this.frameEventMetadata.valueMetadatas; + + this.table.metadata = this.frameEventValueMetadatas; + this.table.addColumnsForObject(domainObject); + } - event[source] = this[`${eventType}Formats`][key].format(datum[source]); - }); + const unsubscribe = this.openmct.telemetry.subscribe( + domainObject, + this.processRealtimeDatum('frameEvent') + ); + const keyString = this.openmct.objects.makeKeyString(domainObject.identifier); - return event; - }, - processCommandEvent(commandEvent) { - this.processVCID(commandEvent.vcid); - this.addToSortedCollection(commandEvent); - }, - processFrameEvent(frameEvent) { - this.processVCID(frameEvent.vcid); - - if (frameEvent.message_type === 'BadTelemetryFrame') { - this.processBadTelemetryFrame(frameEvent); + this.subscriptions[keyString] = unsubscribe; + }, + processRealtimeDatum(eventType) { + return (datum) => { + let event = this.standardizeEvent(eventType, datum); + + if (eventType === 'frameEvent') { + this.processFrameEvent(event); + } else if (eventType === 'commandEvent') { + this.processCommandEvent(event); } + }; + }, + standardizeEvent(eventType, datum) { + let event = { type: eventType }; - this.addToSortedCollection(frameEvent); - }, - processVCID(vcid) { - if (!this.vcids.includes(vcid)) { - this.vcids.push(vcid); + this[`${eventType}ValueMetadatas`].forEach((valueMetadata) => { + const key = valueMetadata.key; + const source = valueMetadata.source; - if (!this.expectedVcidList.includes(Number(vcid))) { - this.unexpectedVcids[vcid] = true; - } - } - }, - processBadTelemetryFrame(frameEvent) { - if (this.vcid && this.vcid === frameEvent.vcid) { - this.badFrames.push(frameEvent); - } - if (!this.vcidsWithBadFrames[frameEvent.vcid]) { - this.vcidsWithBadFrames[frameEvent.vcid] = true; - } - }, - addToSortedCollection(event) { - const vcid = event.vcid; + event[source] = this[`${eventType}Formats`][key].format(datum[source]); + }); - if (this.sortedEventsCollections[vcid] === undefined) { - this.createEventsCollection(vcid); - } + return event; + }, + processCommandEvent(commandEvent) { + this.processVCID(commandEvent.vcid); + this.addToSortedCollection(commandEvent); + }, + processFrameEvent(frameEvent) { + this.processVCID(frameEvent.vcid); - this.sortedEventsCollections[vcid].addRows([event]); - }, - createEventsCollection(vcid) { - const collection = new SortedEventsCollection.default(); - - collection.on('add', this.updateFramesCollection(vcid)); - this.sortedEventsCollections[vcid] = collection; - }, - updateFramesCollection(vcid) { - return (datum) => { - const collection = this.sortedEventsCollections[vcid]; - - this.events[vcid] = - this.events[vcid] !== undefined ? collection.getRows() : [collection.getRows()]; - }; - }, - lastChild(vcid) { - let children = this.events[vcid]; - - return children[children.length - 1]; - }, - hasBadFrames(vcid) { - return this.vcidsWithBadFrames[vcid]; - }, - showBadFrames(vcid) { - this.vcid = vcid; - this.badFrames = this.events[this.vcid].filter((event) => { - return event.type === 'frameEvent' && event.message_type === 'BadTelemetryFrame'; - }); - }, - hideBadFrames() { - this.vcid = undefined; - this.badFrames = []; - }, - exportAsText() { - let textOutput = ''; - - this.vcids.forEach((vcid) => { - textOutput += 'VC-' + vcid + ' ' + 'Events' + '\n'; - - this.events[vcid].forEach((event, index, array) => { - if (event.type === 'frameEvent') { - textOutput += - '\t' + event.event_time + ': ' + event.message_type + ' : Frame Event' + '\n'; - textOutput += '\t\t' + event.summary + '\n'; - } else if (event.type === 'commandEvent') { - textOutput += - '\t' + event.event_time + ': ' + event.status + ' : Command Event' + '\n'; - textOutput += '\t\t' + event.status + '\n'; - } - - if (index === array.length - 1) { - textOutput += '\n'; - } - }); - }); + if (frameEvent.message_type === 'BadTelemetryFrame') { + this.processBadTelemetryFrame(frameEvent); + } - let blob = new Blob([textOutput], { type: 'text' }), - filename = this.domainObject.name + '- Text Output'; + this.addToSortedCollection(frameEvent); + }, + processVCID(vcid) { + if (!this.vcids.includes(vcid)) { + this.vcids.push(vcid); - saveAsObject.saveAs(blob, filename); - }, - isVcidUnexpected(vcid) { - return true; + if (!this.expectedVcidList.includes(Number(vcid))) { + this.unexpectedVcids[vcid] = true; + } } }, - mounted() { - this.composition = this.openmct.composition.get(this.domainObject); - this.composition.on('add', this.addEvents); - this.composition.on('remove', this.removeEvents); - this.composition.load(); + processBadTelemetryFrame(frameEvent) { + if (this.vcid && this.vcid === frameEvent.vcid) { + this.badFrames.push(frameEvent); + } + if (!this.vcidsWithBadFrames[frameEvent.vcid]) { + this.vcidsWithBadFrames[frameEvent.vcid] = true; + } }, - beforeUnmount() { - this.composition.off('add', this.addEvents); - this.composition.off('remove', this.removeEvents); + addToSortedCollection(event) { + const vcid = event.vcid; - Object.entries(this.sortedEventsCollections).forEach(([vcid, collection]) => { - collection.off('add', this.updateFramesCollection(vcid)); - delete this.sortedEventsCollections[vcid]; + if (this.sortedEventsCollections[vcid] === undefined) { + this.createEventsCollection(vcid); + } + + this.sortedEventsCollections[vcid].addRows([event]); + }, + createEventsCollection(vcid) { + const collection = new SortedEventsCollection(); + + collection.on('add', this.updateFramesCollection(vcid)); + this.sortedEventsCollections[vcid] = collection; + }, + updateFramesCollection(vcid) { + return (datum) => { + const collection = this.sortedEventsCollections[vcid]; + + this.events[vcid] = + this.events[vcid] !== undefined ? collection.getRows() : [collection.getRows()]; + }; + }, + lastChild(vcid) { + let children = this.events[vcid]; + + return children[children.length - 1]; + }, + hasBadFrames(vcid) { + return this.vcidsWithBadFrames[vcid]; + }, + showBadFrames(vcid) { + this.vcid = vcid; + this.badFrames = this.events[this.vcid].filter((event) => { + return event.type === 'frameEvent' && event.message_type === 'BadTelemetryFrame'; }); + }, + hideBadFrames() { + this.vcid = undefined; + this.badFrames = []; + }, + exportAsText() { + let textOutput = ''; + + this.vcids.forEach((vcid) => { + textOutput += 'VC-' + vcid + ' ' + 'Events' + '\n'; + + this.events[vcid].forEach((event, index, array) => { + if (event.type === 'frameEvent') { + textOutput += + '\t' + event.event_time + ': ' + event.message_type + ' : Frame Event' + '\n'; + textOutput += '\t\t' + event.summary + '\n'; + } else if (event.type === 'commandEvent') { + textOutput += + '\t' + event.event_time + ': ' + event.status + ' : Command Event' + '\n'; + textOutput += '\t\t' + event.status + '\n'; + } - Object.values(this.subscriptions).forEach((unsubscribe) => { - unsubscribe(); + if (index === array.length - 1) { + textOutput += '\n'; + } + }); }); + + let blob = new Blob([textOutput], { type: 'text' }), + filename = this.domainObject.name + '- Text Output'; + + saveAs(blob, filename); + }, + isVcidUnexpected(vcid) { + return true; } - }; -}); + }, + mounted() { + this.composition = this.openmct.composition.get(this.domainObject); + this.composition.on('add', this.addEvents); + this.composition.on('remove', this.removeEvents); + this.composition.load(); + }, + beforeUnmount() { + this.composition.off('add', this.addEvents); + this.composition.off('remove', this.removeEvents); + + Object.entries(this.sortedEventsCollections).forEach(([vcid, collection]) => { + collection.off('add', this.updateFramesCollection(vcid)); + delete this.sortedEventsCollections[vcid]; + }); + + Object.values(this.subscriptions).forEach((unsubscribe) => { + unsubscribe(); + }); + } +}; diff --git a/src/frameaccountability/components/frameAccountabilityNode.js b/src/frameaccountability/components/frameAccountabilityNode.js index 27238478..c077e5d6 100644 --- a/src/frameaccountability/components/frameAccountabilityNode.js +++ b/src/frameaccountability/components/frameAccountabilityNode.js @@ -1,57 +1,57 @@ -define(['./res/frameAccountabilityNode.html'], function (vcidTemplate) { - const PAGE_THRESHOLD = 50; +import vcidTemplate from './res/frameAccountabilityNode.html'; - return { - name: 'frame-accountability-node', - template: vcidTemplate, - inject: ['FLAG_COLORS'], - props: [ - 'title', - 'iconClass', - 'flagColor', - 'children', - 'finalChild', - 'vcid', - 'showBadFramesLink', - 'unknownVCID' - ], - data() { - return { - expanded: false, - lazyLoadingIndex: 1 - }; +const PAGE_THRESHOLD = 50; + +export default { + name: 'frame-accountability-node', + template: vcidTemplate, + inject: ['FLAG_COLORS'], + props: [ + 'title', + 'iconClass', + 'flagColor', + 'children', + 'finalChild', + 'vcid', + 'showBadFramesLink', + 'unknownVCID' + ], + data() { + return { + expanded: false, + lazyLoadingIndex: 1 + }; + }, + computed: { + maxChildren() { + return PAGE_THRESHOLD * this.lazyLoadingIndex; }, - computed: { - maxChildren() { - return PAGE_THRESHOLD * this.lazyLoadingIndex; - }, - lazyLoadedChildren() { - return this.children.slice(0, this.maxChildren); - }, - numHiddenChildren() { - if (this.children.length > this.maxChildren) { - return this.children.length - this.maxChildren; - } else { - return 0; - } - } + lazyLoadedChildren() { + return this.children.slice(0, this.maxChildren); }, - methods: { - toggleExpand() { - if (this.expanded) { - this.lazyLoadingIndex = 1; - } + numHiddenChildren() { + if (this.children.length > this.maxChildren) { + return this.children.length - this.maxChildren; + } else { + return 0; + } + } + }, + methods: { + toggleExpand() { + if (this.expanded) { + this.lazyLoadingIndex = 1; + } - this.expanded = !this.expanded; - }, - loadMore() { - if (this.numHiddenChildren > 0) { - this.lazyLoadingIndex++; - } - }, - emitShowBadFrames() { - this.$emit('show-bad-frames', this.vcid); + this.expanded = !this.expanded; + }, + loadMore() { + if (this.numHiddenChildren > 0) { + this.lazyLoadingIndex++; } + }, + emitShowBadFrames() { + this.$emit('show-bad-frames', this.vcid); } - }; -}); + } +}; diff --git a/src/frameaccountability/frameAccountabilityViewProvider.js b/src/frameaccountability/frameAccountabilityViewProvider.js index dd5014ad..70802b6b 100644 --- a/src/frameaccountability/frameAccountabilityViewProvider.js +++ b/src/frameaccountability/frameAccountabilityViewProvider.js @@ -1,6 +1,6 @@ -import frameAccountability from './components/frameAccountability'; -import BadFramesTelemetryTable from './BadFramesTelemetryTable'; -import mount from 'ommUtils/mountVueComponent'; +import frameAccountability from './components/frameAccountability.js'; +import BadFramesTelemetryTable from './BadFramesTelemetryTable.js'; +import mount from 'ommUtils/mountVueComponent.js'; const FLAG_COLORS = { InSync: '#7FFF00', diff --git a/src/frameaccountability/plugin.js b/src/frameaccountability/plugin.js index 72fa7ed4..289e5f08 100644 --- a/src/frameaccountability/plugin.js +++ b/src/frameaccountability/plugin.js @@ -1,5 +1,5 @@ -import FrameAccountabilityViewProvider from './frameAccountabilityViewProvider'; -import FrameAccountabilityCompositionPolicy from './frameAccountabilityCompositionPolicy'; +import FrameAccountabilityViewProvider from './frameAccountabilityViewProvider.js'; +import FrameAccountabilityCompositionPolicy from './frameAccountabilityCompositionPolicy.js'; export default function install(options) { return function FrameAccountabilityPlugin(openmct) { diff --git a/src/framesummary/FrameWatchColumn.js b/src/framesummary/FrameWatchColumn.js index 3c574a65..4f735770 100644 --- a/src/framesummary/FrameWatchColumn.js +++ b/src/framesummary/FrameWatchColumn.js @@ -1,38 +1,34 @@ -define(function () { - class FrameWatchColumn { - constructor(key, title) { - this.key = key; - this.title = title; - } - - getKey() { - return this.key; - } +export default class FrameWatchColumn { + constructor(key, title) { + this.key = key; + this.title = title; + } - getTitle() { - return this.title; - } + getKey() { + return this.key; + } - getMetadatum() { - return undefined; - } + getTitle() { + return this.title; + } - hasValueForDatum(telemetryDatum) { - return Object.hasOwn(telemetryDatum, this.key); - } + getMetadatum() { + return undefined; + } - getRawValue(telemetryDatum) { - return telemetryDatum[this.key]; - } + hasValueForDatum(telemetryDatum) { + return Object.hasOwn(telemetryDatum, this.key); + } - getFormattedValue(telemetryValue) { - return telemetryValue; - } + getRawValue(telemetryDatum) { + return telemetryDatum[this.key]; + } - getParsedValue(telemetryValue) { - return telemetryValue; - } + getFormattedValue(telemetryValue) { + return telemetryValue; } - return FrameWatchColumn; -}); + getParsedValue(telemetryValue) { + return telemetryValue; + } +} diff --git a/src/framesummary/FrameWatchConfigurationViewProvider.js b/src/framesummary/FrameWatchConfigurationViewProvider.js index 72b64669..e7935607 100644 --- a/src/framesummary/FrameWatchConfigurationViewProvider.js +++ b/src/framesummary/FrameWatchConfigurationViewProvider.js @@ -1,5 +1,5 @@ -import mount from 'ommUtils/mountVueComponent'; -import FrameWatchTableConfiguration from './FrameWatchTableConfiguration'; +import mount from 'ommUtils/mountVueComponent.js'; +import FrameWatchTableConfiguration from './FrameWatchTableConfiguration.js'; import TableConfigurationComponent from 'openmct.tables.components.TableConfiguration'; export default class FrameWatchConfigurationViewProvider { diff --git a/src/framesummary/FrameWatchTableConfiguration.js b/src/framesummary/FrameWatchTableConfiguration.js index 89245797..7c34ba47 100644 --- a/src/framesummary/FrameWatchTableConfiguration.js +++ b/src/framesummary/FrameWatchTableConfiguration.js @@ -1,6 +1,6 @@ import TelemetryTableConfiguration from 'openmct.tables.TelemetryTableConfiguration'; -import { config } from './config'; -import FrameWatchColumn from './FrameWatchColumn'; +import { config } from './config.js'; +import FrameWatchColumn from './FrameWatchColumn.js'; export default class FrameWatchTableConfiguration extends TelemetryTableConfiguration { constructor(domainObject, openmct, options, type) { diff --git a/src/framesummary/FrameWatchViewProvider.js b/src/framesummary/FrameWatchViewProvider.js index aec5f9b6..d18646c7 100644 --- a/src/framesummary/FrameWatchViewProvider.js +++ b/src/framesummary/FrameWatchViewProvider.js @@ -1,7 +1,7 @@ -import mount from 'ommUtils/mountVueComponent'; -import FrameWatchTable from './FrameWatchTable'; +import mount from 'ommUtils/mountVueComponent.js'; +import FrameWatchTable from './FrameWatchTable.js'; import FrameWatchViewComponent from './components/FrameWatchViewComponent.vue'; -import { FRAME_WATCH_TYPE } from './config'; +import { FRAME_WATCH_TYPE } from './config.js'; export default class FrameWatchViewProvider { constructor(openmct, key, name, options, type = FRAME_WATCH_TYPE) { diff --git a/src/framesummary/config.js b/src/framesummary/config.js index d42cdd4e..50264b5f 100644 --- a/src/framesummary/config.js +++ b/src/framesummary/config.js @@ -1,4 +1,4 @@ -import padStart from 'lodash/padStart'; +import padStart from 'lodash'; export const ENCODING_WATCH_TYPE = 'vista.encodingWatch'; export const FRAME_WATCH_TYPE = 'vista.frameWatch'; diff --git a/src/framesummary/encodingwatch/EncodingWatchRow.js b/src/framesummary/encodingwatch/EncodingWatchRow.js index 0ef55853..6f730ee2 100644 --- a/src/framesummary/encodingwatch/EncodingWatchRow.js +++ b/src/framesummary/encodingwatch/EncodingWatchRow.js @@ -1,6 +1,6 @@ -import FrameWatchRow from '../FrameWatchRow'; -import DatasetCache from 'services/dataset/DatasetCache'; -import Types from '../../types/types'; +import FrameWatchRow from '../FrameWatchRow.js'; +import DatasetCache from 'services/dataset/DatasetCache.js'; +import Types from '../../types/types.js'; export default class EncodingWatchRow extends FrameWatchRow { constructor(datum, columns, objectKeyString, limitEvaluator, rowId, frameEventType) { diff --git a/src/framesummary/plugin.js b/src/framesummary/plugin.js index df51ab2c..1dd8f4b5 100644 --- a/src/framesummary/plugin.js +++ b/src/framesummary/plugin.js @@ -1,6 +1,6 @@ -import FrameWatchViewProvider from './FrameWatchViewProvider'; -import FrameWatchConfigurationViewProvider from './FrameWatchConfigurationViewProvider'; -import { ENCODING_WATCH_TYPE, FRAME_WATCH_TYPE } from './config'; +import FrameWatchViewProvider from './FrameWatchViewProvider.js'; +import FrameWatchConfigurationViewProvider from './FrameWatchConfigurationViewProvider.js'; +import { ENCODING_WATCH_TYPE, FRAME_WATCH_TYPE } from './config.js'; export default function FrameWatchViewPlugin(options) { return function install(openmct) { diff --git a/src/globalFilters/plugin.js b/src/globalFilters/plugin.js index de7f69d7..dab3a625 100644 --- a/src/globalFilters/plugin.js +++ b/src/globalFilters/plugin.js @@ -1,4 +1,4 @@ -import mount from 'ommUtils/mountVueComponent'; +import mount from 'ommUtils/mountVueComponent.js'; import GlobalFilterIndicator from './GlobalFilterIndicator.vue'; export default function plugin(config) { diff --git a/src/historical/HistoricalProvider.js b/src/historical/HistoricalProvider.js index dde2ee74..81ed3c34 100644 --- a/src/historical/HistoricalProvider.js +++ b/src/historical/HistoricalProvider.js @@ -1,433 +1,72 @@ -define([ - 'services/mcws/mcws', - 'services/session/SessionService', - 'services/filtering/FilterService', - '../types/types', - '../formats/UTCDayOfYearFormat', - 'lodash', - 'moment' -], function ( - mcwsDefault, - sessionServiceDefault, - filterServiceDefault, - types, - UTCDayOfYearFormat, - _, - moment -) { - const mcws = mcwsDefault.default; - const UTC_FORMAT_KEY = window.openmctMCWSConfig?.time?.utcFormat; - const PROVIDERS = [ - { - // CHANNEL LAD PROVIDER - supportsRequest: function (domainObject, request) { - return ( - domainObject.type === types.Channel.key && - domainObject.telemetry && - (domainObject.telemetry.channelLADUrl || domainObject.telemetry.channelHistoricalUrl) && - (request.strategy === 'latest' || request.size === 1) - ); - }, - batchId: function (domainObject, options) { - return [domainObject.telemetry.channelLADUrl, options.domain, options.filters]; - }, - batchRequest: function (batch) { - const requests = _.values(batch.requestsById); - const params = requests[0].params; - const options = requests[0].options; - - params.lad_type = params.sort; - params.select = - '(dn,eu,channel_id,ert,scet,sclk,lst,record_type,dn_alarm_state,eu_alarm_state,module,realtime,dss_id)'; - params.filter.channel_id__in = _.map(requests, 'domainObject.telemetry.channel_id'); - setSortFilter(params); - - const ladURL = requests[0].domainObject.telemetry.channelLADUrl; - const fallbackHistoricalURL = requests[0].domainObject.telemetry.channelHistoricalUrl; - let requestURL; - - if (!ladURL) { - requestURL = fallbackHistoricalURL; - delete params.lad_type; - } else { - requestURL = ladURL; - } - - mcws - .dataTable(requestURL, { signal: options.signal }) - .read(params) - .then(function (res) { - const valuesByChannelId = _.groupBy(res, 'channel_id'); - const toFulfill = _.keyBy(requests, 'domainObject.telemetry.channel_id'); - - _.forEach(valuesByChannelId, function (values, id) { - toFulfill[id].resolve(values); - delete toFulfill[id]; - }); - _.forEach(toFulfill, function (request) { - request.resolve([]); - }); - }) - .catch((reason) => { - requests.forEach((request) => request.reject(reason)); - }); - } - }, - { - // MINMAX PROVIDER - supportsRequest: function (domainObject, request) { - return ( - domainObject.type === types.Channel.key && - domainObject.telemetry && - domainObject.telemetry.channelMinMaxUrl && - request.size > 1 && - request.strategy === 'minmax' - ); - }, - batchId: function (domainObject, options) { - return [ - domainObject.telemetry.channelLADUrl, - options.domain, - options.start, - options.end, - options.size - ]; - }, - batchRequest: function (batch) { - const requests = _.values(batch.requestsById); - const params = requests[0].params; - const options = requests[0].options; - - params.minmax = - '(' + [requests[0].options.size, requests[0].options.domain, 'eu_or_dn'].join(',') + ')'; - params.select = - '(dn,eu,channel_id,ert,scet,sclk,lst,record_type,eu_or_dn,dn_alarm_state,eu_alarm_state)'; - params.filter.channel_id__in = _.map(requests, 'domainObject.telemetry.channel_id'); - setSortFilter(params); - - mcws - .dataTable(requests[0].domainObject.telemetry.channelMinMaxUrl, { - signal: options.signal - }) - .read(params) - .then(function (res) { - const valuesByChannelId = _.groupBy(res, 'channel_id'); - const toFulfill = _.keyBy(requests, 'domainObject.telemetry.channel_id'); - - _.forEach(valuesByChannelId, function (values, id) { - toFulfill[id].resolve(values); - delete toFulfill[id]; - }); - _.forEach(toFulfill, function (request) { - request.resolve([]); - }); - }) - .catch((reason) => { - requests.forEach((request) => request.reject(reason)); - }); - }, - isMinMaxProvider: true - }, - { - // EVR PROVIDER - supportsRequest: function (domainObject, options) { - const hasTelemetry = Boolean(domainObject.telemetry); - const hasEvrHistoricalUrl = - hasTelemetry && Boolean(domainObject.telemetry.evrHistoricalUrl); - const hasEvrLADUrl = hasTelemetry && Boolean(domainObject.telemetry.evrLADUrl); - - return hasEvrHistoricalUrl || (hasEvrLADUrl && isLADQuery(options)); - }, - request: function (domainObject, options, params) { - const evrHistoricalUrl = domainObject.telemetry.evrHistoricalUrl; - const evrLADUrl = domainObject.telemetry.evrLADUrl; - - let url = evrHistoricalUrl; - - if (evrLADUrl && isLADQuery(options)) { - url = evrLADUrl; - params.lad_type = params.sort; - - /* - * For LAD queries by name, - * MCWS and AMPCS also requires a level - */ - if (domainObject.telemetry.evr_name) { - params.filter.level = '*'; - } - } - - if (domainObject.telemetry.level) { - params.filter.level = domainObject.telemetry.level; - } - - if (domainObject.telemetry.module) { - params.filter.module = domainObject.telemetry.module; - } - - if (domainObject.telemetry.evr_name) { - params.filter.name = domainObject.telemetry.evr_name; - } - - setMaxResults(domainObject, options, params); - - setSortFilter(params); - - return mcws.dataTable(url, { signal: options.signal }).read(params); - } - }, - { - // dataProductProvider - supportsRequest: function (domainObject, options) { - return domainObject.telemetry && !!domainObject.telemetry.dataProductUrl; - }, - request: function (domainObject, options, params) { - setMaxResults(domainObject, options, params); - setSortFilter(params); - - const promise = mcws - .dataTable(domainObject.telemetry.dataProductUrl, { signal: options.signal }) - .read(params); - - if (domainObject.type === 'vista.dataProducts') { - return promise.then(function (results) { - results.forEach(function (datum) { - const sessionId = datum.session_id; - if (datum.unique_name !== undefined) { - const uniqueName = datum.unique_name.replace(/\.dat$/, ''); - const filter = '(session_id=' + sessionId + ',unique_name=' + uniqueName + ')'; - const params = '?filter=' + filter + '&filetype='; - const base_url = domainObject.telemetry.dataProductContentUrl + params; - datum.emd_url = base_url + '.emd'; - datum.emd_preview = base_url + '.emd'; - datum.dat_url = base_url + '.dat'; - datum.txt_url = base_url.replace('DataProductContent', 'DataProductView') + '.dat'; - } - }); - return results; - }); - } - return promise; - } - }, - { - // channel alarm provider - supportsRequest: function (domainObject, options) { - return ( - domainObject.identifier.namespace === 'vista-channel-alarms' && - domainObject.telemetry && - domainObject.telemetry.channelHistoricalUrl && - domainObject.telemetry.alarmLevel - ); - }, - request: function (domainObject, options, params) { - setMaxResults(domainObject, options, params); - setSortFilter(params); - - const dnQueryParams = JSON.parse(JSON.stringify(params)); - const euQueryParams = JSON.parse(JSON.stringify(params)); - - if (domainObject.telemetry.alarmLevel === 'any') { - dnQueryParams.filter.dn_alarm_state__in = ['RED', 'YELLOW']; - euQueryParams.filter.eu_alarm_state__in = ['RED', 'YELLOW']; - } else { - dnQueryParams.filter.dn_alarm_state = domainObject.telemetry.alarmLevel.toUpperCase(); - - euQueryParams.filter.eu_alarm_state = domainObject.telemetry.alarmLevel.toUpperCase(); - } - - const dataTable = mcws.dataTable(domainObject.telemetry.channelHistoricalUrl, { - signal: options.signal - }); - - return Promise.all([dataTable.read(dnQueryParams), dataTable.read(euQueryParams)]).then( - function (results) { - return results[0].concat(results[1]); - } - ); - } - }, - { - // CommandEvents Provider - supportsRequest: function (domainObject, options) { - return domainObject.telemetry && !!domainObject.telemetry.commandEventUrl; - }, - request: function (domainObject, options, params) { - setMaxResults(domainObject, options, params); - params.sort = 'event_time'; - setSortFilter(params); - - if (options.domain === 'ert') { - params.filter.event_time__gte = params.filter[options.domain + '__gte']; - params.filter.event_time__lte = params.filter[options.domain + '__lte']; - } - - delete params.filter[options.domain + '__gte']; - delete params.filter[options.domain + '__lte']; - - return mcws - .dataTable(domainObject.telemetry.commandEventUrl, { signal: options.signal }) - .read(params) - .then( - function (res) { - return res; - }, - function (errorResponse) { - if (errorResponse.status === 400) { - throw errorResponse; - } - - return []; // TODO: better handling due to error. - } - ); - }, - exclusiveDomains: ['ert'] - }, - { - // HEADER CHANNELS HISTORICAL PROVIDER - supportsRequest: function (domainObject, request) { - return ( - domainObject.type === types.HeaderChannel.key && - domainObject.telemetry && - domainObject.telemetry.channelHistoricalUrl - ); - }, - request: function (domainObject, options, params) { - params.filter.channel_id = domainObject.telemetry.channel_id; - setMaxResults(domainObject, options, params); - setSortFilter(params); - - return mcws - .dataTable(domainObject.telemetry.channelHistoricalUrl, { signal: options.signal }) - .read(params); - } - } - ]; - - const channelHistoricalProvider = { - // CHANNEL HISTORICAL PROVIDER - supportsRequest: function (domainObject, request) { - return ( - domainObject.type === types.Channel.key && - domainObject.telemetry && - domainObject.telemetry.channelHistoricalUrl && - (request.strategy === 'minmax' ? !domainObject.telemetry.channelMinMaxUrl : true) && - request.size !== 1 - ); - }, - batchRequest: function (batch) { - const requests = _.values(batch.requestsById); - const params = requests[0].params; - const options = requests[0].options; - - params.select = - '(dn,eu,channel_id,ert,scet,sclk,lst,record_type,dn_alarm_state,eu_alarm_state,module,realtime,dss_id)'; - params.filter.channel_id__in = _.map(requests, 'domainObject.telemetry.channel_id'); - setSortFilter(params); - - mcws - .dataTable(requests[0].domainObject.telemetry.channelHistoricalUrl, { - signal: options.signal - }) - .read(params) - .then(function (res) { - const valuesByChannelId = _.groupBy(res, 'channel_id'); - const toFulfill = _.keyBy(requests, 'domainObject.telemetry.channel_id'); - - _.forEach(valuesByChannelId, function (values, id) { - toFulfill[id].resolve(values); - delete toFulfill[id]; - }); - _.forEach(toFulfill, function (request) { - request.resolve([]); - }); - }) - .catch((reason) => { - requests.forEach((request) => request.reject(reason)); - }); - }, - request: function (domainObject, options, params) { - params.filter.channel_id = domainObject.telemetry.channel_id; - setSortFilter(params); - setMaxResults(domainObject, options, params); - - return mcws - .dataTable(domainObject.telemetry.channelHistoricalUrl, { signal: options.signal }) - .read(params); - } - }; - - if (window.openmctMCWSConfig?.batchHistoricalChannelQueries === true) { - channelHistoricalProvider.batchId = function (domainObject, options) { - return [domainObject.telemetry.channelHistoricalUrl, options.domain, options.filters]; - }; - } - - PROVIDERS.push(channelHistoricalProvider); - - function isLADQuery(options) { - return options.strategy === 'latest'; - } - - function setMaxResults(domainObject, options, params) { - if ( - domainObject.telemetry.mcwsVersion >= 3.2 && - options.strategy !== 'comprehensive' && - window.openmctMCWSConfig?.maxResults !== undefined - ) { - params.max_records = window.openmctMCWSConfig.maxResults; - } +import sessionService from 'services/session/SessionService.js'; +import filterService from 'services/filtering/FilterService.js'; +import UTCDayOfYearFormat from '../formats/UTCDayOfYearFormat.js'; +import moment from 'moment'; +import channelLADProvider from './providers/ChannelLadProvider.js'; +import minMaxProvider from './providers/MinMaxProvider.js'; +import evrProvider from './providers/EvrProvider.js'; +import dataProductProvider from './providers/DataProductProvider.js'; +import channelAlarmProvider from './providers/ChannelAlarmProvider.js'; +import commandEventsProvider from './providers/CommandEventsProvider.js'; +import headerChannelsHistoricalProvider from './providers/HeaderChannelsHistoricalProvider.js'; +import channelHistoricalProvider from './providers/ChannelHistoricalProvider.js'; + +const UTC_FORMAT_KEY = window.openmctMCWSConfig?.time?.utcFormat; + +// Combine all providers into array +const PROVIDERS = [ + channelLADProvider, + minMaxProvider, + evrProvider, + dataProductProvider, + channelAlarmProvider, + commandEventsProvider, + headerChannelsHistoricalProvider, + channelHistoricalProvider +]; + +function padTime(time) { + if (time < 10) { + return `0${time}`; + } else { + return `${time}`; } +} - function setSortFilter(params) { - if (window.openmctMCWSConfig?.disableSortParam === true) { - delete params.sort; - } - } - - function padTime(time) { - if (time < 10) { - return `0${time}`; - } else { - return `${time}`; - } - } - - function HistoricalProvider(openmct) { +class HistoricalProvider { + constructor(openmct) { this.openmct = openmct; this.timeFormatter = UTC_FORMAT_KEY ? this.openmct.telemetry.getFormatter(UTC_FORMAT_KEY) - : new UTCDayOfYearFormat.default(); + : new UTCDayOfYearFormat(); this.clearAlert = this.clearAlert.bind(this); if (window.openmctMCWSConfig?.queryTimespanLimit !== undefined) { - let duration = moment.duration(window.openmctMCWSConfig.queryTimespanLimit, 'milliseconds'); - let hours = padTime(Math.floor(duration.asHours())); - let minutes = padTime(Math.floor(duration.minutes())); - let seconds = padTime(Math.floor(duration.seconds())); + const duration = moment.duration( + window.openmctMCWSConfig.queryTimespanLimit, + 'milliseconds' + ); + const hours = padTime(Math.floor(duration.asHours())); + const minutes = padTime(Math.floor(duration.minutes())); + const seconds = padTime(Math.floor(duration.seconds())); this.formattedQueryTimespanLimit = `${hours}:${minutes}:${seconds} hrs`; } } - HistoricalProvider.prototype.supportsRequest = function (domainObject) { + supportsRequest(domainObject) { return ['vista', 'vista-channel-alarms', 'vista-frame-event-filter'].includes( domainObject.identifier.namespace ); - }; + } - HistoricalProvider.prototype.dispatchBatch = function (provider, batchKey) { + dispatchBatch(provider, batchKey) { const batch = provider.batches[batchKey]; provider.batchRequest(batch); delete provider.batches[batchKey]; - }; - - HistoricalProvider.prototype.doQueuedRequest = function ( - domainObject, - options, - params, - provider - ) { + } + + doQueuedRequest(domainObject, options, params, provider) { if (!provider.batches) { provider.batches = {}; } @@ -438,11 +77,9 @@ define([ if (!batch) { batch = provider.batches[batchKey] = { requestsById: {}, - dispatch: _.debounce( - function () { - this.dispatchBatch(provider, batchKey); - }.bind(this) - ), + dispatch: debounce(() => { + this.dispatchBatch(provider, batchKey); + }), provider: provider }; } @@ -456,16 +93,16 @@ define([ options: options, params: params }; - entry.promise = new Promise(function (resolve, reject) { + entry.promise = new Promise((resolve, reject) => { entry.resolve = resolve; entry.reject = reject; }); } batch.dispatch(); return entry.promise; - }; + } - HistoricalProvider.prototype.isTimespanLimitExceeded = function (provider, options) { + isTimespanLimitExceeded(provider, options) { const domainsSupported = ['ert', 'scet', 'lmst']; if ( @@ -479,16 +116,14 @@ define([ } return false; - }; + } - HistoricalProvider.prototype.request = function (domainObject, options) { + request(domainObject, options) { let formatter; options = { ...options }; - const provider = PROVIDERS.filter(function (p) { - return p.supportsRequest(domainObject, options); - })[0]; + const provider = PROVIDERS.filter((p) => p.supportsRequest(domainObject, options))[0]; if (!provider) { return Promise.resolve([]); @@ -579,10 +214,10 @@ define([ }); } - const filterService = filterServiceDefault.default(); + const filterServiceInstance = filterService(); - if (filterService) { - const globalFilters = filterService.getActiveFilters(); + if (filterServiceInstance) { + const globalFilters = filterServiceInstance.getActiveFilters(); Object.entries(globalFilters).forEach(([key, filter]) => { const domainObjectFiltersKeys = Object.keys(params.filter); @@ -609,7 +244,7 @@ define([ const responseBody = await errorResponse.text(); const match = responseBody.match(/does not contain the specified parameter column: (\w+)/); - if (match && filterService.hasActiveFilters()) { + if (match && filterServiceInstance.hasActiveFilters()) { this.openmct.notifications.error( `Error requesting telemetry data for ${domainObject.name}: Unsupported filter "${match[1]}". If set, please remove the global filter and retry.` ); @@ -617,10 +252,10 @@ define([ throw errorResponse; } }); - }; + } - HistoricalProvider.prototype.removeFiltersIfAllSelected = function (domainObject, filters) { - let valuesWithFilters = this.openmct.telemetry + removeFiltersIfAllSelected(domainObject, filters) { + const valuesWithFilters = this.openmct.telemetry .getMetadata(domainObject) .values() .filter((metadatum) => metadatum.filters !== undefined) @@ -630,11 +265,11 @@ define([ }, {}); for (const key in filters) { - let metadataFilters = valuesWithFilters[key]; + const metadataFilters = valuesWithFilters[key]; if (metadataFilters) { metadataFilters.forEach((filter) => { if (filter.possibleValues) { - let allSelected = filter.possibleValues.every((possibleValue) => { + const allSelected = filter.possibleValues.every((possibleValue) => { return filters[key].equals && filters[key].equals.includes(possibleValue.value); }); if (allSelected) { @@ -646,9 +281,9 @@ define([ } return filters; - }; + } - HistoricalProvider.prototype.showFiltersWarning = function () { + showFiltersWarning() { //Don't fill the notifications area with lots of warnings. if (!this.filteringAlert) { this.filteringAlert = this.openmct.notifications.alert( @@ -656,33 +291,33 @@ define([ ); this.filteringAlert.on('destroy', this.clearAlert); } - }; + } - HistoricalProvider.prototype.clearAlert = function () { + clearAlert() { this.filteringAlert.off('destroy', this.clearAlert); delete this.filteringAlert; - }; + } - HistoricalProvider.prototype.hasFilters = function (options) { + hasFilters(options) { return ( options.filters !== undefined && Object.values(options.filters).some((filterValue) => { return filterValue && Object.keys(filterValue).length > 0; }) ); - }; + } - HistoricalProvider.prototype.isUnsupportedDomain = function (provider, options) { + isUnsupportedDomain(provider, options) { if (provider.exclusiveDomains && !provider.exclusiveDomains.includes(options.domain)) { return true; } return false; - }; + } - HistoricalProvider.prototype.getSessionService = function () { - return sessionServiceDefault.default(); - }; + getSessionService() { + return sessionService(); + } +} - return HistoricalProvider; -}); +export default HistoricalProvider; diff --git a/src/historical/HistoricalProviderSpec.js b/src/historical/HistoricalProviderSpec.js index 633b49b2..60089577 100644 --- a/src/historical/HistoricalProviderSpec.js +++ b/src/historical/HistoricalProviderSpec.js @@ -1,4 +1,4 @@ -import HistoricalProvider from './HistoricalProvider'; +import HistoricalProvider from './HistoricalProvider.js'; describe('Historical Provider', function () { let historicalProvider; diff --git a/src/historical/plugin.js b/src/historical/plugin.js index 0f2f7a16..8c0a4ae0 100644 --- a/src/historical/plugin.js +++ b/src/historical/plugin.js @@ -1,21 +1,21 @@ -define(['./HistoricalProvider'], function (HistoricalProvider) { - function HistoricalTelemetryPlugin(options) { - return function install(openmct) { - openmct.telemetry.addProvider(new HistoricalProvider(openmct)); +import HistoricalProvider from './HistoricalProvider.js'; - /** - * Provide a dummy historical provider for message filters to avoid errors in views due to bug. - */ - openmct.telemetry.addProvider({ - supportsRequest: function (domainObject) { - return domainObject.identifier.namespace === 'vista-message-filter'; - }, - request: function (domainObject) { - return Promise.resolve([]); - } - }); - }; - } +function HistoricalTelemetryPlugin(options) { + return function install(openmct) { + openmct.telemetry.addProvider(new HistoricalProvider(openmct)); - return HistoricalTelemetryPlugin; -}); + /** + * Provide a dummy historical provider for message filters to avoid errors in views due to bug. + */ + openmct.telemetry.addProvider({ + supportsRequest: function (domainObject) { + return domainObject.identifier.namespace === 'vista-message-filter'; + }, + request: function (domainObject) { + return Promise.resolve([]); + } + }); + }; +} + +export default HistoricalTelemetryPlugin; diff --git a/src/historical/providers/ChannelAlarmProvider.js b/src/historical/providers/ChannelAlarmProvider.js new file mode 100644 index 00000000..227cca23 --- /dev/null +++ b/src/historical/providers/ChannelAlarmProvider.js @@ -0,0 +1,42 @@ +import mcws from 'services/mcws/mcws.js'; +import { setSortFilter, setMaxResults } from '../../utils/utils.js'; + +class ChannelAlarmProvider { + supportsRequest(domainObject, options) { + return ( + domainObject.identifier.namespace === 'vista-channel-alarms' && + domainObject.telemetry && + domainObject.telemetry.channelHistoricalUrl && + domainObject.telemetry.alarmLevel + ); + } + + request(domainObject, options, params) { + setMaxResults(domainObject, options, params); + setSortFilter(params); + + const dnQueryParams = JSON.parse(JSON.stringify(params)); + const euQueryParams = JSON.parse(JSON.stringify(params)); + + if (domainObject.telemetry.alarmLevel === 'any') { + dnQueryParams.filter.dn_alarm_state__in = ['RED', 'YELLOW']; + euQueryParams.filter.eu_alarm_state__in = ['RED', 'YELLOW']; + } else { + dnQueryParams.filter.dn_alarm_state = domainObject.telemetry.alarmLevel.toUpperCase(); + + euQueryParams.filter.eu_alarm_state = domainObject.telemetry.alarmLevel.toUpperCase(); + } + + const dataTable = mcws.dataTable(domainObject.telemetry.channelHistoricalUrl, { + signal: options.signal + }); + + return Promise.all([dataTable.read(dnQueryParams), dataTable.read(euQueryParams)]).then( + (results) => { + return results[0].concat(results[1]); + } + ); + } +} + +export default new ChannelAlarmProvider(); \ No newline at end of file diff --git a/src/historical/providers/ChannelHistoricalProvider.js b/src/historical/providers/ChannelHistoricalProvider.js new file mode 100644 index 00000000..9ba281bc --- /dev/null +++ b/src/historical/providers/ChannelHistoricalProvider.js @@ -0,0 +1,68 @@ +import mcws from 'services/mcws/mcws.js'; +import types from '../../types/types.js'; +import { groupBy, keyBy, setSortFilter, setMaxResults } from '../../utils/utils.js'; + +class ChannelHistoricalProvider { + supportsRequest(domainObject, request) { + return ( + domainObject.type === types.Channel.key && + domainObject.telemetry && + domainObject.telemetry.channelHistoricalUrl && + (request.strategy === 'minmax' ? !domainObject.telemetry.channelMinMaxUrl : true) && + request.size !== 1 + ); + } + + get batchId() { + if (window.openmctMCWSConfig?.batchHistoricalChannelQueries === true) { + return (domainObject, options) => { + return [domainObject.telemetry.channelHistoricalUrl, options.domain, options.filters]; + }; + } + return undefined; + } + + batchRequest(batch) { + const requests = Object.values(batch.requestsById); + const params = requests[0].params; + const options = requests[0].options; + + params.select = + '(dn,eu,channel_id,ert,scet,sclk,lst,record_type,dn_alarm_state,eu_alarm_state,module,realtime,dss_id)'; + params.filter.channel_id__in = requests.map((req) => req.domainObject.telemetry.channel_id); + setSortFilter(params); + + mcws + .dataTable(requests[0].domainObject.telemetry.channelHistoricalUrl, { + signal: options.signal + }) + .read(params) + .then((res) => { + const valuesByChannelId = groupBy(res, 'channel_id'); + const toFulfill = keyBy(requests, (req) => req.domainObject.telemetry.channel_id); + + Object.entries(valuesByChannelId).forEach(([id, values]) => { + toFulfill[id].resolve(values); + delete toFulfill[id]; + }); + Object.values(toFulfill).forEach((request) => { + request.resolve([]); + }); + }) + .catch((reason) => { + requests.forEach((request) => request.reject(reason)); + }); + } + + request(domainObject, options, params) { + params.filter.channel_id = domainObject.telemetry.channel_id; + setSortFilter(params); + setMaxResults(domainObject, options, params); + + return mcws + .dataTable(domainObject.telemetry.channelHistoricalUrl, { signal: options.signal }) + .read(params); + } +} + +export default new ChannelHistoricalProvider(); \ No newline at end of file diff --git a/src/historical/providers/ChannelLadProvider.js b/src/historical/providers/ChannelLadProvider.js new file mode 100644 index 00000000..d16b77ae --- /dev/null +++ b/src/historical/providers/ChannelLadProvider.js @@ -0,0 +1,64 @@ +import mcws from 'services/mcws/mcws.js'; +import types from '../../types/types.js'; +import { groupBy, keyBy, setSortFilter } from '../../utils/utils.js'; + + + +class ChannelLadProvider { + supportsRequest(domainObject, request) { + return ( + domainObject.type === types.Channel.key && + domainObject.telemetry && + (domainObject.telemetry.channelLADUrl || domainObject.telemetry.channelHistoricalUrl) && + (request.strategy === 'latest' || request.size === 1) + ); + } + + batchId(domainObject, options) { + return [domainObject.telemetry.channelLADUrl, options.domain, options.filters]; + } + + batchRequest(batch) { + const requests = Object.values(batch.requestsById); + const params = requests[0].params; + const options = requests[0].options; + + params.lad_type = params.sort; + params.select = + '(dn,eu,channel_id,ert,scet,sclk,lst,record_type,dn_alarm_state,eu_alarm_state,module,realtime,dss_id)'; + params.filter.channel_id__in = requests.map((req) => req.domainObject.telemetry.channel_id); + setSortFilter(params); + + const ladURL = requests[0].domainObject.telemetry.channelLADUrl; + const fallbackHistoricalURL = requests[0].domainObject.telemetry.channelHistoricalUrl; + let requestURL; + + if (!ladURL) { + requestURL = fallbackHistoricalURL; + delete params.lad_type; + } else { + requestURL = ladURL; + } + + mcws + .dataTable(requestURL, { signal: options.signal }) + .read(params) + .then((res) => { + const valuesByChannelId = groupBy(res, 'channel_id'); + const toFulfill = keyBy(requests, (req) => req.domainObject.telemetry.channel_id); + + Object.entries(valuesByChannelId).forEach(([id, values]) => { + toFulfill[id].resolve(values); + delete toFulfill[id]; + }); + Object.values(toFulfill).forEach((request) => { + request.resolve([]); + }); + }) + .catch((reason) => { + requests.forEach((request) => request.reject(reason)); + }); + } +} + +export default new ChannelLadProvider(); diff --git a/src/historical/providers/CommandEventsProvider.js b/src/historical/providers/CommandEventsProvider.js new file mode 100644 index 00000000..118cab72 --- /dev/null +++ b/src/historical/providers/CommandEventsProvider.js @@ -0,0 +1,44 @@ +import mcws from 'services/mcws/mcws.js'; +import { setSortFilter, setMaxResults } from '../../utils/utils.js'; + +class CommandEventsProvider { + constructor() { + this.exclusiveDomains = ['ert']; + } + + supportsRequest(domainObject, options) { + return domainObject.telemetry && !!domainObject.telemetry.commandEventUrl; + } + + request(domainObject, options, params) { + setMaxResults(domainObject, options, params); + params.sort = 'event_time'; + setSortFilter(params); + + if (options.domain === 'ert') { + params.filter.event_time__gte = params.filter[options.domain + '__gte']; + params.filter.event_time__lte = params.filter[options.domain + '__lte']; + } + + delete params.filter[options.domain + '__gte']; + delete params.filter[options.domain + '__lte']; + + return mcws + .dataTable(domainObject.telemetry.commandEventUrl, { signal: options.signal }) + .read(params) + .then( + (res) => { + return res; + }, + (errorResponse) => { + if (errorResponse.status === 400) { + throw errorResponse; + } + + return []; // TODO: better handling due to error. + } + ); + } +} + +export default new CommandEventsProvider(); \ No newline at end of file diff --git a/src/historical/providers/DataProductProvider.js b/src/historical/providers/DataProductProvider.js new file mode 100644 index 00000000..13702261 --- /dev/null +++ b/src/historical/providers/DataProductProvider.js @@ -0,0 +1,39 @@ +import mcws from 'services/mcws/mcws.js'; +import { setSortFilter, setMaxResults } from '../../utils/utils.js'; + +class DataProductProvider { + supportsRequest(domainObject, options) { + return domainObject.telemetry && !!domainObject.telemetry.dataProductUrl; + } + + request(domainObject, options, params) { + setMaxResults(domainObject, options, params); + setSortFilter(params); + + const promise = mcws + .dataTable(domainObject.telemetry.dataProductUrl, { signal: options.signal }) + .read(params); + + if (domainObject.type === 'vista.dataProducts') { + return promise.then((results) => { + results.forEach((datum) => { + const sessionId = datum.session_id; + if (datum.unique_name !== undefined) { + const uniqueName = datum.unique_name.replace(/\.dat$/, ''); + const filter = '(session_id=' + sessionId + ',unique_name=' + uniqueName + ')'; + const params = '?filter=' + filter + '&filetype='; + const base_url = domainObject.telemetry.dataProductContentUrl + params; + datum.emd_url = base_url + '.emd'; + datum.emd_preview = base_url + '.emd'; + datum.dat_url = base_url + '.dat'; + datum.txt_url = base_url.replace('DataProductContent', 'DataProductView') + '.dat'; + } + }); + return results; + }); + } + return promise; + } +} + +export default new DataProductProvider(); \ No newline at end of file diff --git a/src/historical/providers/EvrProvider.js b/src/historical/providers/EvrProvider.js new file mode 100644 index 00000000..e6b20b24 --- /dev/null +++ b/src/historical/providers/EvrProvider.js @@ -0,0 +1,53 @@ +import mcws from 'services/mcws/mcws.js'; +import { setSortFilter, setMaxResults, isLADQuery } from '../../utils/utils.js'; + +class EvrProvider { + supportsRequest(domainObject, options) { + const hasTelemetry = Boolean(domainObject.telemetry); + const hasEvrHistoricalUrl = + hasTelemetry && Boolean(domainObject.telemetry.evrHistoricalUrl); + const hasEvrLADUrl = hasTelemetry && Boolean(domainObject.telemetry.evrLADUrl); + + return hasEvrHistoricalUrl || (hasEvrLADUrl && isLADQuery(options)); + } + + request(domainObject, options, params) { + const evrHistoricalUrl = domainObject.telemetry.evrHistoricalUrl; + const evrLADUrl = domainObject.telemetry.evrLADUrl; + + let url = evrHistoricalUrl; + + if (evrLADUrl && isLADQuery(options)) { + url = evrLADUrl; + params.lad_type = params.sort; + + /* + * For LAD queries by name, + * MCWS and AMPCS also requires a level + */ + if (domainObject.telemetry.evr_name) { + params.filter.level = '*'; + } + } + + if (domainObject.telemetry.level) { + params.filter.level = domainObject.telemetry.level; + } + + if (domainObject.telemetry.module) { + params.filter.module = domainObject.telemetry.module; + } + + if (domainObject.telemetry.evr_name) { + params.filter.name = domainObject.telemetry.evr_name; + } + + setMaxResults(domainObject, options, params); + + setSortFilter(params); + + return mcws.dataTable(url, { signal: options.signal }).read(params); + } +} + +export default new EvrProvider(); \ No newline at end of file diff --git a/src/historical/providers/HeaderChannelsHistoricalProvider.js b/src/historical/providers/HeaderChannelsHistoricalProvider.js new file mode 100644 index 00000000..df5050d9 --- /dev/null +++ b/src/historical/providers/HeaderChannelsHistoricalProvider.js @@ -0,0 +1,25 @@ +import mcws from 'services/mcws/mcws.js'; +import types from '../../types/types.js'; +import { setSortFilter, setMaxResults } from '../../utils/utils.js'; + +class HeaderChannelsHistoricalProvider { + supportsRequest(domainObject, request) { + return ( + domainObject.type === types.HeaderChannel.key && + domainObject.telemetry && + domainObject.telemetry.channelHistoricalUrl + ); + } + + request(domainObject, options, params) { + params.filter.channel_id = domainObject.telemetry.channel_id; + setMaxResults(domainObject, options, params); + setSortFilter(params); + + return mcws + .dataTable(domainObject.telemetry.channelHistoricalUrl, { signal: options.signal }) + .read(params); + } +} + +export default new HeaderChannelsHistoricalProvider(); \ No newline at end of file diff --git a/src/historical/providers/MinMaxProvider.js b/src/historical/providers/MinMaxProvider.js new file mode 100644 index 00000000..be4c2cd6 --- /dev/null +++ b/src/historical/providers/MinMaxProvider.js @@ -0,0 +1,65 @@ +import mcws from 'services/mcws/mcws.js'; +import types from '../../types/types.js'; +import { groupBy, keyBy, setSortFilter } from '../../utils/utils.js'; + +class MinMaxProvider { + constructor() { + this.isMinMaxProvider = true; + } + + supportsRequest(domainObject, request) { + return ( + domainObject.type === types.Channel.key && + domainObject.telemetry && + domainObject.telemetry.channelMinMaxUrl && + request.size > 1 && + request.strategy === 'minmax' + ); + } + + batchId(domainObject, options) { + return [ + domainObject.telemetry.channelLADUrl, + options.domain, + options.start, + options.end, + options.size + ]; + } + + batchRequest(batch) { + const requests = Object.values(batch.requestsById); + const params = requests[0].params; + const options = requests[0].options; + + params.minmax = + '(' + [requests[0].options.size, requests[0].options.domain, 'eu_or_dn'].join(',') + ')'; + params.select = + '(dn,eu,channel_id,ert,scet,sclk,lst,record_type,eu_or_dn,dn_alarm_state,eu_alarm_state)'; + params.filter.channel_id__in = requests.map((req) => req.domainObject.telemetry.channel_id); + setSortFilter(params); + + mcws + .dataTable(requests[0].domainObject.telemetry.channelMinMaxUrl, { + signal: options.signal + }) + .read(params) + .then((res) => { + const valuesByChannelId = groupBy(res, 'channel_id'); + const toFulfill = keyBy(requests, (req) => req.domainObject.telemetry.channel_id); + + Object.entries(valuesByChannelId).forEach(([id, values]) => { + toFulfill[id].resolve(values); + delete toFulfill[id]; + }); + Object.values(toFulfill).forEach((request) => { + request.resolve([]); + }); + }) + .catch((reason) => { + requests.forEach((request) => request.reject(reason)); + }); + } +} + +export default new MinMaxProvider(); \ No newline at end of file diff --git a/src/lib/eventHelpers.js b/src/lib/eventHelpers.js index ec14a362..25f5a0b0 100644 --- a/src/lib/eventHelpers.js +++ b/src/lib/eventHelpers.js @@ -1,68 +1,69 @@ -define([], function () { - 'use strict'; +const helperFunctions = { + listenTo(object, event, callback, context) { + if (!this._listeningTo) { + this._listeningTo = []; + } - var helperFunctions = { - listenTo: function (object, event, callback, context) { - if (!this._listeningTo) { - this._listeningTo = []; - } - var listener = { - object: object, - event: event, - callback: callback, - context: context, - _cb: context ? callback.bind(context) : callback - }; - if (object.$watch && event.indexOf('change:') === 0) { - var scopePath = event.replace('change:', ''); - listener.unlisten = object.$watch(scopePath, listener._cb, true); - } else if (object.$on) { - listener.unlisten = object.$on(event, listener._cb); - } else { - object.on(event, listener._cb); - } - this._listeningTo.push(listener); - }, + const listener = { + object: object, + event: event, + callback: callback, + context: context, + _cb: context ? callback.bind(context) : callback + }; - stopListening: function (object, event, callback, context) { - if (!this._listeningTo) { - this._listeningTo = []; - } + if (object.$watch && event.startsWith('change:')) { + const scopePath = event.replace('change:', ''); + listener.unlisten = object.$watch(scopePath, listener._cb, true); + } else if (object.$on) { + listener.unlisten = object.$on(event, listener._cb); + } else { + object.on(event, listener._cb); + } - this._listeningTo - .filter(function (listener) { - if (object && object !== listener.object) { - return false; - } - if (event && event !== listener.event) { - return false; - } - if (callback && callback !== listener.callback) { - return false; - } - if (context && context !== listener.context) { - return false; - } - return true; - }) - .map(function (listener) { - if (listener.unlisten) { - listener.unlisten(); - } else { - listener.object.off(listener.event, listener._cb); - } - return listener; - }) - .forEach(function (listener) { - this._listeningTo.splice(this._listeningTo.indexOf(listener), 1); - }, this); - }, + this._listeningTo.push(listener); + }, - extend: function (object) { - object.listenTo = helperFunctions.listenTo; - object.stopListening = helperFunctions.stopListening; + stopListening(object, event, callback, context) { + if (!this._listeningTo) { + this._listeningTo = []; } - }; - return helperFunctions; -}); + this._listeningTo + .filter((listener) => { + if (object && object !== listener.object) { + return false; + } + if (event && event !== listener.event) { + return false; + } + if (callback && callback !== listener.callback) { + return false; + } + if (context && context !== listener.context) { + return false; + } + + return true; + }) + .map((listener) => { + if (listener.unlisten) { + listener.unlisten(); + } else { + listener.object.off(listener.event, listener._cb); + } + + return listener; + }) + .forEach((listener) => { + this._listeningTo.splice(this._listeningTo.indexOf(listener), 1); + }); + }, + + extend(object) { + object.listenTo = helperFunctions.listenTo; + object.stopListening = helperFunctions.stopListening; + } +}; + +export default helperFunctions; diff --git a/src/lib/extend.js b/src/lib/extend.js index 953253a6..0656acf7 100644 --- a/src/lib/extend.js +++ b/src/lib/extend.js @@ -1,40 +1,36 @@ -define([], function () { - 'use strict'; +function extend(props) { + const parent = this; + let child; + let Surrogate; + + if (props && Object.hasOwn(props, 'constructor')) { + child = props.constructor; + } else { + child = function () { + return parent.apply(this, arguments); + }; + } - function extend(props) { - var parent = this, - child, - Surrogate; + Object.keys(parent).forEach((propKey) => { + child[propKey] = parent[propKey]; + }); - if (props && Object.hasOwn(props, 'constructor')) { - child = props.constructor; - } else { - child = function () { - return parent.apply(this, arguments); - }; - } + // Surrogate allows inheriting from parent without invoking constructor. + Surrogate = function () { + this.constructor = child; + }; + Surrogate.prototype = parent.prototype; + child.prototype = new Surrogate(); - Object.keys(parent).forEach(function copyStaticProperties(propKey) { - child[propKey] = parent[propKey]; + if (props) { + Object.keys(props).forEach((key) => { + child.prototype[key] = props[key]; }); + } - // Surrogate allows inheriting from parent without invoking constructor. - Surrogate = function () { - this.constructor = child; - }; - Surrogate.prototype = parent.prototype; - child.prototype = new Surrogate(); - - if (props) { - Object.keys(props).forEach(function copyInstanceProperties(key) { - child.prototype[key] = props[key]; - }); - } - - child.__super__ = parent.prototype; + child.__super__ = parent.prototype; - return child; - } + return child; +} - return extend; -}); +export default extend; diff --git a/src/link/plugin.js b/src/link/plugin.js index 1c8780eb..42c5b964 100644 --- a/src/link/plugin.js +++ b/src/link/plugin.js @@ -1,46 +1,46 @@ -define(['@braintree/sanitize-url'], function (urlSanitizeLib) { - function LinkPlugin() { - return function install(openmct) { - openmct.types.addType('vista.link', { - name: 'Hyperlink', - description: 'A link to another page in VISTA or an external resource.', - cssClass: 'icon-activity', - initialize: function (obj) { - return obj; - }, - creatable: true, - form: [ - { - name: 'URL', - key: 'url', - control: 'textfield', - cssClass: 'l-input-lg' - } - ] - }); +import urlSanitizeLib from '@braintree/sanitize-url'; - openmct.objectViews.addProvider({ - key: 'view.link', - canView: function (domainObject) { - return domainObject.type === 'vista.link'; - }, - view: function (domainObject) { - return { - show: function (container) { - container.textContent = ''; +function LinkPlugin() { + return function install(openmct) { + openmct.types.addType('vista.link', { + name: 'Hyperlink', + description: 'A link to another page in VISTA or an external resource.', + cssClass: 'icon-activity', + initialize: function (obj) { + return obj; + }, + creatable: true, + form: [ + { + name: 'URL', + key: 'url', + control: 'textfield', + cssClass: 'l-input-lg' + } + ] + }); - const anchor = document.createElement('a'); - anchor.href = urlSanitizeLib.sanitizeUrl(domainObject.url); - anchor.textContent = domainObject.name; + openmct.objectViews.addProvider({ + key: 'view.link', + canView: function (domainObject) { + return domainObject.type === 'vista.link'; + }, + view: function (domainObject) { + return { + show: function (container) { + container.textContent = ''; - container.appendChild(anchor); - }, - destroy: function () {} - }; - } - }); - }; - } + const anchor = document.createElement('a'); + anchor.href = urlSanitizeLib.sanitizeUrl(domainObject.url); + anchor.textContent = domainObject.name; + + container.appendChild(anchor); + }, + destroy: function () {} + }; + } + }); + }; +} - return LinkPlugin; -}); +export default LinkPlugin; diff --git a/src/mcwsIndicator/MCWSIndicator.vue b/src/mcwsIndicator/MCWSIndicator.vue index 6ea8f4bb..8f6731c1 100644 --- a/src/mcwsIndicator/MCWSIndicator.vue +++ b/src/mcwsIndicator/MCWSIndicator.vue @@ -7,7 +7,7 @@