docs: better docs and types for the API (#7796)

* docs: fix type imports in openmct.js

* docs: fix type imports

* docs: fix types for eventHelpers

* docs: types for TypeRegistry

* docs: types for StatusAPI

* docs: fix ObjectAPI types and docs

* docs: more types

* docs: improved types for main entry

* docs: improved types

* fix: unbreak the linting

* chore: remove EventEmitter webpack alias as it hide types

* fix: return type

* fix: parameter type

* fix: types for composables

* chore: add webpack consts to eslintrc

* fix: remove usage of deprecated timeAPI methods and add a ton of docs and types

* docs: update README.md

* lint: clean up API.md

* chore: upgrade eventemitter to v5.0.2

* refactor: update imports for EventEmitter to remove alias

* format: lint

* docs: update types for Views and ViewProviders

* docs: expose common types at the base import level

* docs(types): remove unnecessary tsconfig options

* docs: ActionAPI

* docs: AnnotationAPI

* docs: import common types from the same origin

* docs: FormsAPI & TelemetryAPI types

* docs: FormController, IndicatorAPI

* docs: MenuAPI, ActionsAPI

* docs: `@memberof` is not supported by `tsc` and JSDoc generation so remove it

* docs: RootRegistry and RootObjectProvider

* docs: Transaction + Overlay

* lint: words for the word god

* fix: review comments
This commit is contained in:
Jesse Mazzella 2024-07-31 10:46:16 -07:00 committed by GitHub
parent e3fcbe1a35
commit 4ee68cccd6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
117 changed files with 1494 additions and 1089 deletions

View File

@ -481,9 +481,20 @@
"specced",
"composables",
"countup",
"darkmatter"
"darkmatter",
"Undeletes"
],
"dictionaries": [
"npm",
"softwareTerms",
"node",
"html",
"css",
"bash",
"en_US",
"en-gb",
"misc"
],
"dictionaries": ["npm", "softwareTerms", "node", "html", "css", "bash", "en_US", "en-gb", "misc"],
"ignorePaths": [
"package.json",
"dist/**",
@ -494,4 +505,4 @@
"html-test-results",
"test-results"
]
}
}

View File

@ -10,7 +10,12 @@ const config = {
serviceworker: true
},
globals: {
_: 'readonly'
_: 'readonly',
__webpack_public_path__: 'writeable',
__OPENMCT_VERSION__: 'readonly',
__OPENMCT_BUILD_DATE__: 'readonly',
__OPENMCT_REVISION__: 'readonly',
__OPENMCT_BUILD_BRANCH__: 'readonly'
},
plugins: ['prettier', 'unicorn', 'simple-import-sort'],
extends: [

View File

@ -70,7 +70,6 @@ const config = {
'@': path.join(projectRootDir, 'src'),
legacyRegistry: path.join(projectRootDir, 'src/legacyRegistry'),
csv: 'comma-separated-values',
EventEmitter: 'eventemitter3',
bourbon: 'bourbon.scss',
'plotly-basic': 'plotly.js-basic-dist-min',
'plotly-gl2d': 'plotly.js-gl2d-dist-min',

61
API.md
View File

@ -381,6 +381,7 @@ openmct.composition.addProvider({
The `addProvider` function accepts a Composition Provider object as its sole
argument. A Composition Provider is a javascript object exposing two functions:
- `appliesTo`: A `function` that accepts a `domainObject` argument, and returns
a `boolean` value indicating whether this composition provider applies to the
given object.
@ -618,9 +619,10 @@ interface Formatter {
Open MCT on its own defines a handful of built-in formats:
###### **Number Format (default):**
###### **Number Format (default):**
Applied to data with `format: 'number'`
```js
valueMetadata = {
format: 'number'
@ -635,15 +637,18 @@ interface NumberFormatter extends Formatter {
validate: (value: any) => boolean;
}
```
###### **String Format**:
###### **String Format**
Applied to data with `format: 'string'`
```js
valueMetadata = {
format: 'string'
// ...
};
```
```ts
interface StringFormatter extends Formatter {
parse: (value: any) => string;
@ -652,8 +657,10 @@ interface StringFormatter extends Formatter {
}
```
###### **Enum Format**:
###### **Enum Format**
Applied to data with `format: 'enum'`
```js
valueMetadata = {
format: 'enum',
@ -676,6 +683,7 @@ valueMetadata = {
Creates a two-way mapping between enum string and value to be used in the `parse` and `format` methods.
Ex:
- `formatter.parse('APPLE') === 1;`
- `formatter.format(1) === 'APPLE';`
@ -691,7 +699,6 @@ interface EnumFormatter extends Formatter {
Formats implement the following interface (provided here as TypeScript for simplicity):
Formats are registered with the Telemetry API using the `addFormat` function. eg.
```javascript
@ -763,8 +770,8 @@ state of the application, and emits events to inform listeners when the state ch
Because the data displayed tends to be time domain data, Open MCT must always
have at least one time system installed and activated. When you download Open
MCT, it will be pre-configured to use the UTC time system, which is installed and activated,
along with other default plugins, in `index.html`. Installing and activating a time system
MCT, it will be pre-configured to use the UTC time system, which is installed and activated,
along with other default plugins, in `index.html`. Installing and activating a time system
is simple, and is covered [in the next section](#defining-and-registering-time-systems).
### Time Systems and Bounds
@ -817,7 +824,7 @@ numbers in UTC terrestrial time.
#### Getting and Setting the Active Time System
Once registered, a time system can be activated by calling `setTimeSystem` with
the timeSystem `key` or an instance of the time system. You can also specify
the timeSystem `key` or an instance of the time system. You can also specify
valid [bounds](#time-bounds) for the timeSystem.
```javascript
@ -841,10 +848,9 @@ Setting the active time system will trigger a [`'timeSystemChanged'`](#time-even
event. If you supplied bounds, a [`'boundsChanged'`](#time-events) event will be triggered afterwards with your newly supplied bounds.
> ⚠️ **Deprecated**
>
> - The method `timeSystem()` is deprecated. Please use `getTimeSystem()` and `setTimeSystem()` as a replacement.
#### Time Bounds
The TimeAPI provides a getter and setter for querying and setting time bounds. Time
@ -875,15 +881,16 @@ To respond to bounds change events, listen for the [`'boundsChanged'`](#time-eve
event.
> ⚠️ **Deprecated**
>
> - The method `bounds()` is deprecated and will be removed in a future release. Please use `getBounds()` and `setBounds()` as a replacement.
### Clocks
The Time API requires a clock source which will cause the bounds to be updated
automatically whenever the clock source "ticks". A clock is simply an object that
supports registration of listeners and periodically invokes its listeners with a
number. Open MCT supports registration of new clock sources that tick on almost
anything. A tick occurs when the clock invokes callback functions registered by its
The Time API requires a clock source which will cause the bounds to be updated
automatically whenever the clock source "ticks". A clock is simply an object that
supports registration of listeners and periodically invokes its listeners with a
number. Open MCT supports registration of new clock sources that tick on almost
anything. A tick occurs when the clock invokes callback functions registered by its
listeners with a new time value.
An example of a clock source is the [LocalClock](https://github.com/nasa/openmct/blob/master/src/plugins/utcTimeSystem/LocalClock.js)
@ -972,6 +979,7 @@ openmct.time.getClock();
```
> ⚠️ **Deprecated**
>
> - The method `clock()` is deprecated and will be removed in a future release. Please use `getClock()` and `setClock()` as a replacement.
#### ⚠️ [DEPRECATED] Stopping an active clock
@ -986,12 +994,13 @@ openmct.time.stopClock();
```
> ⚠️ **Deprecated**
>
> - The method `stopClock()` is deprecated and will be removed in a future release.
#### Clock Offsets
When in Real-time [mode](#time-modes), the time bounds of the application will be updated automatically each time the
clock "ticks". The bounds are calculated based on the current value provided by
When in Real-time [mode](#time-modes), the time bounds of the application will be updated automatically each time the
clock "ticks". The bounds are calculated based on the current value provided by
the active clock (via its `tick` event, or its `currentValue()` method).
Unlike bounds, which represent absolute time values, clock offsets represent
@ -1026,13 +1035,14 @@ new bounds will be calculated based on the `currentValue()` of the active clock.
Clock offsets are only relevant when in Real-time [mode](#time-modes).
> ⚠️ **Deprecated**
>
> - The method `clockOffsets()` is deprecated and will be removed in a future release. Please use `getClockOffsets()` and `setClockOffsets()` as a replacement.
### Time Modes
There are two time modes in Open MCT, "Fixed" and "Real-time". In Real-time mode the
There are two time modes in Open MCT, "Fixed" and "Real-time". In Real-time mode the
time bounds of the application will be updated automatically each time the clock "ticks".
The bounds are calculated based on the current value provided by the active clock. In
The bounds are calculated based on the current value provided by the active clock. In
Fixed mode, the time bounds are set for a specified time range. When Open MCT is first
initialized, it will be in Real-time mode.
@ -1120,6 +1130,7 @@ The events emitted by the Time API are:
- `mode`: A string representation of the current time mode, either `'realtime'` or `'fixed'`.
> ⚠️ **Deprecated Events** (These will be removed in a future release):
>
> - `bounds``boundsChanged`
> - `timeSystem``timeSystemChanged`
> - `clock``clockChanged`
@ -1262,7 +1273,7 @@ Returns the currently set text as a `string`.
[the built-in glyphs](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home/glyphs?view=styleguide.glyphs)
may be used here, or a custom CSS class can be provided. Returns the currently defined CSS
class as a `string`.
- `.statusClass([className])`: Gets or sets the CSS class used to determine status. Accepts an __optional__
- `.statusClass([className])`: Gets or sets the CSS class used to determine status. Accepts an **optional**
`string` parameter to be used to set a status class applied to the indicator. May be used to apply
different colors to indicate status.
@ -1312,7 +1323,7 @@ can be used to manage user information and roles.
### Example
Open MCT provides an example [user](example/exampleUser/exampleUserCreator.js) and [user provider](example/exampleUser/ExampleUserProvider.js) which
Open MCT provides an example [user](example/exampleUser/exampleUserCreator.js) and [user provider](example/exampleUser/ExampleUserProvider.js) which
can be used as a starting point for creating a custom user provider.
## Visibility-Based Rendering in View Providers
@ -1335,10 +1346,10 @@ Heres the signature for the show function:
`show(element, isEditing, viewOptions)`
* `element` (HTMLElement) - The DOM element where the view should be rendered.
* `isEditing` (boolean) - Indicates whether the view is in editing mode.
* `viewOptions` (Object) - An object with configuration options for the view, including:
* `renderWhenVisible` (Function) - This function wraps the `requestAnimationFrame` and only triggers the provided render logic when the view is visible in the viewport.
- `element` (HTMLElement) - The DOM element where the view should be rendered.
- `isEditing` (boolean) - Indicates whether the view is in editing mode.
- `viewOptions` (Object) - An object with configuration options for the view, including:
- `renderWhenVisible` (Function) - This function wraps the `requestAnimationFrame` and only triggers the provided render logic when the view is visible in the viewport.
### Example
@ -1367,8 +1378,6 @@ const myViewProvider = {
};
```
Note that `renderWhenVisible` defers rendering while the view is not visible and caters to the latest execution call. This provides responsiveness for dynamic content while ensuring performance optimizations.
Ensure your view logic is prepared to handle potentially multiple deferrals if using this API, as only the last call to renderWhenVisible will be queued for execution upon the view becoming visible.

112
README.md
View File

@ -5,12 +5,10 @@ Open MCT (Open Mission Control Technologies) is a next-generation mission contro
> [!NOTE]
> Please visit our [Official Site](https://nasa.github.io/openmct/) and [Getting Started Guide](https://nasa.github.io/openmct/getting-started/)
Once you've created something amazing with Open MCT, showcase your work in our GitHub Discussions [Show and Tell](https://github.com/nasa/openmct/discussions/categories/show-and-tell) section. We love seeing unique and wonderful implementations of Open MCT!
![Screen Shot 2022-11-23 at 9 51 36 AM](https://user-images.githubusercontent.com/4215777/203617422-4d912bfc-766f-4074-8324-409d9bbe7c05.png)
## Building and Running Open MCT Locally
Building and running Open MCT in your local dev environment is very easy. Be sure you have [Git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/) installed, then follow the directions below. Need additional information? Check out the [Getting Started](https://nasa.github.io/openmct/getting-started/) page on our website.
@ -18,19 +16,19 @@ Building and running Open MCT in your local dev environment is very easy. Be sur
1. Clone the source code:
```
```sh
git clone https://github.com/nasa/openmct.git
```
2. (Optional) Install the correct node version using [nvm](https://github.com/nvm-sh/nvm):
```
```sh
nvm install
```
3. Install development dependencies (Note: Check the `package.json` engine for our tested and supported node versions):
3. Install development dependencies (Note: Check the `package.json` engine for our tested and supported node versions):
```
```sh
npm install
```
@ -57,9 +55,9 @@ our documentation.
> [!NOTE]
> We want Open MCT to be as easy to use, install, run, and develop for as
> possible, and your feedback will help us get there!
> Feedback can be provided via [GitHub issues](https://github.com/nasa/openmct/issues/new/choose),
> [Starting a GitHub Discussion](https://github.com/nasa/openmct/discussions),
> possible, and your feedback will help us get there!
> Feedback can be provided via [GitHub issues](https://github.com/nasa/openmct/issues/new/choose),
> [Starting a GitHub Discussion](https://github.com/nasa/openmct/discussions),
> or by emailing us at [arc-dl-openmct@mail.nasa.gov](mailto:arc-dl-openmct@mail.nasa.gov).
## Developing Applications With Open MCT
@ -68,28 +66,29 @@ For more on developing with Open MCT, see our documentation for a guide on [Deve
## Compatibility
This is a fast moving project and we do our best to test and support the widest possible range of browsers, operating systems, and nodejs APIs. We have a published list of support available in our package.json's `browserslist` key.
This is a fast moving project and we do our best to test and support the widest possible range of browsers, operating systems, and NodeJS APIs. We have a published list of support available in our package.json's `browserslist` key.
The project uses `nvm` to ensure the node and npm version used, is coherent in all projects. Install nvm (non-windows), [here](https://github.com/nvm-sh/nvm) or the windows equivalent [here](https://github.com/coreybutler/nvm-windows)
The project utilizes `nvm` to maintain consistent node and npm versions across all projects. For UNIX, MacOS, Windows WSL, and other POSIX-compliant shell environments, click [here](https://github.com/nvm-sh/nvm). For Windows, check out [nvm-windows](https://github.com/coreybutler/nvm-windows).
If you encounter an issue with a particular browser, OS, or nodejs API, please file a [GitHub issue](https://github.com/nasa/openmct/issues/new/choose)
If you encounter an issue with a particular browser, OS, or NodeJS API, please [file an issue](https://github.com/nasa/openmct/issues/new/choose).
## Plugins
Open MCT can be extended via plugins that make calls to the Open MCT API. A plugin is a group
Open MCT can be extended via plugins that make calls to the Open MCT API. A plugin is a group
of software components (including source code and resources such as images and HTML templates)
that is intended to be added or removed as a single unit.
As well as providing an extension mechanism, most of the core Open MCT codebase is also
As well as providing an extension mechanism, most of the core Open MCT codebase is also
written as plugins.
For information on writing plugins, please see [our API documentation](./API.md#plugins).
## Tests
Our automated test coverage comes in the form of unit, e2e, visual, performance, and security tests.
Our automated test coverage comes in the form of unit, e2e, visual, performance, and security tests.
### Unit Tests
Unit Tests are written for [Jasmine](https://jasmine.github.io/api/edge/global)
and run by [Karma](http://karma-runner.github.io). To run:
@ -101,24 +100,34 @@ in the `src` hierarchy. Full configuration details are found in
alongside the units that they test; for example, `src/foo/Bar.js` would be
tested by `src/foo/BarSpec.js`.
### e2e, Visual, and Performance tests
The e2e, Visual, and Performance tests are written for playwright and run by playwright's new test runner [@playwright/test](https://playwright.dev/).
### e2e, Visual, and Performance Testing
To run the e2e tests which are part of every commit:
Our e2e (end-to-end), Visual, and Performance tests leverage the Playwright framework and are executed using Playwright's test runner, [@playwright/test](https://playwright.dev/).
`npm run test:e2e:stable`
#### How to Run Tests
To run the visual test suite:
- **e2e Tests**: These tests are run on every commit. To run the tests locally, use:
`npm run test:e2e:visual`
```sh
npm run test:e2e:stable
```
To run the performance tests:
- **Visual Tests**: For running the visual test suite, use:
`npm run test:perf`
```sh
npm run test:e2e:visual
```
The test suite is configured to all tests located in `e2e/tests/` ending in `*.e2e.spec.js`. For more about the e2e test suite, please see the [README](./e2e/README.md)
- **Performance Tests**: To initiate the performance tests, enter:
```sh
npm run test:perf
```
All tests are located within the `e2e/tests/` directory and are identified by the `*.e2e.spec.js` filename pattern. For more information about the e2e test suite, refer to the [README](./e2e/README.md).
### Security Tests
Each commit is analyzed for known security vulnerabilities using [CodeQL](https://codeql.github.com/docs/codeql-language-guides/codeql-library-for-javascript/). The list of CWE coverage items is available in the [CodeQL docs](https://codeql.github.com/codeql-query-help/javascript-cwe/). The CodeQL workflow is specified in the [CodeQL analysis file](./.github/workflows/codeql-analysis.yml) and the custom [CodeQL config](./.github/codeql/codeql-config.yml).
### Test Reporting and Code Coverage
@ -129,60 +138,41 @@ Our code coverage is generated during the runtime of our unit, e2e, and visual t
For more on the specifics of our code coverage setup, [see](TESTING.md#code-coverage)
# Glossary
## Glossary
Certain terms are used throughout Open MCT with consistent meanings
or conventions. Any deviations from the below are issues and should be
addressed (either by updating this glossary or changing code to reflect
correct usage.) Other developer documentation, particularly in-line
documentation, may presume an understanding of these terms.
* _plugin_: A plugin is a removable, reusable grouping of software elements.
The application is composed of plugins.
* _composition_: In the context of a domain object, this refers to the set of
other domain objects that compose or are contained by that object. A domain
object's composition is the set of domain objects that should appear
immediately beneath it in a tree hierarchy. A domain object's composition is
described in its model as an array of id's; its composition capability
provides a means to retrieve the actual domain object instances associated
with these identifiers asynchronously.
* _description_: When used as an object property, this refers to the human-readable
description of a thing; usually a single sentence or short paragraph.
(Most often used in the context of extensions, domain
object models, or other similar application-specific objects.)
* _domain object_: A meaningful object to the user; a distinct thing in
the work support by Open MCT. Anything that appears in the left-hand
tree is a domain object.
* _identifier_: A tuple consisting of a namespace and a key, which together uniquely
identifies a domain object.
* _model_: The persistent state associated with a domain object. A domain
object's model is a JavaScript object which can be converted to JSON
without losing information (that is, it contains no methods.)
* _name_: When used as an object property, this refers to the human-readable
name for a thing. (Most often used in the context of extensions, domain
object models, or other similar application-specific objects.)
* _navigation_: Refers to the current state of the application with respect
to the user's expressed interest in a specific domain object; e.g. when
a user clicks on a domain object in the tree, they are _navigating_ to
it, and it is thereafter considered the _navigated_ object (until the
user makes another such choice.)
* _namespace_: A name used to identify a persistence store. A running open MCT
application could potentially use multiple persistence stores, with the
| Term | Definition |
|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| _plugin_ | A removable, reusable grouping of software elements. The application is composed of plugins. |
| _composition_ | In the context of a domain object, this term refers to the set of other domain objects that compose or are contained by that object. A domain object's composition is the set of domain objects that should appear immediately beneath it in a tree hierarchy. It is described in its model as an array of ids, providing a means to asynchronously retrieve the actual domain object instances associated with these identifiers. |
| _description_ | When used as an object property, this term refers to the human-readable description of a thing, usually a single sentence or short paragraph. It is most often used in the context of extensions, domain object models, or other similar application-specific objects. |
| _domain object_ | A meaningful object to the user and a distinct thing in the work supported by Open MCT. Anything that appears in the left-hand tree is a domain object. |
| _identifier_ | A tuple consisting of a namespace and a key, which together uniquely identifies a domain object. |
| _model_ | The persistent state associated with a domain object. A domain object's model is a JavaScript object that can be converted to JSON without losing information, meaning it contains no methods. |
| _name_ | When used as an object property, this term refers to the human-readable name for a thing. It is most often used in the context of extensions, domain object models, or other similar application-specific objects. |
| _navigation_ | This term refers to the current state of the application with respect to the user's expressed interest in a specific domain object. For example, when a user clicks on a domain object in the tree, they are navigating to it, and it is thereafter considered the navigated object until the user makes another such choice. |
| _namespace_ | A name used to identify a persistence store. A running Open MCT application could potentially use multiple persistence stores. |
## Open MCT v2.0.0
Support for our legacy bundle-based API, and the libraries that it was built on (like Angular 1.x), have now been removed entirely from this repository.
For now if you have an Open MCT application that makes use of the legacy API, [a plugin](https://github.com/nasa/openmct-legacy-plugin) is provided that bootstraps the legacy bundling mechanism and API. This plugin will not be maintained over the long term however, and the legacy support plugin will not be tested for compatibility with future versions of Open MCT. It is provided for convenience only.
### How do I know if I am using legacy API?
You might still be using legacy API if your source code
* Contains files named bundle.js, or bundle.json,
* Makes calls to `openmct.$injector()`, or `openmct.$angular`,
* Makes calls to `openmct.legacyRegistry`, `openmct.legacyExtension`, or `openmct.legacyBundle`.
- Contains files named bundle.js, or bundle.json,
- Makes calls to `openmct.$injector()`, or `openmct.$angular`,
- Makes calls to `openmct.legacyRegistry`, `openmct.legacyExtension`, or `openmct.legacyBundle`.
### What should I do if I am using legacy API?
Please refer to [the modern Open MCT API](https://nasa.github.io/openmct/documentation/). Post any questions to the [Discussions section](https://github.com/nasa/openmct/discussions) of the Open MCT GitHub repository.
## Related Repos

View File

@ -14,13 +14,13 @@
extend the platform are provided in the following documentation.
## Sections
* The [API](api/) uses inline documentation
* The [API](api/) uses inline documentation.
using [TypeScript](https://www.typescriptlang.org) and some legacy [JSDoc](https://jsdoc.app/). It describes the JavaScript objects and
functions that make up the software platform.
* The [Development Process](process/) document describes the
* The [Development Process](process/) document describes the
Open MCT software development cycle.
* The [Tutorials](https://github.com/nasa/openmct-tutorial) give examples of extending the platform to add
functionality, and integrate with data sources.
* The [tutorial](https://github.com/nasa/openmct-tutorial) and [plugin template](https://github.com/nasa/openmct-hello) give examples of extending the platform to add
functionality and integrate with data sources.

View File

@ -35,7 +35,7 @@
* @property {string} type the type of domain object to create (e.g.: "Sine Wave Generator").
* @property {string} [name] the desired name of the created domain object.
* @property {string | import('../src/api/objects/ObjectAPI').Identifier} [parent] the Identifier or uuid of the parent object.
* @property {Object<string, string>} [customParameters] any additional parameters to be passed to the domain object's form. E.g. '[aria-label="Data Rate (hz)"]': {'0.1'}
* @property {Record<string, string>} [customParameters] any additional parameters to be passed to the domain object's form. E.g. '[aria-label="Data Rate (hz)"]': {'0.1'}
*/
/**

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import EventEmitter from 'EventEmitter';
import { EventEmitter } from 'eventemitter3';
import { v4 as uuid } from 'uuid';
import createExampleUser from './exampleUserCreator.js';

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import EventEmitter from 'EventEmitter';
import { EventEmitter } from 'eventemitter3';
export default class SinewaveLimitProvider extends EventEmitter {
#openmct;

View File

@ -22,13 +22,38 @@
const matcher = /\/openmct.js$/;
if (document.currentScript) {
// @ts-ignore
let src = document.currentScript.src;
if (src && matcher.test(src)) {
// eslint-disable-next-line no-undef
// @ts-ignore
__webpack_public_path__ = src.replace(matcher, '') + '/';
}
}
import { MCT } from './src/MCT.js';
const openmct = new MCT();
export default openmct;
/**
* @typedef {MCT} OpenMCT
* @typedef {import('./src/api/objects/ObjectAPI.js').DomainObject} DomainObject
* @typedef {import('./src/api/objects/ObjectAPI.js').Identifier} Identifier
* @typedef {import('./src/api/objects/Transaction.js').default} Transaction
* @typedef {import('./src/api/actions/ActionsAPI.js').Action} Action
* @typedef {import('./src/api/actions/ActionCollection.js').default} ActionCollection
* @typedef {import('./src/api/composition/CompositionCollection.js').default} CompositionCollection
* @typedef {import('./src/api/composition/CompositionProvider.js').default} CompositionProvider
* @typedef {import('./src/ui/registries/ViewRegistry.js').ViewProvider} ViewProvider
* @typedef {import('./src/ui/registries/ViewRegistry.js').View} View
*
* @typedef {DomainObject[]} ObjectPath
* @typedef {(...args: any[]) => (openmct: OpenMCT) => void} OpenMCTPlugin
* An OpenMCT Plugin returns a function that receives an instance of
* the OpenMCT API and uses it to install itself.
*/
/**
* @typedef {Object} BuildInfo
* @property {string} version
@ -36,46 +61,3 @@ if (document.currentScript) {
* @property {string} revision
* @property {string} branch
*/
/**
* @typedef {Object} OpenMCT
* @property {BuildInfo} buildInfo
* @property {import('./src/selection/Selection').default} selection
* @property {import('./src/api/time/TimeAPI').default} time
* @property {import('./src/api/composition/CompositionAPI').default} composition
* @property {import('./src/ui/registries/ViewRegistry').default} objectViews
* @property {import('./src/ui/registries/InspectorViewRegistry').default} inspectorViews
* @property {import('./src/ui/registries/ViewRegistry').default} propertyEditors
* @property {import('./src/ui/registries/ToolbarRegistry').default} toolbars
* @property {import('./src/api/types/TypeRegistry').default} types
* @property {import('./src/api/objects/ObjectAPI').default} objects
* @property {import('./src/api/telemetry/TelemetryAPI').default} telemetry
* @property {import('./src/api/indicators/IndicatorAPI').default} indicators
* @property {import('./src/api/user/UserAPI').default} user
* @property {import('./src/api/notifications/NotificationAPI').default} notifications
* @property {import('./src/api/Editor').default} editor
* @property {import('./src/api/overlays/OverlayAPI')} overlays
* @property {import('./src/api/tooltips/ToolTipAPI')} tooltips
* @property {import('./src/api/menu/MenuAPI').default} menus
* @property {import('./src/api/actions/ActionsAPI').default} actions
* @property {import('./src/api/status/StatusAPI').default} status
* @property {import('./src/api/priority/PriorityAPI').default} priority
* @property {import('./src/ui/router/ApplicationRouter')} router
* @property {import('./src/api/faultmanagement/FaultManagementAPI').default} faults
* @property {import('./src/api/forms/FormsAPI').default} forms
* @property {import('./src/api/Branding').default} branding
* @property {import('./src/api/annotation/AnnotationAPI').default} annotation
* @property {{(plugin: OpenMCTPlugin) => void}} install
* @property {{() => string}} getAssetPath
* @property {{(assetPath: string) => void}} setAssetPath
* @property {{(domElement: HTMLElement, isHeadlessMode: boolean) => void}} start
* @property {{() => void}} startHeadless
* @property {{() => void}} destroy
* @property {OpenMCTPlugin[]} plugins
* @property {OpenMCTComponent[]} components
*/
import { MCT } from './src/MCT.js';
/** @type {OpenMCT} */
const openmct = new MCT();
export default openmct;

View File

@ -19,8 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/* eslint-disable no-undef */
import EventEmitter from 'EventEmitter';
import { EventEmitter } from 'eventemitter3';
import { createApp, markRaw } from 'vue';
import ActionsAPI from './api/actions/ActionsAPI.js';
@ -73,10 +72,25 @@ import Browse from './ui/router/Browse.js';
* The Open MCT application. This may be configured by installing plugins
* or registering extensions before the application is started.
* @constructor
* @memberof module:openmct
* @extends EventEmitter
*/
export class MCT extends EventEmitter {
/**
* @type {import('openmct.js').BuildInfo}
*/
buildInfo;
/**
* @type {string}
*/
defaultClock;
/**
* @type {Record<string, OpenMCTPlugin>}
*/
plugins;
/**
* Tracks current selection state of the application.
* @type {Selection}
*/
selection;
constructor() {
super();
@ -89,21 +103,11 @@ export class MCT extends EventEmitter {
this.destroy = this.destroy.bind(this);
this.defaultClock = 'local';
this.plugins = plugins;
/**
* Tracks current selection state of the application.
* @private
*/
this.selection = new Selection(this);
/**
* MCT's time conductor, which may be used to synchronize view contents
* for telemetry- or time-based views.
* @type {module:openmct.TimeConductor}
* @memberof module:openmct.MCT#
* @name conductor
* @type {TimeAPI}
*/
this.time = new TimeAPI(this);
@ -116,9 +120,7 @@ export class MCT extends EventEmitter {
* `composition` may be called as a function, in which case it acts
* as [`composition.get`]{@link module:openmct.CompositionAPI#get}.
*
* @type {module:openmct.CompositionAPI}
* @memberof module:openmct.MCT#
* @name composition
* @type {CompositionAPI}
*/
this.composition = new CompositionAPI(this);
@ -126,9 +128,7 @@ export class MCT extends EventEmitter {
* Registry for views of domain objects which should appear in the
* main viewing area.
*
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name objectViews
* @type {ViewRegistry}
*/
this.objectViews = new ViewRegistry();
@ -136,9 +136,7 @@ export class MCT extends EventEmitter {
* Registry for views which should appear in the Inspector area.
* These views will be chosen based on the selection state.
*
* @type {module:openmct.InspectorViewRegistry}
* @memberof module:openmct.MCT#
* @name inspectorViews
* @type {InspectorViewRegistry}
*/
this.inspectorViews = new InspectorViewRegistry();
@ -147,9 +145,7 @@ export class MCT extends EventEmitter {
* dialogs, and similar user interface elements used for
* modifying domain objects external to its regular views.
*
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name propertyEditors
* @type {ViewRegistry}
*/
this.propertyEditors = new ViewRegistry();
@ -157,9 +153,7 @@ export class MCT extends EventEmitter {
* Registry for views which should appear in the toolbar area while
* editing. These views will be chosen based on the selection state.
*
* @type {module:openmct.ToolbarRegistry}
* @memberof module:openmct.MCT#
* @name toolbars
* @type {ToolbarRegistry}
*/
this.toolbars = new ToolbarRegistry();
@ -167,9 +161,7 @@ export class MCT extends EventEmitter {
* Registry for domain object types which may exist within this
* instance of Open MCT.
*
* @type {module:openmct.TypeRegistry}
* @memberof module:openmct.MCT#
* @name types
* @type {TypeRegistry}
*/
this.types = new TypeRegistry();
@ -177,9 +169,7 @@ export class MCT extends EventEmitter {
* An interface for interacting with domain objects and the domain
* object hierarchy.
*
* @type {module:openmct.ObjectAPI}
* @memberof module:openmct.MCT#
* @name objects
* @type {ObjectAPI}
*/
this.objects = new ObjectAPI(this.types, this);
@ -187,49 +177,100 @@ export class MCT extends EventEmitter {
* An interface for retrieving and interpreting telemetry data associated
* with a domain object.
*
* @type {module:openmct.TelemetryAPI}
* @memberof module:openmct.MCT#
* @name telemetry
* @type {TelemetryAPI}
*/
this.telemetry = new TelemetryAPI(this);
/**
* An interface for creating new indicators and changing them dynamically.
*
* @type {module:openmct.IndicatorAPI}
* @memberof module:openmct.MCT#
* @name indicators
* @type {IndicatorAPI}
*/
this.indicators = new IndicatorAPI(this);
/**
* MCT's user awareness management, to enable user and
* role specific functionality.
* @type {module:openmct.UserAPI}
* @memberof module:openmct.MCT#
* @name user
* @type {UserAPI}
*/
this.user = new UserAPI(this);
/**
* An interface for managing notifications and alerts.
* @type {NotificationAPI}
*/
this.notifications = new NotificationAPI();
/**
* An interface for editing domain objects.
* @type {EditorAPI}
*/
this.editor = new EditorAPI(this);
/**
* An interface for managing overlays.
* @type {OverlayAPI}
*/
this.overlays = new OverlayAPI();
/**
* An interface for managing tooltips.
* @type {ToolTipAPI}
*/
this.tooltips = new ToolTipAPI();
/**
* An interface for managing menus.
* @type {MenuAPI}
*/
this.menus = new MenuAPI(this);
/**
* An interface for managing menu actions.
* @type {ActionsAPI}
*/
this.actions = new ActionsAPI(this);
/**
* An interface for managing statuses.
* @type {StatusAPI}
*/
this.status = new StatusAPI(this);
/**
* An object defining constants for priority levels.
* @type {PriorityAPI}
*/
this.priority = PriorityAPI;
/**
* An interface for routing application traffic.
* @type {ApplicationRouter}
*/
this.router = new ApplicationRouter(this);
/**
* An interface for managing faults.
* @type {FaultManagementAPI}
*/
this.faults = new FaultManagementAPI(this);
/**
* An interface for managing forms.
* @type {FormsAPI}
*/
this.forms = new FormsAPI(this);
/**
* An interface for branding the application.
* @type {BrandingAPI}
*/
this.branding = BrandingAPI;
/**
* MCT's annotation API that enables
* human-created comments and categorization linked to data products
* @type {module:openmct.AnnotationAPI}
* @memberof module:openmct.MCT#
* @name annotation
* @type {AnnotationAPI}
*/
this.annotation = new AnnotationAPI(this);
@ -268,7 +309,6 @@ export class MCT extends EventEmitter {
}
/**
* Set path to where assets are hosted. This should be the path to main.js.
* @memberof module:openmct.MCT#
* @method setAssetPath
*/
setAssetPath(assetPath) {
@ -276,7 +316,6 @@ export class MCT extends EventEmitter {
}
/**
* Get path to where assets are hosted.
* @memberof module:openmct.MCT#
* @method getAssetPath
*/
getAssetPath() {
@ -295,9 +334,8 @@ export class MCT extends EventEmitter {
* Start running Open MCT. This should be called only after any plugins
* have been installed.
* @fires module:openmct.MCT~start
* @memberof module:openmct.MCT#
* @method start
* @param {HTMLElement} [domElement] the DOM element in which to run
* @param {Element?} domElement the DOM element in which to run
* MCT; if undefined, MCT will be run in the body of the document
*/
start(domElement = document.body.firstElementChild, isHeadlessMode = false) {
@ -330,7 +368,6 @@ export class MCT extends EventEmitter {
* Fired by [MCT]{@link module:openmct.MCT} when the application
* is started.
* @event start
* @memberof module:openmct.MCT~
*/
if (!isHeadlessMode) {
const appLayout = createApp(Layout);
@ -361,7 +398,6 @@ export class MCT extends EventEmitter {
*
* @param {Function} plugin a plugin install function which will be
* invoked with the mct instance.
* @memberof module:openmct.MCT#
*/
install(plugin) {
plugin(this);
@ -372,3 +408,7 @@ export class MCT extends EventEmitter {
this.emit('destroy');
}
}
/**
* @typedef {import('../openmct.js').OpenMCTPlugin} OpenMCTPlugin
*/

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import EventEmitter from 'EventEmitter';
import { EventEmitter } from 'eventemitter3';
export default class Editor extends EventEmitter {
constructor(openmct) {

View File

@ -20,10 +20,22 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import EventEmitter from 'EventEmitter';
import { EventEmitter } from 'eventemitter3';
import _ from 'lodash';
/**
* A collection of actions applicable to a domain object.
* @extends EventEmitter
*/
class ActionCollection extends EventEmitter {
/**
* Creates an instance of ActionCollection.
* @param {Object.<string, Action>} applicableActions - The actions applicable to the domain object.
* @param {import('openmct').ObjectPath} objectPath - The path to the domain object.
* @param {import('openmct').View} view - The view displaying the domain object.
* @param {import('openmct').OpenMCT} openmct - The Open MCT API.
* @param {boolean} skipEnvironmentObservers - Whether to skip setting up environment observers.
*/
constructor(applicableActions, objectPath, view, openmct, skipEnvironmentObservers) {
super();
@ -48,6 +60,10 @@ class ActionCollection extends EventEmitter {
}
}
/**
* Disables the specified actions.
* @param {string[]} actionKeys - The keys of the actions to disable.
*/
disable(actionKeys) {
actionKeys.forEach((actionKey) => {
if (this.applicableActions[actionKey]) {
@ -57,6 +73,10 @@ class ActionCollection extends EventEmitter {
this._update();
}
/**
* Enables the specified actions.
* @param {string[]} actionKeys - The keys of the actions to enable.
*/
enable(actionKeys) {
actionKeys.forEach((actionKey) => {
if (this.applicableActions[actionKey]) {
@ -66,6 +86,10 @@ class ActionCollection extends EventEmitter {
this._update();
}
/**
* Hides the specified actions.
* @param {string[]} actionKeys - The keys of the actions to hide.
*/
hide(actionKeys) {
actionKeys.forEach((actionKey) => {
if (this.applicableActions[actionKey]) {
@ -75,6 +99,10 @@ class ActionCollection extends EventEmitter {
this._update();
}
/**
* Shows the specified actions.
* @param {string[]} actionKeys - The keys of the actions to show.
*/
show(actionKeys) {
actionKeys.forEach((actionKey) => {
if (this.applicableActions[actionKey]) {
@ -84,6 +112,9 @@ class ActionCollection extends EventEmitter {
this._update();
}
/**
* Destroys the action collection, removing all listeners and observers.
*/
destroy() {
if (!this.skipEnvironmentObservers) {
this.objectUnsubscribes.forEach((unsubscribe) => {
@ -97,6 +128,10 @@ class ActionCollection extends EventEmitter {
this.removeAllListeners();
}
/**
* Gets all visible actions.
* @returns {Action[]} An array of visible actions.
*/
getVisibleActions() {
let actionsArray = Object.keys(this.applicableActions);
let visibleActions = [];
@ -112,6 +147,10 @@ class ActionCollection extends EventEmitter {
return visibleActions;
}
/**
* Gets all actions that should be shown in the status bar.
* @returns {Action[]} An array of status bar actions.
*/
getStatusBarActions() {
let actionsArray = Object.keys(this.applicableActions);
let statusBarActions = [];
@ -127,17 +166,34 @@ class ActionCollection extends EventEmitter {
return statusBarActions;
}
/**
* Gets the object containing all applicable actions.
* @returns {Object.<string, Action>} The object of applicable actions.
*/
getActionsObject() {
return this.applicableActions;
}
/**
* Emits an update event with the current applicable actions.
* @private
*/
_update() {
this.emit('update', this.applicableActions);
}
/**
* Sets up observers for the object path.
* @private
*/
_observeObjectPath() {
let actionCollection = this;
/**
* Updates an object with new properties.
* @param {Object} oldObject - The object to update.
* @param {Object} newObject - The object containing new properties.
*/
function updateObject(oldObject, newObject) {
Object.assign(oldObject, newObject);
@ -157,6 +213,10 @@ class ActionCollection extends EventEmitter {
});
}
/**
* Updates the applicable actions.
* @private
*/
_updateActions() {
let newApplicableActions = this.openmct.actions._applicableActions(this.objectPath, this.view);
@ -167,6 +227,13 @@ class ActionCollection extends EventEmitter {
this._update();
}
/**
* Merges old and new actions, preserving existing action states.
* @param {Object.<string, Action>} oldActions - The existing actions.
* @param {Object.<string, Action>} newActions - The new actions.
* @returns {Object.<string, Action>} The merged actions.
* @private
*/
_mergeOldAndNewActions(oldActions, newActions) {
let mergedActions = {};
Object.keys(newActions).forEach((key) => {
@ -182,3 +249,7 @@ class ActionCollection extends EventEmitter {
}
export default ActionCollection;
/**
* @typedef {import('openmct').Action} Action
*/

View File

@ -19,19 +19,30 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import EventEmitter from 'EventEmitter';
import { EventEmitter } from 'eventemitter3';
import _ from 'lodash';
import ActionCollection from './ActionCollection.js';
/**
* The ActionsAPI manages the registration and retrieval of actions in Open MCT.
* @extends EventEmitter
*/
class ActionsAPI extends EventEmitter {
/**
* @param {import('openmct').OpenMCT} openmct - The Open MCT instance
*/
constructor(openmct) {
super();
/** @type {Object<string, Action>} */
this._allActions = {};
/** @type {WeakMap<Object, ActionCollection>} */
this._actionCollections = new WeakMap();
/** @type {import('openmct').OpenMCT} */
this._openmct = openmct;
/** @type {string[]} */
this._groupOrder = ['windowing', 'undefined', 'view', 'action', 'export', 'import'];
this.register = this.register.bind(this);
@ -40,14 +51,29 @@ class ActionsAPI extends EventEmitter {
this._updateCachedActionCollections = this._updateCachedActionCollections.bind(this);
}
/**
* Register an action with the API.
* @param {Action} actionDefinition - The definition of the action to register
*/
register(actionDefinition) {
this._allActions[actionDefinition.key] = actionDefinition;
}
/**
* Get an action by its key.
* @param {string} key - The key of the action to retrieve
* @returns {Action|undefined} The action definition, or undefined if not found
*/
getAction(key) {
return this._allActions[key];
}
/**
* Get or create an ActionCollection for a given object path and view.
* @param {import('openmct').ObjectPath} objectPath - The path of the object
* @param {import('openmct').View} [view] - The view object
* @returns {ActionCollection} The ActionCollection for the given object path and view
*/
getActionsCollection(objectPath, view) {
if (view) {
return (
@ -59,14 +85,31 @@ class ActionsAPI extends EventEmitter {
}
}
/**
* Update the order in which action groups are displayed.
* @param {string[]} groupArray - An array of group names in the desired order
*/
updateGroupOrder(groupArray) {
this._groupOrder = groupArray;
}
/**
* Get a cached ActionCollection for a given view.
* @param {import('openmct').ObjectPath} objectPath - The path of the object
* @param {Object} view - The view object
* @returns {ActionCollection|undefined} The cached ActionCollection, or undefined if not found
*/
_getCachedActionCollection(objectPath, view) {
return this._actionCollections.get(view);
}
/**
* Create a new ActionCollection.
* @param {import('openmct').ObjectPath} objectPath - The path of the object
* @param {import('openmct').View} [view] - The view object
* @param {boolean} skipEnvironmentObservers - Whether to skip environment observers
* @returns {ActionCollection} The new ActionCollection
*/
_newActionCollection(objectPath, view, skipEnvironmentObservers) {
let applicableActions = this._applicableActions(objectPath, view);
@ -84,20 +127,35 @@ class ActionsAPI extends EventEmitter {
return actionCollection;
}
/**
* Cache an ActionCollection for a given view.
* @param {import('openmct').View} view - The view object
* @param {ActionCollection} actionCollection - The ActionCollection to cache
*/
_cacheActionCollection(view, actionCollection) {
this._actionCollections.set(view, actionCollection);
actionCollection.on('destroy', this._updateCachedActionCollections);
}
_updateCachedActionCollections(key) {
if (this._actionCollections.has(key)) {
let actionCollection = this._actionCollections.get(key);
/**
* Update cached ActionCollections when destroyed.
* @param {import('openmct').View} view - The key (View object)of the destroyed ActionCollection
*/
_updateCachedActionCollections(view) {
if (this._actionCollections.has(view)) {
let actionCollection = this._actionCollections.get(view);
actionCollection.off('destroy', this._updateCachedActionCollections);
delete actionCollection.applicableActions;
this._actionCollections.delete(key);
this._actionCollections.delete(view);
}
}
/**
* Get applicable actions for a given object path and view.
* @param {import('openmct').ObjectPath} objectPath - The path of the object
* @param {import('openmct').View} [view] - The view object
* @returns {Object<string, Action>} A dictionary of applicable actions keyed by action key
*/
_applicableActions(objectPath, view) {
let actionsObject = {};
@ -120,6 +178,11 @@ class ActionsAPI extends EventEmitter {
return actionsObject;
}
/**
* Group and sort actions based on their group and priority.
* @param {Action[]|Object<string, Action>} actionsArray - An array or object of actions to group and sort
* @returns {Action[][]} An array of grouped and sorted action arrays
*/
_groupAndSortActions(actionsArray = []) {
if (!Array.isArray(actionsArray) && typeof actionsArray === 'object') {
actionsArray = Object.keys(actionsArray).map((key) => actionsArray[key]);
@ -153,3 +216,19 @@ class ActionsAPI extends EventEmitter {
}
export default ActionsAPI;
/**
* @typedef {Object} Action
* @property {string} name - The display name of the action.
* @property {string} key - A unique identifier for the action.
* @property {string} description - A brief description of what the action does.
* @property {string} cssClass - The CSS class for the action's icon.
* @property {string} [group] - The group this action belongs to (e.g., 'action', 'import').
* @property {number} [priority] - The priority of the action within its group (controls the order of the actions in the menu).
* @property {boolean} [isHidden] - Whether the action should be hidden from menus.
* @property {(objectPath: ObjectPath, view: View) => void} invoke - Executes the action.
* @property {(objectPath: ObjectPath, view: View) => boolean} appliesTo - Determines if the action is applicable to the given object path.
*/
/** @typedef {import('openmct').ObjectPath} ObjectPath */