Compare commits
1 Commits
bugfix/iss
...
context-me
Author | SHA1 | Date | |
---|---|---|---|
485e948abe |
@ -1,198 +1,36 @@
|
|||||||
version: 2.1
|
version: 2
|
||||||
executors:
|
|
||||||
pw-focal-development:
|
|
||||||
docker:
|
|
||||||
- image: mcr.microsoft.com/playwright:v1.19.1-focal
|
|
||||||
environment:
|
|
||||||
NODE_ENV: development # Needed to ensure 'dist' folder created and devDependencies installed
|
|
||||||
parameters:
|
|
||||||
BUST_CACHE:
|
|
||||||
description: "Set this with the CircleCI UI Trigger Workflow button (boolean = true) to bust the cache!"
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
commands:
|
|
||||||
build_and_install:
|
|
||||||
description: "All steps used to build and install. Will not work on node10"
|
|
||||||
parameters:
|
|
||||||
node-version:
|
|
||||||
type: string
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- restore_cache_cmd:
|
|
||||||
node-version: << parameters.node-version >>
|
|
||||||
- node/install:
|
|
||||||
install-npm: true
|
|
||||||
node-version: << parameters.node-version >>
|
|
||||||
- run: npm install
|
|
||||||
restore_cache_cmd:
|
|
||||||
description: "Custom command for restoring cache with the ability to bust cache. When BUST_CACHE is set to true, jobs will not restore cache"
|
|
||||||
parameters:
|
|
||||||
node-version:
|
|
||||||
type: string
|
|
||||||
steps:
|
|
||||||
- when:
|
|
||||||
condition:
|
|
||||||
equal: [false, << pipeline.parameters.BUST_CACHE >> ]
|
|
||||||
steps:
|
|
||||||
- restore_cache:
|
|
||||||
key: deps-{{ .Branch }}--<< parameters.node-version >>--{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }}
|
|
||||||
save_cache_cmd:
|
|
||||||
description: "Custom command for saving cache."
|
|
||||||
parameters:
|
|
||||||
node-version:
|
|
||||||
type: string
|
|
||||||
steps:
|
|
||||||
- save_cache:
|
|
||||||
key: deps-{{ .Branch }}--<< parameters.node-version >>--{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }}
|
|
||||||
paths:
|
|
||||||
- ~/.npm
|
|
||||||
- node_modules
|
|
||||||
generate_and_store_version_and_filesystem_artifacts:
|
|
||||||
description: "Track important packages and files"
|
|
||||||
steps:
|
|
||||||
- run: |
|
|
||||||
mkdir /tmp/artifacts
|
|
||||||
printenv NODE_ENV >> /tmp/artifacts/NODE_ENV.txt
|
|
||||||
npm -v >> /tmp/artifacts/npm-version.txt
|
|
||||||
node -v >> /tmp/artifacts/node-version.txt
|
|
||||||
ls -latR >> /tmp/artifacts/dir.txt
|
|
||||||
- store_artifacts:
|
|
||||||
path: /tmp/artifacts/
|
|
||||||
upload_code_covio:
|
|
||||||
description: "Command to upload code coverage reports to codecov.io"
|
|
||||||
steps:
|
|
||||||
- run: curl -Os https://uploader.codecov.io/latest/linux/codecov;chmod +x codecov;./codecov
|
|
||||||
orbs:
|
|
||||||
node: circleci/node@4.9.0
|
|
||||||
browser-tools: circleci/browser-tools@1.2.3
|
|
||||||
jobs:
|
jobs:
|
||||||
npm-audit:
|
build:
|
||||||
parameters:
|
docker:
|
||||||
node-version:
|
- image: circleci/node:8-browsers
|
||||||
type: string
|
environment:
|
||||||
executor: pw-focal-development
|
CHROME_BIN: "/usr/bin/google-chrome"
|
||||||
steps:
|
steps:
|
||||||
- build_and_install:
|
- checkout
|
||||||
node-version: <<parameters.node-version>>
|
- run:
|
||||||
- run: npm audit --audit-level=low
|
name: Update npm
|
||||||
- generate_and_store_version_and_filesystem_artifacts
|
command: 'sudo npm install -g npm@latest'
|
||||||
lint:
|
- restore_cache:
|
||||||
parameters:
|
key: dependency-cache-{{ checksum "package.json" }}
|
||||||
node-version:
|
- run:
|
||||||
type: string
|
name: Installing dependencies (npm install)
|
||||||
executor: pw-focal-development
|
command: npm install
|
||||||
steps:
|
- save_cache:
|
||||||
- build_and_install:
|
key: dependency-cache-{{ checksum "package.json" }}
|
||||||
node-version: <<parameters.node-version>>
|
paths:
|
||||||
- run: npm run lint
|
- node_modules
|
||||||
- generate_and_store_version_and_filesystem_artifacts
|
- run:
|
||||||
unit-test:
|
name: npm run test
|
||||||
parameters:
|
command: npm run test
|
||||||
node-version:
|
- run:
|
||||||
type: string
|
name: npm run lint
|
||||||
browser:
|
command: npm run lint
|
||||||
type: string
|
- store_artifacts:
|
||||||
executor: pw-focal-development
|
path: dist
|
||||||
steps:
|
prefix: dist
|
||||||
- build_and_install:
|
|
||||||
node-version: <<parameters.node-version>>
|
|
||||||
- when:
|
|
||||||
condition:
|
|
||||||
equal: [ "FirefoxESR", <<parameters.browser>> ]
|
|
||||||
steps:
|
|
||||||
- browser-tools/install-firefox:
|
|
||||||
version: "91.4.0esr" #https://archive.mozilla.org/pub/firefox/releases/
|
|
||||||
- when:
|
|
||||||
condition:
|
|
||||||
equal: [ "FirefoxHeadless", <<parameters.browser>> ]
|
|
||||||
steps:
|
|
||||||
- browser-tools/install-firefox
|
|
||||||
- when:
|
|
||||||
condition:
|
|
||||||
equal: [ "ChromeHeadless", <<parameters.browser>> ]
|
|
||||||
steps:
|
|
||||||
- browser-tools/install-chrome:
|
|
||||||
replace-existing: false
|
|
||||||
- run: npm run test:coverage -- --browsers=<<parameters.browser>>
|
|
||||||
- save_cache_cmd:
|
|
||||||
node-version: <<parameters.node-version>>
|
|
||||||
- store_test_results:
|
|
||||||
path: dist/reports/tests/
|
|
||||||
- store_artifacts:
|
|
||||||
path: dist/reports/
|
|
||||||
- generate_and_store_version_and_filesystem_artifacts
|
|
||||||
e2e-test:
|
|
||||||
parameters:
|
|
||||||
node-version:
|
|
||||||
type: string
|
|
||||||
suite:
|
|
||||||
type: string
|
|
||||||
executor: pw-focal-development
|
|
||||||
steps:
|
|
||||||
- build_and_install:
|
|
||||||
node-version: <<parameters.node-version>>
|
|
||||||
- run: npx playwright install
|
|
||||||
- run: npm run test:e2e:<<parameters.suite>>
|
|
||||||
- store_test_results:
|
|
||||||
path: test-results/results.xml
|
|
||||||
- store_artifacts:
|
|
||||||
path: test-results
|
|
||||||
- generate_and_store_version_and_filesystem_artifacts
|
|
||||||
workflows:
|
workflows:
|
||||||
overall-circleci-commit-status: #These jobs run on every commit
|
version: 2
|
||||||
|
test:
|
||||||
jobs:
|
jobs:
|
||||||
- lint:
|
- build
|
||||||
node-version: lts/gallium
|
|
||||||
- unit-test:
|
|
||||||
name: node12-chrome
|
|
||||||
node-version: lts/erbium
|
|
||||||
browser: ChromeHeadless
|
|
||||||
- unit-test:
|
|
||||||
name: node14-chrome
|
|
||||||
node-version: lts/fermium
|
|
||||||
browser: ChromeHeadless
|
|
||||||
post-steps:
|
|
||||||
- upload_code_covio
|
|
||||||
- unit-test:
|
|
||||||
name: node16-chrome
|
|
||||||
node-version: lts/gallium
|
|
||||||
browser: ChromeHeadless
|
|
||||||
- e2e-test:
|
|
||||||
name: e2e-ci
|
|
||||||
node-version: lts/gallium
|
|
||||||
suite: ci
|
|
||||||
the-nightly: #These jobs do not run on PRs, but against master at night
|
|
||||||
jobs:
|
|
||||||
- unit-test:
|
|
||||||
name: node12-firefoxESR-nightly
|
|
||||||
node-version: lts/erbium
|
|
||||||
browser: FirefoxESR
|
|
||||||
- unit-test:
|
|
||||||
name: node12-chrome-nightly
|
|
||||||
node-version: lts/erbium
|
|
||||||
browser: ChromeHeadless
|
|
||||||
- unit-test:
|
|
||||||
name: node14-firefox-nightly
|
|
||||||
node-version: lts/fermium
|
|
||||||
browser: FirefoxHeadless
|
|
||||||
- unit-test:
|
|
||||||
name: node14-chrome-nightly
|
|
||||||
node-version: lts/fermium
|
|
||||||
browser: ChromeHeadless
|
|
||||||
- unit-test:
|
|
||||||
name: node16-chrome-nightly
|
|
||||||
node-version: lts/gallium
|
|
||||||
browser: ChromeHeadless
|
|
||||||
- npm-audit:
|
|
||||||
node-version: lts/gallium
|
|
||||||
- e2e-test:
|
|
||||||
name: e2e-full-nightly
|
|
||||||
node-version: lts/gallium
|
|
||||||
suite: full
|
|
||||||
triggers:
|
|
||||||
- schedule:
|
|
||||||
cron: "0 0 * * *"
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
|
207
.eslintrc.js
@ -1,4 +1,3 @@
|
|||||||
const LEGACY_FILES = ["example/**"];
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
@ -6,17 +5,9 @@ module.exports = {
|
|||||||
"jasmine": true,
|
"jasmine": true,
|
||||||
"amd": true
|
"amd": true
|
||||||
},
|
},
|
||||||
"globals": {
|
"extends": "eslint:recommended",
|
||||||
"_": "readonly"
|
"parser": "babel-eslint",
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:vue/recommended",
|
|
||||||
"plugin:you-dont-need-lodash-underscore/compatible"
|
|
||||||
],
|
|
||||||
"parser": "vue-eslint-parser",
|
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"parser": "babel-eslint",
|
|
||||||
"allowImportExportEverywhere": true,
|
"allowImportExportEverywhere": true,
|
||||||
"ecmaVersion": 2015,
|
"ecmaVersion": 2015,
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
@ -24,9 +15,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"you-dont-need-lodash-underscore/omit": "off",
|
|
||||||
"you-dont-need-lodash-underscore/throttle": "off",
|
|
||||||
"you-dont-need-lodash-underscore/flatten": "off",
|
|
||||||
"no-bitwise": "error",
|
"no-bitwise": "error",
|
||||||
"curly": "error",
|
"curly": "error",
|
||||||
"eqeqeq": "error",
|
"eqeqeq": "error",
|
||||||
@ -54,7 +42,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
"anonymous": "always",
|
"anonymous": "always",
|
||||||
"asyncArrow": "always",
|
"asyncArrow": "always",
|
||||||
"named": "never"
|
"named": "never",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"array-bracket-spacing": "error",
|
"array-bracket-spacing": "error",
|
||||||
@ -70,200 +58,21 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dot-notation": "error",
|
"dot-notation": "error",
|
||||||
"indent": ["error", 4],
|
"indent": ["error", 4]
|
||||||
|
|
||||||
// https://eslint.org/docs/rules/no-case-declarations
|
|
||||||
"no-case-declarations": "error",
|
|
||||||
// https://eslint.org/docs/rules/max-classes-per-file
|
|
||||||
"max-classes-per-file": ["error", 1],
|
|
||||||
// https://eslint.org/docs/rules/no-eq-null
|
|
||||||
"no-eq-null": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-eval
|
|
||||||
"no-eval": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-floating-decimal
|
|
||||||
"no-floating-decimal": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-implicit-globals
|
|
||||||
"no-implicit-globals": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-implied-eval
|
|
||||||
"no-implied-eval": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-lone-blocks
|
|
||||||
"no-lone-blocks": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-loop-func
|
|
||||||
"no-loop-func": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-new-func
|
|
||||||
"no-new-func": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-new-wrappers
|
|
||||||
"no-new-wrappers": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-octal-escape
|
|
||||||
"no-octal-escape": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-proto
|
|
||||||
"no-proto": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-return-await
|
|
||||||
"no-return-await": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-script-url
|
|
||||||
"no-script-url": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-self-compare
|
|
||||||
"no-self-compare": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-sequences
|
|
||||||
"no-sequences": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-unmodified-loop-condition
|
|
||||||
"no-unmodified-loop-condition": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-useless-call
|
|
||||||
"no-useless-call": "error",
|
|
||||||
// https://eslint.org/docs/rules/wrap-iife
|
|
||||||
"wrap-iife": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-nested-ternary
|
|
||||||
"no-nested-ternary": "error",
|
|
||||||
// https://eslint.org/docs/rules/switch-colon-spacing
|
|
||||||
"switch-colon-spacing": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-useless-computed-key
|
|
||||||
"no-useless-computed-key": "error",
|
|
||||||
// https://eslint.org/docs/rules/rest-spread-spacing
|
|
||||||
"rest-spread-spacing": ["error"],
|
|
||||||
// https://eslint.org/docs/rules/no-var
|
|
||||||
"no-var": "error",
|
|
||||||
// https://eslint.org/docs/rules/one-var
|
|
||||||
"one-var": ["error", "never"],
|
|
||||||
// https://eslint.org/docs/rules/default-case-last
|
|
||||||
"default-case-last": "error",
|
|
||||||
// https://eslint.org/docs/rules/default-param-last
|
|
||||||
"default-param-last": "error",
|
|
||||||
// https://eslint.org/docs/rules/grouped-accessor-pairs
|
|
||||||
"grouped-accessor-pairs": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-constructor-return
|
|
||||||
"no-constructor-return": "error",
|
|
||||||
// https://eslint.org/docs/rules/array-callback-return
|
|
||||||
"array-callback-return": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-invalid-this
|
|
||||||
"no-invalid-this": "error", // Believe this one actually surfaces some bugs
|
|
||||||
// https://eslint.org/docs/rules/func-style
|
|
||||||
"func-style": ["error", "declaration"],
|
|
||||||
// https://eslint.org/docs/rules/no-unused-expressions
|
|
||||||
"no-unused-expressions": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-useless-concat
|
|
||||||
"no-useless-concat": "error",
|
|
||||||
// https://eslint.org/docs/rules/radix
|
|
||||||
"radix": "error",
|
|
||||||
// https://eslint.org/docs/rules/require-await
|
|
||||||
"require-await": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-alert
|
|
||||||
"no-alert": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-useless-constructor
|
|
||||||
"no-useless-constructor": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-duplicate-imports
|
|
||||||
"no-duplicate-imports": "error",
|
|
||||||
|
|
||||||
// https://eslint.org/docs/rules/no-implicit-coercion
|
|
||||||
"no-implicit-coercion": "error",
|
|
||||||
//https://eslint.org/docs/rules/no-unneeded-ternary
|
|
||||||
"no-unneeded-ternary": "error",
|
|
||||||
// https://eslint.org/docs/rules/semi
|
|
||||||
"semi": ["error", "always"],
|
|
||||||
// https://eslint.org/docs/rules/no-multi-spaces
|
|
||||||
"no-multi-spaces": "error",
|
|
||||||
// https://eslint.org/docs/rules/key-spacing
|
|
||||||
"key-spacing": ["error", {
|
|
||||||
"afterColon": true
|
|
||||||
}],
|
|
||||||
// https://eslint.org/docs/rules/keyword-spacing
|
|
||||||
"keyword-spacing": ["error", {
|
|
||||||
"before": true,
|
|
||||||
"after": true
|
|
||||||
}],
|
|
||||||
// https://eslint.org/docs/rules/comma-spacing
|
|
||||||
// Also requires one line code fix
|
|
||||||
"comma-spacing": ["error", {
|
|
||||||
"after": true
|
|
||||||
}],
|
|
||||||
//https://eslint.org/docs/rules/no-whitespace-before-property
|
|
||||||
"no-whitespace-before-property": "error",
|
|
||||||
// https://eslint.org/docs/rules/object-curly-newline
|
|
||||||
"object-curly-newline": ["error", {
|
|
||||||
"consistent": true,
|
|
||||||
"multiline": true
|
|
||||||
}],
|
|
||||||
// https://eslint.org/docs/rules/object-property-newline
|
|
||||||
"object-property-newline": "error",
|
|
||||||
// https://eslint.org/docs/rules/brace-style
|
|
||||||
"brace-style": "error",
|
|
||||||
// https://eslint.org/docs/rules/no-multiple-empty-lines
|
|
||||||
"no-multiple-empty-lines": ["error", {"max": 1}],
|
|
||||||
// https://eslint.org/docs/rules/operator-linebreak
|
|
||||||
"operator-linebreak": ["error", "before", {"overrides": {"=": "after"}}],
|
|
||||||
// https://eslint.org/docs/rules/padding-line-between-statements
|
|
||||||
"padding-line-between-statements": ["error", {
|
|
||||||
"blankLine": "always",
|
|
||||||
"prev": "multiline-block-like",
|
|
||||||
"next": "*"
|
|
||||||
}, {
|
|
||||||
"blankLine": "always",
|
|
||||||
"prev": "*",
|
|
||||||
"next": "return"
|
|
||||||
}],
|
|
||||||
// https://eslint.org/docs/rules/space-infix-ops
|
|
||||||
"space-infix-ops": "error",
|
|
||||||
// https://eslint.org/docs/rules/space-unary-ops
|
|
||||||
"space-unary-ops": ["error", {
|
|
||||||
"words": true,
|
|
||||||
"nonwords": false
|
|
||||||
}],
|
|
||||||
// https://eslint.org/docs/rules/arrow-spacing
|
|
||||||
"arrow-spacing": "error",
|
|
||||||
// https://eslint.org/docs/rules/semi-spacing
|
|
||||||
"semi-spacing": ["error", {
|
|
||||||
"before": false,
|
|
||||||
"after": true
|
|
||||||
}],
|
|
||||||
|
|
||||||
"vue/html-indent": [
|
|
||||||
"error",
|
|
||||||
4,
|
|
||||||
{
|
|
||||||
"attribute": 1,
|
|
||||||
"baseIndent": 0,
|
|
||||||
"closeBracket": 0,
|
|
||||||
"alignAttributesVertically": true,
|
|
||||||
"ignores": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"vue/html-self-closing": ["error",
|
|
||||||
{
|
|
||||||
"html": {
|
|
||||||
"void": "never",
|
|
||||||
"normal": "never",
|
|
||||||
"component": "always"
|
|
||||||
},
|
|
||||||
"svg": "always",
|
|
||||||
"math": "always"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"vue/max-attributes-per-line": ["error", {
|
|
||||||
"singleline": 1,
|
|
||||||
"multiline": {
|
|
||||||
"max": 1,
|
|
||||||
"allowFirstLine": true
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"vue/multiline-html-element-content-newline": "off",
|
|
||||||
"vue/singleline-html-element-content-newline": "off",
|
|
||||||
"vue/no-mutating-props": "off"
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": LEGACY_FILES,
|
"files": ["*Spec.js"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-unused-vars": [
|
"no-unused-vars": [
|
||||||
"warn",
|
"warn",
|
||||||
{
|
{
|
||||||
"vars": "all",
|
"vars": "all",
|
||||||
"args": "none",
|
"args": "none",
|
||||||
"varsIgnorePattern": "controller"
|
"varsIgnorePattern": "controller",
|
||||||
|
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"no-nested-ternary": "off",
|
|
||||||
"no-var": "off",
|
|
||||||
"one-var": "off"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
45
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,45 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: File a Bug !
|
|
||||||
title: ''
|
|
||||||
labels: type:bug
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--- Focus on user impact in the title. Use the Summary Field to -->
|
|
||||||
<!--- describe the problem technically. -->
|
|
||||||
|
|
||||||
#### Summary
|
|
||||||
<!--- A description of the issue encountered. When possible, a description -->
|
|
||||||
<!--- of the impact of the issue. What use case does it impede?-->
|
|
||||||
|
|
||||||
#### Expected vs Current Behavior
|
|
||||||
<!--- Tell us what should have happened -->
|
|
||||||
|
|
||||||
#### Steps to Reproduce
|
|
||||||
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
|
|
||||||
<!--- reproduce this bug. Include code to reproduce, if relevant -->
|
|
||||||
1.
|
|
||||||
2.
|
|
||||||
3.
|
|
||||||
4.
|
|
||||||
|
|
||||||
#### Environment
|
|
||||||
<!--- If encountered on local machine, execute the following:
|
|
||||||
<!--- npx envinfo --system --browsers --npmPackages --binaries --languages --markdown -->
|
|
||||||
* Open MCT Version: <!--- date of build, version, or SHA -->
|
|
||||||
* Deployment Type: <!--- npm dev? VIPER Dev? openmct-yamcs? -->
|
|
||||||
* OS:
|
|
||||||
* Browser:
|
|
||||||
|
|
||||||
#### Impact Check List
|
|
||||||
<!--- Please select from the following options -->
|
|
||||||
- [ ] Data loss or misrepresented data?
|
|
||||||
- [ ] Regression? Did this used to work or has it always been broken?
|
|
||||||
- [ ] Is there a workaround available?
|
|
||||||
- [ ] Does this impact a critical component?
|
|
||||||
- [ ] Is this just a visual bug with no functional impact?
|
|
||||||
|
|
||||||
#### Additional Information
|
|
||||||
<!--- Include any screenshots, gifs, or logs which will expedite triage -->
|
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +0,0 @@
|
|||||||
blank_issues_enabled: true
|
|
||||||
contact_links:
|
|
||||||
- name: Discussions
|
|
||||||
url: https://github.com/nasa/openmct/discussions
|
|
||||||
about: Have a question about the project?
|
|
20
.github/ISSUE_TEMPLATE/enhancement-request.md
vendored
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: Enhancement request
|
|
||||||
about: Suggest an enhancement or new improvement for this project
|
|
||||||
title: ''
|
|
||||||
labels: type:enhancement
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
11
.github/ISSUE_TEMPLATE/maintenance-type.md
vendored
@ -1,11 +0,0 @@
|
|||||||
---
|
|
||||||
name: Maintenance
|
|
||||||
about: Add, update or remove documentation, tests, or dependencies.
|
|
||||||
title: ''
|
|
||||||
labels: type:maintenance
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Summary
|
|
||||||
<!--- Generally describe the purpose of the change. -->
|
|
29
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,29 +0,0 @@
|
|||||||
<!--- Note: Please open the PR in draft form until you are ready for active review. -->
|
|
||||||
Closes <!--- Insert Issue Number(s) this PR addresses. Start by typing # will open a dropdown of recent issues. Note: this does not work on PRs which target release branches -->
|
|
||||||
|
|
||||||
### Describe your changes:
|
|
||||||
<!--- Describe your changes and add any comments about your approach either here or inline if code comments aren't added -->
|
|
||||||
|
|
||||||
### All Submissions:
|
|
||||||
|
|
||||||
* [ ] Have you followed the guidelines in our [Contributing document](https://github.com/nasa/openmct/blob/master/CONTRIBUTING.md)?
|
|
||||||
* [ ] Have you checked to ensure there aren't other open [Pull Requests](https://github.com/nasa/openmct/pulls) for the same update/change?
|
|
||||||
* [ ] Is this change backwards compatible? For example, developers won't need to change how they are calling the API or how they've extended core plugins such as Tables or Plots.
|
|
||||||
|
|
||||||
### Author Checklist
|
|
||||||
|
|
||||||
* [ ] Changes address original issue?
|
|
||||||
* [ ] Unit tests included and/or updated with changes?
|
|
||||||
* [ ] Command line build passes?
|
|
||||||
* [ ] Has this been smoke tested?
|
|
||||||
* [ ] Testing instructions included in associated issue?
|
|
||||||
|
|
||||||
### Reviewer Checklist
|
|
||||||
|
|
||||||
* [ ] Changes appear to address issue?
|
|
||||||
* [ ] Changes appear not to be breaking changes?
|
|
||||||
* [ ] Appropriate unit tests included?
|
|
||||||
* [ ] Code style and in-line documentation are appropriate?
|
|
||||||
* [ ] Commit messages meet standards?
|
|
||||||
* [ ] Has associated issue been labelled unverified? (only applicable if this PR closes the issue)
|
|
||||||
* [ ] Has associated issue been labelled bug? (only applicable if this PR is for a bug fix)
|
|
24
.github/dependabot.yml
vendored
@ -1,24 +0,0 @@
|
|||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "npm"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
open-pull-requests-limit: 10
|
|
||||||
labels:
|
|
||||||
- "type:maintenance"
|
|
||||||
- "dependencies"
|
|
||||||
- "pr:e2e"
|
|
||||||
- "pr:daveit"
|
|
||||||
- "pr:visual"
|
|
||||||
- "pr:platform"
|
|
||||||
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
labels:
|
|
||||||
- "type:maintenance"
|
|
||||||
- "dependencies"
|
|
||||||
- "pr:daveit"
|
|
43
.github/workflows/codeql-analysis.yml
vendored
@ -1,43 +0,0 @@
|
|||||||
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
paths-ignore:
|
|
||||||
- '**/*Spec.js'
|
|
||||||
- '**/*.md'
|
|
||||||
- '**/*.txt'
|
|
||||||
- '**/*.yml'
|
|
||||||
- '**/*.yaml'
|
|
||||||
- '**/*.spec.js'
|
|
||||||
- '**/*.config.js'
|
|
||||||
schedule:
|
|
||||||
- cron: '28 21 * * 3'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v1
|
|
||||||
with:
|
|
||||||
languages: javascript
|
|
||||||
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v1
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v1
|
|
61
.github/workflows/e2e-pr.yml
vendored
@ -1,61 +0,0 @@
|
|||||||
name: "e2e-pr"
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- labeled
|
|
||||||
- opened
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
e2e-full:
|
|
||||||
if: ${{ github.event.label.name == 'pr:e2e' }}
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os:
|
|
||||||
- ubuntu-latest
|
|
||||||
- windows-latest
|
|
||||||
steps:
|
|
||||||
- name: Trigger Success
|
|
||||||
uses: actions/github-script@v6
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
github.rest.issues.createComment({
|
|
||||||
issue_number: context.issue.number,
|
|
||||||
owner: "nasa",
|
|
||||||
repo: "openmct",
|
|
||||||
body: 'Started e2e Run. Follow along: https://github.com/nasa/openmct/actions/runs/' + context.runId
|
|
||||||
})
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '16'
|
|
||||||
- run: npx playwright install-deps
|
|
||||||
- run: npm install
|
|
||||||
- run: npm run test:e2e:full
|
|
||||||
- name: Archive test results
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
path: test-results
|
|
||||||
- name: Test success
|
|
||||||
if: ${{ success() }}
|
|
||||||
uses: actions/github-script@v6
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
github.rest.issues.createComment({
|
|
||||||
issue_number: context.issue.number,
|
|
||||||
owner: "nasa",
|
|
||||||
repo: "openmct",
|
|
||||||
body: 'Success ✅ ! Build artifacts are here: https://github.com/nasa/openmct/actions/runs/' + context.runId
|
|
||||||
})
|
|
||||||
- name: Test failure
|
|
||||||
if: ${{ failure() }}
|
|
||||||
uses: actions/github-script@v6
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
github.rest.issues.createComment({
|
|
||||||
issue_number: context.issue.number,
|
|
||||||
owner: "nasa",
|
|
||||||
repo: "openmct",
|
|
||||||
body: 'Failure ❌ ! Build artifacts are here: https://github.com/nasa/openmct/actions/runs/' + context.runId
|
|
||||||
})
|
|
25
.github/workflows/e2e-visual.yml
vendored
@ -1,25 +0,0 @@
|
|||||||
name: "e2e-visual"
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- labeled
|
|
||||||
- opened
|
|
||||||
schedule:
|
|
||||||
- cron: '28 21 * * 1-5'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
e2e-visual:
|
|
||||||
if: ${{ github.event.label.name == 'pr:visual' }} || ${{ github.event.workflow_dispatch }} || ${{ github.event.schedule }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '16'
|
|
||||||
- run: npx playwright install-deps
|
|
||||||
- run: npm install
|
|
||||||
- name: Run the e2e visual tests
|
|
||||||
run: npm run test:e2e:visual
|
|
||||||
env:
|
|
||||||
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
|
|
21
.github/workflows/e2e.yml
vendored
@ -1,21 +0,0 @@
|
|||||||
name: "e2e"
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: 'Which branch do you want to test?' # Limited to branch for now
|
|
||||||
required: false
|
|
||||||
default: 'master'
|
|
||||||
jobs:
|
|
||||||
e2e:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.inputs.version }}
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '16'
|
|
||||||
- run: npm install
|
|
||||||
- name: Run the e2e tests
|
|
||||||
run: npm run test:e2e:ci
|
|
100
.github/workflows/lighthouse.yml
vendored
@ -1,100 +0,0 @@
|
|||||||
name: lighthouse
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: 'Which branch do you want to test?' # Limited to branch for now
|
|
||||||
required: false
|
|
||||||
default: 'master'
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- labeled
|
|
||||||
schedule:
|
|
||||||
- cron: '28 21 * * 1-5'
|
|
||||||
jobs:
|
|
||||||
lighthouse-pr:
|
|
||||||
if: ${{ github.event.label.name == 'pr:lighthouse' }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout Master for Baseline
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
ref: master #explicitly checkout master for baseline
|
|
||||||
- name: Install Node 14
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }}
|
|
||||||
- name: npm install with lighthouse cli
|
|
||||||
run: npm install && npm install -g @lhci/cli
|
|
||||||
- name: Run lhci against master to generate baseline and ignore exit codes
|
|
||||||
run: lhci autorun || true
|
|
||||||
- name: Perform clean checkout of PR
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
clean: true
|
|
||||||
- name: Install Node version which is compatible with PR
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
- name: npm install with lighthouse cli
|
|
||||||
run: npm install && npm install -g @lhci/cli
|
|
||||||
- name: Run lhci with PR
|
|
||||||
run: lhci autorun
|
|
||||||
env:
|
|
||||||
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
|
|
||||||
lighthouse-nightly:
|
|
||||||
if: ${{ github.event.schedule }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Install Node 14
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }}
|
|
||||||
- name: npm install with lighthouse cli
|
|
||||||
run: npm install && npm install -g @lhci/cli
|
|
||||||
- name: Run lhci against master to generate baseline
|
|
||||||
run: lhci autorun
|
|
||||||
env:
|
|
||||||
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
|
|
||||||
lighthouse-dispatch:
|
|
||||||
if: ${{ github.event.workflow_dispatch }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.inputs.version }}
|
|
||||||
- name: Install Node 14
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }}
|
|
||||||
- name: npm install with lighthouse cli
|
|
||||||
run: npm install && npm install -g @lhci/cli
|
|
||||||
- name: Run lhci against master to generate baseline
|
|
||||||
run: lhci autorun
|
|
||||||
|
|
33
.github/workflows/npm-prerelease.yml
vendored
@ -1,33 +0,0 @@
|
|||||||
# This workflow will run tests using node and then publish a package to npmjs when a prerelease is created
|
|
||||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
|
|
||||||
|
|
||||||
name: npm_prerelease
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [prereleased]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
- run: npm install
|
|
||||||
- run: npm test
|
|
||||||
|
|
||||||
publish-npm-prerelease:
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
registry-url: https://registry.npmjs.org/
|
|
||||||
- run: npm install
|
|
||||||
- run: npm publish --access public --tag unstable
|
|
||||||
env:
|
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
34
.github/workflows/pr-platform.yml
vendored
@ -1,34 +0,0 @@
|
|||||||
name: "pr-platform"
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
types: [ labeled ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
e2e-full:
|
|
||||||
if: ${{ github.event.label.name == 'pr:platform' }}
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
os:
|
|
||||||
- ubuntu-latest
|
|
||||||
- macos-latest
|
|
||||||
- windows-latest
|
|
||||||
node_version:
|
|
||||||
- 12
|
|
||||||
- 14
|
|
||||||
- 16
|
|
||||||
architecture:
|
|
||||||
- x64
|
|
||||||
name: Node ${{ matrix.node_version }} - ${{ matrix.architecture }} on ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node_version }}
|
|
||||||
architecture: ${{ matrix.architecture }}
|
|
||||||
- run: npm install
|
|
||||||
- run: npm test
|
|
||||||
- run: npm run lint
|
|
19
.github/workflows/prcop-config.json
vendored
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"linters": [
|
|
||||||
{
|
|
||||||
"name": "descriptionRegexp",
|
|
||||||
"config": {
|
|
||||||
"regexp": "x] Testing instructions",
|
|
||||||
"errorMessage": ":police_officer: PR Description does not confirm that associated issue(s) contain Testing instructions"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "descriptionMinWords",
|
|
||||||
"config": {
|
|
||||||
"minWordsCount": 160,
|
|
||||||
"errorMessage": ":police_officer: Please, be sure to use existing PR template."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"disableWord": "pr:daveit"
|
|
||||||
}
|
|
26
.github/workflows/prcop.yml
vendored
@ -1,26 +0,0 @@
|
|||||||
name: PRCop
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- reopened
|
|
||||||
- edited
|
|
||||||
- synchronize
|
|
||||||
- ready_for_review
|
|
||||||
- review_requested
|
|
||||||
- review_request_removed
|
|
||||||
pull_request_review_comment:
|
|
||||||
types:
|
|
||||||
- created
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
prcop:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Template Check
|
|
||||||
steps:
|
|
||||||
- name: Linting Pull Request
|
|
||||||
uses: makaroni4/prcop@v1.0.35
|
|
||||||
with:
|
|
||||||
config-file: ".github/workflows/prcop-config.json"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
13
.gitignore
vendored
@ -37,17 +37,4 @@ protractor/logs
|
|||||||
# npm-debug log
|
# npm-debug log
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
|
||||||
# karma reports
|
|
||||||
report.*.json
|
|
||||||
|
|
||||||
# Lighthouse reports
|
|
||||||
.lighthouseci
|
|
||||||
|
|
||||||
# e2e test artifacts
|
|
||||||
test-results
|
|
||||||
allure-results
|
|
||||||
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
||||||
#codecov artifacts
|
|
||||||
codecov
|
|
||||||
|
@ -33,12 +33,3 @@ protractor/logs
|
|||||||
|
|
||||||
# npm-debug log
|
# npm-debug log
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
|
||||||
# Infra and tests
|
|
||||||
.circleci
|
|
||||||
.github
|
|
||||||
e2e
|
|
||||||
codecov.yml
|
|
||||||
lighthouserc.yml
|
|
||||||
*.Spec.js
|
|
||||||
karma.conf.js
|
|
||||||
|
9
.npmrc
@ -1,9 +0,0 @@
|
|||||||
loglevel=warn
|
|
||||||
|
|
||||||
# Temporary: istanbul-instrumenter-loader is working with webpack 5, but states
|
|
||||||
# webpack 4 being the latest version it supports, so this legacy-peer-deps
|
|
||||||
# allows us to install it anyway.
|
|
||||||
legacy-peer-deps=true
|
|
||||||
|
|
||||||
#Prevent folks from ignoring an important error when building from source
|
|
||||||
engine-strict=true
|
|
139
API.md
@ -27,7 +27,7 @@
|
|||||||
- [Request Strategies **draft**](#request-strategies-draft)
|
- [Request Strategies **draft**](#request-strategies-draft)
|
||||||
- [`latest` request strategy](#latest-request-strategy)
|
- [`latest` request strategy](#latest-request-strategy)
|
||||||
- [`minmax` request strategy](#minmax-request-strategy)
|
- [`minmax` request strategy](#minmax-request-strategy)
|
||||||
- [Telemetry Formats](#telemetry-formats)
|
- [Telemetry Formats **draft**](#telemetry-formats-draft)
|
||||||
- [Registering Formats](#registering-formats)
|
- [Registering Formats](#registering-formats)
|
||||||
- [Telemetry Data](#telemetry-data)
|
- [Telemetry Data](#telemetry-data)
|
||||||
- [Telemetry Datums](#telemetry-datums)
|
- [Telemetry Datums](#telemetry-datums)
|
||||||
@ -52,8 +52,7 @@
|
|||||||
- [The URL Status Indicator](#the-url-status-indicator)
|
- [The URL Status Indicator](#the-url-status-indicator)
|
||||||
- [Creating a Simple Indicator](#creating-a-simple-indicator)
|
- [Creating a Simple Indicator](#creating-a-simple-indicator)
|
||||||
- [Custom Indicators](#custom-indicators)
|
- [Custom Indicators](#custom-indicators)
|
||||||
- [Priority API](#priority-api)
|
- [Included Plugins](#included-plugins)
|
||||||
- [Priority Types](#priority-types)
|
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
@ -110,13 +109,15 @@ script loaders are also supported.
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Open MCT</title>
|
<title>Open MCT</title>
|
||||||
<script src="dist/openmct.js"></script>
|
<script src="openmct.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
|
openmct.setAssetPath('openmct/dist');
|
||||||
openmct.install(openmct.plugins.LocalStorage());
|
openmct.install(openmct.plugins.LocalStorage());
|
||||||
openmct.install(openmct.plugins.MyItems());
|
openmct.install(openmct.plugins.MyItems());
|
||||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||||
|
openmct.install(openmct.plugins.Espresso());
|
||||||
openmct.start();
|
openmct.start();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
@ -127,6 +128,9 @@ The Open MCT library included above requires certain assets such as html
|
|||||||
templates, images, and css. If you installed Open MCT from GitHub as described
|
templates, images, and css. If you installed Open MCT from GitHub as described
|
||||||
in the section on [Building from Source](#building-from-source) then these
|
in the section on [Building from Source](#building-from-source) then these
|
||||||
assets will have been downloaded along with the Open MCT javascript library.
|
assets will have been downloaded along with the Open MCT javascript library.
|
||||||
|
You can specify the location of these assets by calling `openmct.setAssetPath()`.
|
||||||
|
Typically this will be the same location as the `openmct.js` library is
|
||||||
|
included from.
|
||||||
|
|
||||||
There are some plugins bundled with the application that provide UI,
|
There are some plugins bundled with the application that provide UI,
|
||||||
persistence, and other default configuration which are necessary to be able to
|
persistence, and other default configuration which are necessary to be able to
|
||||||
@ -233,7 +237,7 @@ attributes
|
|||||||
of this object. This is used for specifying an icon to appear next to each
|
of this object. This is used for specifying an icon to appear next to each
|
||||||
object of this type.
|
object of this type.
|
||||||
|
|
||||||
The [Open MCT Tutorials](https://github.com/nasa/openmct-tutorial) provide a
|
The [Open MCT Tutorials](https://github.com/openmct/openmct-tutorial) provide a
|
||||||
step-by-step examples of writing code for Open MCT that includes a [section on
|
step-by-step examples of writing code for Open MCT that includes a [section on
|
||||||
defining a new object type](https://github.com/nasa/openmct-tutorial#step-3---providing-objects).
|
defining a new object type](https://github.com/nasa/openmct-tutorial#step-3---providing-objects).
|
||||||
|
|
||||||
@ -249,24 +253,16 @@ To do so, use the `addRoot` method of the object API.
|
|||||||
eg.
|
eg.
|
||||||
```javascript
|
```javascript
|
||||||
openmct.objects.addRoot({
|
openmct.objects.addRoot({
|
||||||
namespace: "example.namespace",
|
namespace: "example.namespace",
|
||||||
key: "my-key"
|
key: "my-key"
|
||||||
},
|
});
|
||||||
openmct.priority.HIGH);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The `addRoot` function takes a two arguments, the first can be an [object identifier](#domain-objects-and-identifiers) for a root level object, or an array of identifiers for root
|
The `addRoot` function takes a single [object identifier](#domain-objects-and-identifiers)
|
||||||
level objects, or a function that returns a promise for an identifier or an array of root level objects, the second is a [priority](#priority-api) or numeric value.
|
as an argument.
|
||||||
|
|
||||||
When using the `getAll` method of the object API, they will be returned in order of priority.
|
Root objects are loaded just like any other objects, i.e. via an object
|
||||||
|
provider.
|
||||||
eg.
|
|
||||||
```javascript
|
|
||||||
openmct.objects.addRoot(identifier, openmct.priority.LOW); // low = -1000, will appear last in composition or tree
|
|
||||||
openmct.objects.addRoot(otherIdentifier, openmct.priority.HIGH); // high = 1000, will appear first in composition or tree
|
|
||||||
```
|
|
||||||
|
|
||||||
Root objects are loaded just like any other objects, i.e. via an object provider.
|
|
||||||
|
|
||||||
## Object Providers
|
## Object Providers
|
||||||
|
|
||||||
@ -433,14 +429,13 @@ attribute | type | flags | notes
|
|||||||
|
|
||||||
###### Value Hints
|
###### Value Hints
|
||||||
|
|
||||||
Each telemetry value description has an object defining hints. Keys in this object represent the hint itself, and the value represents the weight of that hint. A lower weight means the hint has a higher priority. For example, multiple values could be hinted for use as the y-axis of a plot (raw, engineering), but the highest priority would be the default choice. Likewise, a table will use hints to determine the default order of columns.
|
Each telemetry value description has an object defining hints. Keys in this this object represent the hint itself, and the value represents the weight of that hint. A lower weight means the hint has a higher priority. For example, multiple values could be hinted for use as the y axis of a plot (raw, engineering), but the highest priority would be the default choice. Likewise, a table will use hints to determine the default order of columns.
|
||||||
|
|
||||||
Known hints:
|
Known hints:
|
||||||
|
|
||||||
* `domain`: Values with a `domain` hint will be used for the x-axis of a plot, and tables will render columns for these values first.
|
* `domain`: Indicates that the value represents the "input" of a datum. Values with a `domain` hint will be used for the x-axis of a plot, and tables will render columns for these values first.
|
||||||
* `range`: Values with a `range` hint will be used as the y-axis on a plot, and tables will render columns for these values after the `domain` values.
|
* `range`: Indicates that the value is the "output" of a datum. Values with a `range` hint will be used as the y-axis on a plot, and tables will render columns for these values after the `domain` values.
|
||||||
* `image`: Indicates that the value may be interpreted as the URL to an image file, in which case appropriate views will be made available.
|
* `image`: Indicates that the value may be interpreted as the URL to an image file, in which case appropriate views will be made available.
|
||||||
* `imageDownloadName`: Indicates that the value may be interpreted as the name of the image file.
|
|
||||||
|
|
||||||
##### The Time Conductor and Telemetry
|
##### The Time Conductor and Telemetry
|
||||||
|
|
||||||
@ -491,8 +486,6 @@ In this case, the `domain` is the currently selected time-system, and the start
|
|||||||
|
|
||||||
A telemetry provider's `request` method should return a promise for an array of telemetry datums. These datums must be sorted by `domain` in ascending order.
|
A telemetry provider's `request` method should return a promise for an array of telemetry datums. These datums must be sorted by `domain` in ascending order.
|
||||||
|
|
||||||
The telemetry provider's `request` method will also return an object `signal` with an `aborted` property with a value `true` if the request has been aborted by user navigation. This can be used to trigger actions when a request has been aborted.
|
|
||||||
|
|
||||||
#### Request Strategies **draft**
|
#### Request Strategies **draft**
|
||||||
|
|
||||||
To improve performance views may request a certain strategy for data reduction. These are intended to improve visualization performance by reducing the amount of data needed to be sent to the client. These strategies will be indicated by additional parameters in the request options. You may choose to handle them or ignore them.
|
To improve performance views may request a certain strategy for data reduction. These are intended to improve visualization performance by reducing the amount of data needed to be sent to the client. These strategies will be indicated by additional parameters in the request options. You may choose to handle them or ignore them.
|
||||||
@ -518,7 +511,7 @@ example:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This strategy says "I want the latest data point in this time range". A provider which recognizes this request should return only one value-- the latest-- in the requested time range. Depending on your back-end implementation, performing these queries in bulk can be a large performance increase. These are generally issued by views that are only capable of displaying a single value and only need to show the latest value.
|
This strategy says "I want the lastest data point in this time range". A provider which recognizes this request should return only one value-- the latest-- in the requested time range. Depending on your back-end implementation, performing these queries in bulk can be a large performance increase. These are generally issued by views that are only capable of displaying a single value and only need to show the latest value.
|
||||||
|
|
||||||
##### `minmax` request strategy
|
##### `minmax` request strategy
|
||||||
|
|
||||||
@ -535,7 +528,7 @@ example:
|
|||||||
|
|
||||||
MinMax queries are issued by plots, and may be issued by other types as well. The aim is to reduce the amount of data returned but still faithfully represent the full extent of the data. In order to do this, the view calculates the maximum data resolution it can display (i.e. the number of horizontal pixels in a plot) and sends that as the `size`. The response should include at least one minimum and one maximum value per point of resolution.
|
MinMax queries are issued by plots, and may be issued by other types as well. The aim is to reduce the amount of data returned but still faithfully represent the full extent of the data. In order to do this, the view calculates the maximum data resolution it can display (i.e. the number of horizontal pixels in a plot) and sends that as the `size`. The response should include at least one minimum and one maximum value per point of resolution.
|
||||||
|
|
||||||
#### Telemetry Formats
|
#### Telemetry Formats **draft**
|
||||||
|
|
||||||
Telemetry format objects define how to interpret and display telemetry data.
|
Telemetry format objects define how to interpret and display telemetry data.
|
||||||
They have a simple structure:
|
They have a simple structure:
|
||||||
@ -607,21 +600,13 @@ section.
|
|||||||
|
|
||||||
#### Limit Evaluators **draft**
|
#### Limit Evaluators **draft**
|
||||||
|
|
||||||
Limit evaluators allow a telemetry integrator to define which limits exist for a
|
Limit evaluators allow a telemetry integrator to define how limits should be
|
||||||
telemetry endpoint and how limits should be applied to telemetry from a given domain object.
|
applied to telemetry from a given domain object. For an example of a limit
|
||||||
|
evaluator, take a look at `examples/generator/SinewaveLimitProvider.js`.
|
||||||
A limit evaluator can implement the `evalute` method which is used to define how limits
|
|
||||||
should be applied to telemetry and the `getLimits` method which is used to specify
|
|
||||||
what the limit values are for different limit levels.
|
|
||||||
|
|
||||||
Limit levels can be mapped to one of 5 colors for visualization:
|
|
||||||
`purple`, `red`, `orange`, `yellow` and `cyan`.
|
|
||||||
|
|
||||||
For an example of a limit evaluator, take a look at `examples/generator/SinewaveLimitProvider.js`.
|
|
||||||
|
|
||||||
### Telemetry Consumer APIs **draft**
|
### Telemetry Consumer APIs **draft**
|
||||||
|
|
||||||
The APIs for requesting telemetry from Open MCT -- e.g. for use in custom views -- are currently in draft state and are being revised. If you'd like to experiment with them before they are finalized, please contact the team via the contact-us link on our website.
|
The APIs for requesting telemetry from Open MCT -- e.g. for use in custom views -- are currently in draft state and are being revised. If you'd like to experiement with them before they are finalized, please contact the team via the contact-us link on our website.
|
||||||
|
|
||||||
|
|
||||||
## Time API
|
## Time API
|
||||||
@ -1008,8 +993,8 @@ reveal additional information when the mouse cursor is hovered over it.
|
|||||||
A common use case for indicators is to convey the state of some external system such as a
|
A common use case for indicators is to convey the state of some external system such as a
|
||||||
persistence backend or HTTP server. So long as this system is accessible via HTTP request,
|
persistence backend or HTTP server. So long as this system is accessible via HTTP request,
|
||||||
Open MCT provides a general purpose indicator to show whether the server is available and
|
Open MCT provides a general purpose indicator to show whether the server is available and
|
||||||
returning a 2xx status code. The URL Status Indicator is made available as a default plugin. See
|
returing a 2xx status code. The URL Status Indicator is made available as a default plugin. See
|
||||||
the [documentation](./src/plugins/URLIndicatorPlugin) for details on how to install and configure the
|
[Included Plugins](#included-plugins) below for details on how to install and configure the
|
||||||
URL Status Indicator.
|
URL Status Indicator.
|
||||||
|
|
||||||
### Creating a Simple Indicator
|
### Creating a Simple Indicator
|
||||||
@ -1048,7 +1033,7 @@ different colors to indicate status.
|
|||||||
|
|
||||||
### Custom Indicators
|
### Custom Indicators
|
||||||
|
|
||||||
A completely custom indicator can be added by simply providing a DOM element to place alongside other indicators.
|
A completely custom indicator can be added by simple providing a DOM element to place alongside other indicators.
|
||||||
|
|
||||||
``` javascript
|
``` javascript
|
||||||
var domNode = document.createElement('div');
|
var domNode = document.createElement('div');
|
||||||
@ -1062,24 +1047,58 @@ A completely custom indicator can be added by simply providing a DOM element to
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Priority API
|
## Included Plugins
|
||||||
|
|
||||||
Open MCT provides some built-in priority values that can be used in the application for view providers, indicators, root object order, and more.
|
Open MCT is packaged along with a few general-purpose plugins:
|
||||||
|
|
||||||
### Priority Types
|
* `openmct.plugins.Conductor` provides a user interface for working with time
|
||||||
|
within the application. If activated, configuration must be provided. This is
|
||||||
|
detailed in the section on [Time Conductor Configuration](#time-conductor-configuration).
|
||||||
|
* `openmct.plugins.CouchDB` is an adapter for using CouchDB for persistence
|
||||||
|
of user-created objects. This is a constructor that takes the URL for the
|
||||||
|
CouchDB database as a parameter, e.g.
|
||||||
|
```javascript
|
||||||
|
openmct.install(openmct.plugins.CouchDB('http://localhost:5984/openmct'))
|
||||||
|
```
|
||||||
|
* `openmct.plugins.Elasticsearch` is an adapter for using Elasticsearch for
|
||||||
|
persistence of user-created objects. This is a
|
||||||
|
constructor that takes the URL for the Elasticsearch instance as a
|
||||||
|
parameter. eg.
|
||||||
|
```javascript
|
||||||
|
openmct.install(openmct.plugins.CouchDB('http://localhost:9200'))
|
||||||
|
```
|
||||||
|
* `openmct.plugins.Espresso` and `openmct.plugins.Snow` are two different
|
||||||
|
themes (dark and light) available for Open MCT. Note that at least one
|
||||||
|
of these themes must be installed for Open MCT to appear correctly.
|
||||||
|
* `openmct.plugins.URLIndicator` adds an indicator which shows the
|
||||||
|
availability of a URL with the following options:
|
||||||
|
- `url` : URL to indicate the status of
|
||||||
|
- `iconClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
|
||||||
|
- `interval`: Interval between checking the connection, defaults to `10000`
|
||||||
|
- `label` Name showing up as text in the status bar, defaults to url
|
||||||
|
```javascript
|
||||||
|
openmct.install(openmct.plugins.URLIndicator({
|
||||||
|
url: 'http://localhost:8080',
|
||||||
|
iconClass: 'check',
|
||||||
|
interval: 10000,
|
||||||
|
label: 'Localhost'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
```
|
||||||
|
* `openmct.plugins.LocalStorage` provides persistence of user-created
|
||||||
|
objects in browser-local storage. This is particularly useful in
|
||||||
|
development environments.
|
||||||
|
* `openmct.plugins.MyItems` adds a top-level folder named "My Items"
|
||||||
|
when the application is first started, providing a place for a
|
||||||
|
user to store created items.
|
||||||
|
* `openmct.plugins.UTCTimeSystem` provides a default time system for Open MCT.
|
||||||
|
|
||||||
Currently, the Open MCT Priority API provides (type: numeric value):
|
Generally, you will want to either install these plugins, or install
|
||||||
- HIGH: 1000
|
different plugins that provide persistence and an initial folder
|
||||||
- Default: 0
|
hierarchy.
|
||||||
- LOW: -1000
|
|
||||||
|
|
||||||
View provider Example:
|
eg.
|
||||||
|
```javascript
|
||||||
``` javascript
|
openmct.install(openmct.plugins.LocalStorage());
|
||||||
class ViewProvider {
|
openmct.install(openmct.plugins.MyItems());
|
||||||
...
|
```
|
||||||
priority() {
|
|
||||||
return openmct.priority.HIGH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
242
CONTRIBUTING.md
@ -10,7 +10,7 @@ accept changes from external contributors.
|
|||||||
|
|
||||||
The short version:
|
The short version:
|
||||||
|
|
||||||
1. Write your contribution or describe your idea in the form of an [GitHub issue](https://github.com/nasa/openmct/issues/new/choose) or [Starting a GitHub Discussion](https://github.com/nasa/openmct/discussions)
|
1. Write your contribution.
|
||||||
2. Make sure your contribution meets code, test, and commit message
|
2. Make sure your contribution meets code, test, and commit message
|
||||||
standards as described below.
|
standards as described below.
|
||||||
3. Submit a pull request from a topic branch back to `master`. Include a check
|
3. Submit a pull request from a topic branch back to `master`. Include a check
|
||||||
@ -18,7 +18,6 @@ The short version:
|
|||||||
for review.)
|
for review.)
|
||||||
4. Respond to any discussion. When the reviewer decides it's ready, they
|
4. Respond to any discussion. When the reviewer decides it's ready, they
|
||||||
will merge back `master` and fill out their own check list.
|
will merge back `master` and fill out their own check list.
|
||||||
5. If you are a first-time contributor, please see [this discussion](https://github.com/nasa/openmct/discussions/3821) for further information.
|
|
||||||
|
|
||||||
## Contribution Process
|
## Contribution Process
|
||||||
|
|
||||||
@ -104,7 +103,7 @@ the name chosen could not be mistaken for a topic or master branch.
|
|||||||
### Merging
|
### Merging
|
||||||
|
|
||||||
When development is complete on an issue, the first step toward merging it
|
When development is complete on an issue, the first step toward merging it
|
||||||
back into the master branch is to file a Pull Request (PR). The contributions
|
back into the master branch is to file a Pull Request. The contributions
|
||||||
should meet code, test, and commit message standards as described below,
|
should meet code, test, and commit message standards as described below,
|
||||||
and the pull request should include a completed author checklist, also
|
and the pull request should include a completed author checklist, also
|
||||||
as described below. Pull requests may be assigned to specific team
|
as described below. Pull requests may be assigned to specific team
|
||||||
@ -115,15 +114,6 @@ request. When the reviewer is satisfied, they should add a comment to
|
|||||||
the pull request containing the reviewer checklist (from below) and complete
|
the pull request containing the reviewer checklist (from below) and complete
|
||||||
the merge back to the master branch.
|
the merge back to the master branch.
|
||||||
|
|
||||||
Additionally:
|
|
||||||
* Every pull request must link to the issue that it addresses. Eg. “Addresses #1234” or “Closes #1234”. This is the responsibility of the pull request’s __author__. If no issue exists, [create one](https://github.com/nasa/openmct/issues/new/choose).
|
|
||||||
* Every __author__ must include testing instructions. These instructions should identify the areas of code affected, and some minimal test steps. If addressing a bug, reproduction steps should be included, if they were not included in the original issue. If reproduction steps were included on the original issue, and are sufficient, refer to them.
|
|
||||||
* A pull request that closes an issue should say so in the description. Including the text “Closes #1234” will cause the linked issue to be automatically closed when the pull request is merged. This is the responsibility of the pull request’s __author__.
|
|
||||||
* When a pull request is merged, and the corresponding issue closed, the __reviewer__ must add the tag “unverified” to the original issue. This will indicate that although the issue is closed, it has not been tested yet.
|
|
||||||
* Every PR must have two reviewers assigned, though only one approval is necessary for merge.
|
|
||||||
* Changes to API require approval by a senior developer.
|
|
||||||
* When creating a PR, it is the author's responsibility to apply any priority label from the issue to the PR as well. This helps with prioritization.
|
|
||||||
|
|
||||||
## Standards
|
## Standards
|
||||||
|
|
||||||
Contributions to Open MCT are expected to meet the following standards.
|
Contributions to Open MCT are expected to meet the following standards.
|
||||||
@ -132,104 +122,97 @@ changes.
|
|||||||
|
|
||||||
### Code Standards
|
### Code Standards
|
||||||
|
|
||||||
JavaScript sources in Open MCT must satisfy the ESLint rules defined in
|
JavaScript sources in Open MCT must satisfy JSLint under its default
|
||||||
this repository. This is verified by the command line build.
|
settings. This is verified by the command line build.
|
||||||
|
|
||||||
#### Code Guidelines
|
#### Code Guidelines
|
||||||
|
|
||||||
The following guidelines are provided for anyone contributing source code to the Open MCT project:
|
JavaScript sources in Open MCT should:
|
||||||
|
|
||||||
|
* Use four spaces for indentation. Tabs should not be used.
|
||||||
|
* Include JSDoc for any exposed API (e.g. public methods, constructors).
|
||||||
|
* Include non-JSDoc comments as-needed for explaining private variables,
|
||||||
|
methods, or algorithms when they are non-obvious.
|
||||||
|
* Define one public class per script, expressed as a constructor function
|
||||||
|
returned from an AMD-style module.
|
||||||
|
* Follow “Java-like” naming conventions. These includes:
|
||||||
|
* Classes should use camel case, first letter capitalized
|
||||||
|
(e.g. SomeClassName).
|
||||||
|
* Methods, variables, fields, and function names should use camel case,
|
||||||
|
first letter lower-case (e.g. someVariableName).
|
||||||
|
* Constants (variables or fields which are meant to be declared and
|
||||||
|
initialized statically, and never changed) should use only capital
|
||||||
|
letters, with underscores between words (e.g. SOME_CONSTANT).
|
||||||
|
* File names should be the name of the exported class, plus a .js extension
|
||||||
|
(e.g. SomeClassName.js).
|
||||||
|
* Avoid anonymous functions, except when functions are short (a few lines)
|
||||||
|
and/or their inclusion makes sense within the flow of the code
|
||||||
|
(e.g. as arguments to a forEach call).
|
||||||
|
* Avoid deep nesting (especially of functions), except where necessary
|
||||||
|
(e.g. due to closure scope).
|
||||||
|
* End with a single new-line character.
|
||||||
|
* Expose public methods by declaring them on the class's prototype.
|
||||||
|
* Within a given function's scope, do not mix declarations and imperative
|
||||||
|
code, and present these in the following order:
|
||||||
|
* First, variable declarations and initialization.
|
||||||
|
* Second, function declarations.
|
||||||
|
* Third, imperative statements.
|
||||||
|
* Finally, the returned value.
|
||||||
|
|
||||||
1. Write clean code. Here’s a good summary - https://github.com/ryanmcdermott/clean-code-javascript.
|
|
||||||
1. Include JSDoc for any exposed API (e.g. public methods, classes).
|
|
||||||
1. Include non-JSDoc comments as-needed for explaining private variables,
|
|
||||||
methods, or algorithms when they are non-obvious. Otherwise code
|
|
||||||
should be self-documenting.
|
|
||||||
1. Classes and Vue components should use camel case, first letter capitalized
|
|
||||||
(e.g. SomeClassName).
|
|
||||||
1. Methods, variables, fields, events, and function names should use camelCase,
|
|
||||||
first letter lower-case (e.g. someVariableName).
|
|
||||||
1. Source files that export functions should use camelCase, first letter lower-case (eg. testTools.js)
|
|
||||||
1. Constants (variables or fields which are meant to be declared and
|
|
||||||
initialized statically, and never changed) should use only capital
|
|
||||||
letters, with underscores between words (e.g. SOME_CONSTANT). They should always be declared as `const`s
|
|
||||||
1. File names should be the name of the exported class, plus a .js extension
|
|
||||||
(e.g. SomeClassName.js).
|
|
||||||
1. Avoid anonymous functions, except when functions are short (one or two lines)
|
|
||||||
and their inclusion makes sense within the flow of the code
|
|
||||||
(e.g. as arguments to a forEach call). Anonymous functions should always be arrow functions.
|
|
||||||
1. Named functions are preferred over functions assigned to variables.
|
|
||||||
eg.
|
|
||||||
```JavaScript
|
|
||||||
function renameObject(object, newName) {
|
|
||||||
Object.name = newName;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
is preferable to
|
|
||||||
```JavaScript
|
|
||||||
const rename = (object, newName) => {
|
|
||||||
Object.name = newName;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
1. Avoid deep nesting (especially of functions), except where necessary
|
|
||||||
(e.g. due to closure scope).
|
|
||||||
1. End with a single new-line character.
|
|
||||||
1. Always use ES6 `Class`es and inheritence rather than the pre-ES6 prototypal
|
|
||||||
pattern.
|
|
||||||
1. Within a given function's scope, do not mix declarations and imperative
|
|
||||||
code, and present these in the following order:
|
|
||||||
* First, variable declarations and initialization.
|
|
||||||
* Secondly, imperative statements.
|
|
||||||
* Finally, the returned value. A single return statement at the end of the function should be used, except where an early return would improve code clarity.
|
|
||||||
1. Avoid the use of "magic" values.
|
|
||||||
eg.
|
|
||||||
```JavaScript
|
|
||||||
const UNAUTHORIZED = 401;
|
|
||||||
if (responseCode === UNAUTHORIZED)
|
|
||||||
```
|
|
||||||
is preferable to
|
|
||||||
```JavaScript
|
|
||||||
if (responseCode === 401)
|
|
||||||
```
|
|
||||||
1. Use the ternary operator only for simple cases such as variable assignment. Nested ternaries should be avoided in all cases.
|
|
||||||
1. Test specs should reside alongside the source code they test, not in a separate directory.
|
|
||||||
1. Organize code by feature, not by type.
|
|
||||||
eg.
|
|
||||||
```
|
|
||||||
- telemetryTable
|
|
||||||
- row
|
|
||||||
TableRow.js
|
|
||||||
TableRowCollection.js
|
|
||||||
TableRow.vue
|
|
||||||
- column
|
|
||||||
TableColumn.js
|
|
||||||
TableColumn.vue
|
|
||||||
plugin.js
|
|
||||||
pluginSpec.js
|
|
||||||
```
|
|
||||||
is preferable to
|
|
||||||
```
|
|
||||||
- telemetryTable
|
|
||||||
- components
|
|
||||||
TableRow.vue
|
|
||||||
TableColumn.vue
|
|
||||||
- collections
|
|
||||||
TableRowCollection.js
|
|
||||||
TableColumn.js
|
|
||||||
TableRow.js
|
|
||||||
plugin.js
|
|
||||||
pluginSpec.js
|
|
||||||
```
|
|
||||||
Deviations from Open MCT code style guidelines require two-party agreement,
|
Deviations from Open MCT code style guidelines require two-party agreement,
|
||||||
typically from the author of the change and its reviewer.
|
typically from the author of the change and its reviewer.
|
||||||
|
|
||||||
|
#### Code Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bundles should declare themselves as namespaces in whichever source
|
||||||
|
* file is most like the "main point of entry" to the bundle.
|
||||||
|
* @namespace some/bundle
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
['./OtherClass'],
|
||||||
|
function (OtherClass) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A summary of how to use this class goes here.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @memberof some/bundle
|
||||||
|
*/
|
||||||
|
function ExampleClass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods which are not intended for external use should
|
||||||
|
// not have JSDoc (or should be marked @private)
|
||||||
|
ExampleClass.prototype.privateMethod = function () {
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A summary of this method goes here.
|
||||||
|
* @param {number} n a parameter
|
||||||
|
* @returns {number} a return value
|
||||||
|
*/
|
||||||
|
ExampleClass.prototype.publicMethod = function (n) {
|
||||||
|
return n * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExampleClass;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
### Test Standards
|
### Test Standards
|
||||||
|
|
||||||
Automated testing shall occur whenever changes are merged into the main
|
Automated testing shall occur whenever changes are merged into the main
|
||||||
development branch and must be confirmed alongside any pull request.
|
development branch and must be confirmed alongside any pull request.
|
||||||
|
|
||||||
Automated tests are tests which exercise plugins, API, and utility classes.
|
Automated tests are typically unit tests which exercise individual software
|
||||||
Tests are subject to code review along with the actual implementation, to
|
components. Tests are subject to code review along with the actual
|
||||||
ensure that tests are applicable and useful.
|
implementation, to ensure that tests are applicable and useful.
|
||||||
|
|
||||||
Examples of useful tests:
|
Examples of useful tests:
|
||||||
* Tests which replicate bugs (or their root causes) to verify their
|
* Tests which replicate bugs (or their root causes) to verify their
|
||||||
@ -239,26 +222,8 @@ Examples of useful tests:
|
|||||||
* Tests which verify expected interactions with other components in the
|
* Tests which verify expected interactions with other components in the
|
||||||
system.
|
system.
|
||||||
|
|
||||||
#### Guidelines
|
During automated testing, code coverage metrics will be reported. Line
|
||||||
* 100% statement coverage is achievable and desirable.
|
coverage must remain at or above 80%.
|
||||||
* Do blackbox testing. Test external behaviors, not internal details. Write tests that describe what your plugin is supposed to do. How it does this doesn't matter, so don't test it.
|
|
||||||
* Unit test specs for plugins should be defined at the plugin level. Start with one test spec per plugin named pluginSpec.js, and as this test spec grows too big, break it up into multiple test specs that logically group related tests.
|
|
||||||
* Unit tests for API or for utility functions and classes may be defined at a per-source file level.
|
|
||||||
* Wherever possible only use and mock public API, builtin functions, and UI in your test specs. Do not directly invoke any private functions. ie. only call or mock functions and objects exposed by openmct.* (eg. openmct.telemetry, openmct.objectView, etc.), and builtin browser functions (fetch, requestAnimationFrame, setTimeout, etc.).
|
|
||||||
* Where builtin functions have been mocked, be sure to clear them between tests.
|
|
||||||
* Test at an appropriate level of isolation. Eg.
|
|
||||||
* If you’re testing a view, you do not need to test the whole application UI, you can just fetch the view provider using the public API and render the view into an element that you have created.
|
|
||||||
* You do not need to test that the view switcher works, there should be separate tests for that.
|
|
||||||
* You do not need to test that telemetry providers work, you can mock openmct.telemetry.request() to feed test data to the view.
|
|
||||||
* Use your best judgement when deciding on appropriate scope.
|
|
||||||
* Automated tests for plugins should start by actually installing the plugin being tested, and then test that installing the plugin adds the desired features and behavior to Open MCT, observing the above rules.
|
|
||||||
* All variables used in a test spec, including any instances of the Open MCT API should be declared inside of an appropriate block scope (not at the root level of the source file), and should be initialized in the relevant beforeEach block. `beforeEach` is preferable to `beforeAll` to avoid leaking of state between tests.
|
|
||||||
* A `afterEach` or `afterAll` should be used to do any clean up necessary to prevent leakage of state between test specs. This can happen when functions on `window` are wrapped, or when the URL is changed. [A convenience function](https://github.com/nasa/openmct/blob/master/src/utils/testing.js#L59) is provided for resetting the URL and clearing builtin spies between tests.
|
|
||||||
* If writing unit tests for legacy Angular code be sure to follow [best practices in order to avoid memory leaks](https://www.thecodecampus.de/blog/avoid-memory-leaks-angularjs-unit-tests/).
|
|
||||||
|
|
||||||
#### Examples
|
|
||||||
* [Example of an automated test spec for an object view plugin](https://github.com/nasa/openmct/blob/master/src/plugins/telemetryTable/pluginSpec.js)
|
|
||||||
* [Example of an automated test spec for API](https://github.com/nasa/openmct/blob/master/src/api/time/TimeAPISpec.js)
|
|
||||||
|
|
||||||
### Commit Message Standards
|
### Commit Message Standards
|
||||||
|
|
||||||
@ -297,12 +262,23 @@ these standards.
|
|||||||
|
|
||||||
Issues are tracked at https://github.com/nasa/openmct/issues.
|
Issues are tracked at https://github.com/nasa/openmct/issues.
|
||||||
|
|
||||||
|
Issues should include:
|
||||||
|
|
||||||
|
* A short description of the issue encountered.
|
||||||
|
* A longer-form description of the issue encountered. When possible, steps to
|
||||||
|
reproduce the issue.
|
||||||
|
* When possible, a description of the impact of the issue. What use case does
|
||||||
|
it impede?
|
||||||
|
* An assessment of the severity of the issue.
|
||||||
|
|
||||||
Issue severity is categorized as follows (in ascending order):
|
Issue severity is categorized as follows (in ascending order):
|
||||||
|
|
||||||
* _Trivial_: Minimal impact on the usefulness and functionality of the software; a "nice-to-have." Visual impact without functional impact,
|
* _Trivial_: Minimal impact on the usefulness and functionality of the
|
||||||
* _Medium_: Some impairment of use, but simple workarounds exist
|
software; a "nice-to-have."
|
||||||
* _Critical_: Significant loss of functionality or impairment of use. Display of telemetry data is not affected though.
|
* _(Unspecified)_: Major loss of functionality or impairment of use.
|
||||||
* _Blocker_: Major functionality is impaired or lost, threatening mission success. Display of telemetry data is impaired or blocked by the bug, which could lead to loss of situational awareness.
|
* _Critical_: Large-scale loss of functionality or impairment of use,
|
||||||
|
such that remaining utility becomes marginal.
|
||||||
|
* _Blocker_: Harmful or otherwise unacceptable behavior. Must fix.
|
||||||
|
|
||||||
## Check Lists
|
## Check Lists
|
||||||
|
|
||||||
@ -312,20 +288,14 @@ checklist).
|
|||||||
|
|
||||||
### Author Checklist
|
### Author Checklist
|
||||||
|
|
||||||
[Within PR Template](.github/PULL_REQUEST_TEMPLATE.md)
|
1. Changes address original issue?
|
||||||
|
2. Unit tests included and/or updated with changes?
|
||||||
|
3. Command line build passes?
|
||||||
|
4. Changes have been smoke-tested?
|
||||||
|
|
||||||
### Reviewer Checklist
|
### Reviewer Checklist
|
||||||
|
|
||||||
* [ ] Changes appear to address issue?
|
1. Changes appear to address issue?
|
||||||
* [ ] Changes appear not to be breaking changes?
|
2. Appropriate unit tests included?
|
||||||
* [ ] Appropriate unit tests included?
|
3. Code style and in-line documentation are appropriate?
|
||||||
* [ ] Code style and in-line documentation are appropriate?
|
4. Commit messages meet standards?
|
||||||
* [ ] Commit messages meet standards?
|
|
||||||
* [ ] Has associated issue been labelled `unverified`? (only applicable if this PR closes the issue)
|
|
||||||
* [ ] Has associated issue been labelled `bug`? (only applicable if this PR is for a bug fix)
|
|
||||||
* [ ] List of Acceptance Tests Performed.
|
|
||||||
|
|
||||||
Write out a small list of tests performed with just enough detail for another developer on the team
|
|
||||||
to execute.
|
|
||||||
|
|
||||||
i.e. ```When Clicking on Add button, new `object` appears in dropdown.```
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
# Open MCT License
|
|
||||||
|
|
||||||
Open MCT, Copyright (c) 2014-2022, United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All rights reserved.
|
|
||||||
|
|
||||||
Open MCT is licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
691
LICENSES.md
Normal file
@ -0,0 +1,691 @@
|
|||||||
|
# Open MCT Licenses
|
||||||
|
|
||||||
|
Open MCT, Copyright (c) 2014-2017, United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All rights reserved.
|
||||||
|
|
||||||
|
Open MCT is licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
Open MCT includes source code licensed under additional open source licenses as follows.
|
||||||
|
|
||||||
|
## Software Components Licenses
|
||||||
|
|
||||||
|
This software includes components released under the following licenses:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### SuperSocket
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://supersocket.codeplex.com/
|
||||||
|
|
||||||
|
* Version: 0.9.0.2
|
||||||
|
|
||||||
|
* Author: Kerry Jiang
|
||||||
|
|
||||||
|
* Description: Supports SuperWebSocket
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright 2012 Kerry Jiang (kerry-jiang@hotmail.com)
|
||||||
|
|
||||||
|
SuperSocket is licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### SuperWebSocket
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://superswebocket.codeplex.com/
|
||||||
|
|
||||||
|
* Version: 0.9.0.2
|
||||||
|
|
||||||
|
* Author: Kerry Jiang
|
||||||
|
|
||||||
|
* Description: WebSocket implementation for client-server communication
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright 2010-2013 Kerry Jiang (kerry-jiang@hotmail.com)
|
||||||
|
|
||||||
|
SuperWebSocket is licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### log4net
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://logging.apache.org/log4net/
|
||||||
|
|
||||||
|
* Version: 1.2.13
|
||||||
|
|
||||||
|
* Author: Apache Software Foundation
|
||||||
|
|
||||||
|
* Description: Logging.
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright © 2004-2015 Apache Software Foundation.
|
||||||
|
|
||||||
|
log4net is licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Blanket.js
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://blanketjs.org/
|
||||||
|
|
||||||
|
* Version: 1.1.5
|
||||||
|
|
||||||
|
* Author: Alex Seville
|
||||||
|
|
||||||
|
* Description: Code coverage measurement and reporting
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2013 Alex Seville
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Jasmine
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://jasmine.github.io/
|
||||||
|
|
||||||
|
* Version: 1.3.1
|
||||||
|
|
||||||
|
* Author: Pivotal Labs
|
||||||
|
|
||||||
|
* Description: Unit testing
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2008-2011 Pivotal Labs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### RequireJS
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://requirejs.org/
|
||||||
|
|
||||||
|
* Version: 2.1.22
|
||||||
|
|
||||||
|
* Author: The Dojo Foundation
|
||||||
|
|
||||||
|
* Description: Script loader
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2010-2015, The Dojo Foundation
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### requirejs-text
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://github.com/requirejs/text
|
||||||
|
|
||||||
|
* Version: 2.0.14
|
||||||
|
|
||||||
|
* Author: The Dojo Foundation
|
||||||
|
|
||||||
|
* Description: Text loading plugin for RequireJS
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2010-2014, The Dojo Foundation
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### AngularJS
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://angularjs.org/
|
||||||
|
|
||||||
|
* Version: 1.4.4
|
||||||
|
|
||||||
|
* Author: Google
|
||||||
|
|
||||||
|
* Description: Client-side web application framework
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Angular-Route
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://angularjs.org/
|
||||||
|
|
||||||
|
* Version: 1.4.4
|
||||||
|
|
||||||
|
* Author: Google
|
||||||
|
|
||||||
|
* Description: Client-side view routing
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ES6-Promise
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://github.com/jakearchibald/es6-promise
|
||||||
|
|
||||||
|
* Version: 3.0.2
|
||||||
|
|
||||||
|
* Authors: Yehuda Katz, Tom Dale, Stefan Penner and contributors
|
||||||
|
|
||||||
|
* Description: Promise polyfill for pre-ECMAScript 6 browsers
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### screenfull.js
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://github.com/sindresorhus/screenfull.js/
|
||||||
|
|
||||||
|
* Version: 3.0.0
|
||||||
|
|
||||||
|
* Author: Sindre Sorhus
|
||||||
|
|
||||||
|
* Description: Wrapper for cross-browser usage of fullscreen API
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Math.uuid.js
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://github.com/broofa/node-uuid
|
||||||
|
|
||||||
|
* Version: 1.4.7
|
||||||
|
|
||||||
|
* Author: Robert Kieffer
|
||||||
|
|
||||||
|
* Description: Unique identifer generation.
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2010-2012 Robert Kieffer
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Normalize.css
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://github.com/necolas/normalize.css
|
||||||
|
|
||||||
|
* Version: 1.1.2
|
||||||
|
|
||||||
|
* Authors: Nicolas Gallagher, Jonathan Neal
|
||||||
|
|
||||||
|
* Description: Browser style normalization
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) Nicolas Gallagher and Jonathan Neal
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Moment.js
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://momentjs.com
|
||||||
|
|
||||||
|
* Version: 2.11.1
|
||||||
|
|
||||||
|
* Authors: Tim Wood, Iskren Chernev, Moment.js contributors
|
||||||
|
|
||||||
|
* Description: Time/date parsing/formatting
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2011-2014 Tim Wood, Iskren Chernev, Moment.js contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### moment-duration-format
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://github.com/jsmreese/moment-duration-format
|
||||||
|
|
||||||
|
* Version: 1.3.0
|
||||||
|
|
||||||
|
* Authors: John Madhavan-Reese
|
||||||
|
|
||||||
|
* Description: Duration parsing/formatting
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright 2014 John Madhavan-Reese
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### CSV.js
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://github.com/knrz/CSV.js
|
||||||
|
|
||||||
|
* Version: 3.6.4
|
||||||
|
|
||||||
|
* Authors: Kash Nouroozi
|
||||||
|
|
||||||
|
* Description: Encoder for CSV (comma separated values) export
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2014 Kash Nouroozi
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### FileSaver.js
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: https://github.com/eligrey/FileSaver.js/
|
||||||
|
|
||||||
|
* Version: 0.0.2
|
||||||
|
|
||||||
|
* Authors: Eli Grey
|
||||||
|
|
||||||
|
* Description: File download initiator (for file exports)
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright © 2015 Eli Grey.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Zepto
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://zeptojs.com/
|
||||||
|
|
||||||
|
* Version: 1.1.6
|
||||||
|
|
||||||
|
* Authors: Thomas Fuchs
|
||||||
|
|
||||||
|
* Description: DOM manipulation
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2010-2016 Thomas Fuchs
|
||||||
|
http://zeptojs.com/
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Json.NET
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://www.newtonsoft.com/json
|
||||||
|
|
||||||
|
* Version: 6.0.8
|
||||||
|
|
||||||
|
* Author: Newtonsoft
|
||||||
|
|
||||||
|
* Description: JSON serialization/deserialization
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright (c) 2007 James Newton-King
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Nancy
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://nancyfx.org
|
||||||
|
|
||||||
|
* Version: 0.23.2
|
||||||
|
|
||||||
|
* Author: Andreas Håkansson, Steven Robbins and contributors
|
||||||
|
|
||||||
|
* Description: Embedded web server
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright © 2010 Andreas Håkansson, Steven Robbins and contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Nancy.Hosting.Self
|
||||||
|
|
||||||
|
#### Info
|
||||||
|
|
||||||
|
* Link: http://nancyfx.org
|
||||||
|
|
||||||
|
* Version: 0.23.2
|
||||||
|
|
||||||
|
* Author: Andreas Håkansson, Steven Robbins and contributors
|
||||||
|
|
||||||
|
* Description: Embedded web server
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright © 2010 Andreas Håkansson, Steven Robbins and contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Almond
|
||||||
|
|
||||||
|
* Link: https://github.com/requirejs/almond
|
||||||
|
|
||||||
|
* Version: 0.3.3
|
||||||
|
|
||||||
|
* Author: jQuery Foundation
|
||||||
|
|
||||||
|
* Description: Lightweight RequireJS replacement for builds
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright jQuery Foundation and other contributors, https://jquery.org/
|
||||||
|
|
||||||
|
This software consists of voluntary contributions made by many
|
||||||
|
individuals. For exact contribution history, see the revision history
|
||||||
|
available at https://github.com/requirejs/almond
|
||||||
|
|
||||||
|
The following license applies to all parts of this software except as
|
||||||
|
documented below:
|
||||||
|
|
||||||
|
====
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
====
|
||||||
|
|
||||||
|
Copyright and related rights for sample code are waived via CC0. Sample
|
||||||
|
code is defined as all source code displayed within the prose of the
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
CC0: http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
|
====
|
||||||
|
|
||||||
|
Files located in the node_modules directory, and certain utilities used
|
||||||
|
to build or test the software in the test and dist directories, are
|
||||||
|
externally maintained libraries used by this software which have their own
|
||||||
|
licenses; we recommend you read them, as their terms may differ from the
|
||||||
|
terms above.
|
||||||
|
|
||||||
|
|
||||||
|
### Lodash
|
||||||
|
|
||||||
|
* Link: https://lodash.com
|
||||||
|
|
||||||
|
* Version: 3.10.1
|
||||||
|
|
||||||
|
* Author: Dojo Foundation
|
||||||
|
|
||||||
|
* Description: Utility functions
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
|
||||||
|
Based on Underscore.js, copyright 2009-2015 Jeremy Ashkenas,
|
||||||
|
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
### EventEmitter3
|
||||||
|
|
||||||
|
* Link: https://github.com/primus/eventemitter3
|
||||||
|
|
||||||
|
* Version: 1.2.0
|
||||||
|
|
||||||
|
* Author: Arnout Kazemier
|
||||||
|
|
||||||
|
* Description: Event-driven programming support
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Arnout Kazemier
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
107
README.md
@ -1,31 +1,33 @@
|
|||||||
# Open MCT [](http://www.apache.org/licenses/LICENSE-2.0) [](https://lgtm.com/projects/g/nasa/openmct/context:javascript) [](https://codecov.io/gh/nasa/openmct) [](https://percy.io/b2e34b17/openmct) [](https://www.npmjs.com/package/openmct)
|
# Open MCT [](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
|
||||||
Open MCT (Open Mission Control Technologies) is a next-generation mission control framework for visualization of data on desktop and mobile devices. It is developed at NASA's Ames Research Center, and is being used by NASA for data analysis of spacecraft missions, as well as planning and operation of experimental rover systems. As a generalizable and open source framework, Open MCT could be used as the basis for building applications for planning, operation, and analysis of any systems producing telemetry data.
|
Open MCT (Open Mission Control Technologies) is a next-generation mission control framework for visualization of data on desktop and mobile devices. It is developed at NASA's Ames Research Center, and is being used by NASA for data analysis of spacecraft missions, as well as planning and operation of experimental rover systems. As a generalizable and open source framework, Open MCT could be used as the basis for building applications for planning, operation, and analysis of any systems producing telemetry data.
|
||||||
|
|
||||||
Please visit our [Official Site](https://nasa.github.io/openmct/) and [Getting Started Guide](https://nasa.github.io/openmct/getting-started/)
|
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!
|
|
||||||
|
|
||||||
## See Open MCT in Action
|
## See Open MCT in Action
|
||||||
|
|
||||||
Try Open MCT now with our [live demo](https://openmct-demo.herokuapp.com/).
|
Try Open MCT now with our [live demo](https://openmct-demo.herokuapp.com/).
|
||||||

|

|
||||||
|
|
||||||
## Open MCT v2.0.0
|
## New API
|
||||||
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.
|
A simpler, [easier-to-use API](https://nasa.github.io/openmct/docs/api/)
|
||||||
|
has been added to Open MCT. Changes in this
|
||||||
|
API include a move away from a declarative system of JSON configuration files
|
||||||
|
towards an imperative system based on function calls. Developers will be able
|
||||||
|
to extend and build on Open MCT by making direct function calls to a public
|
||||||
|
API. Open MCT is also being refactored to minimize the dependencies that using
|
||||||
|
Open MCT imposes on developers, such as the current requirement to use
|
||||||
|
AngularJS.
|
||||||
|
|
||||||
### How do I know if I am using legacy API?
|
This new API has not yet been heavily used and is likely to contain defects.
|
||||||
You might still be using legacy API if your source code
|
You can help by trying it out, and reporting any issues you encounter
|
||||||
|
using our GitHub issue tracker. Such issues may include bugs, suggestions,
|
||||||
|
missing documentation, or even just requests for help if you're having
|
||||||
|
trouble.
|
||||||
|
|
||||||
* Contains files named bundle.js, or bundle.json,
|
We want Open MCT to be as easy to use, install, run, and develop for as
|
||||||
* Makes calls to `openmct.$injector()`, or `openmct.$angular`,
|
possible, and your feedback will help us get there!
|
||||||
* 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.
|
|
||||||
|
|
||||||
## Building and Running Open MCT Locally
|
## Building and Running Open MCT Locally
|
||||||
|
|
||||||
@ -36,7 +38,7 @@ Building and running Open MCT in your local dev environment is very easy. Be sur
|
|||||||
|
|
||||||
`git clone https://github.com/nasa/openmct.git`
|
`git clone https://github.com/nasa/openmct.git`
|
||||||
|
|
||||||
2. Install development dependencies. Note: Check the package.json engine for our tested and supported node versions.
|
2. Install development dependencies
|
||||||
|
|
||||||
`npm install`
|
`npm install`
|
||||||
|
|
||||||
@ -48,7 +50,7 @@ Open MCT is now running, and can be accessed by pointing a web browser at [http:
|
|||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
Documentation is available on the [Open MCT website](https://nasa.github.io/openmct/documentation/).
|
Documentation is available on the [Open MCT website](https://nasa.github.io/openmct/documentation/). The documentation can also be built locally.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
@ -56,29 +58,48 @@ The clearest examples for developing Open MCT plugins are in the
|
|||||||
[tutorials](https://github.com/nasa/openmct-tutorial) provided in
|
[tutorials](https://github.com/nasa/openmct-tutorial) provided in
|
||||||
our documentation.
|
our documentation.
|
||||||
|
|
||||||
We want Open MCT to be as easy to use, install, run, and develop for as
|
For a practical example of a telemetry adapter, see David Hudson's
|
||||||
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).
|
[Kerbal Space Program plugin](https://github.com/hudsonfoo/kerbal-openmct),
|
||||||
|
which allows [Kerbal Space Program](https://kerbalspaceprogram.com) players
|
||||||
|
to build and use displays for their own missions in Open MCT.
|
||||||
|
|
||||||
## Building Applications With Open MCT
|
Additional examples are available in the `examples` hierarchy of this
|
||||||
|
repository; however, be aware that these examples are
|
||||||
|
[not fully-documented](https://github.com/nasa/openmct/issues/846), so
|
||||||
|
the tutorials will likely serve as a better starting point.
|
||||||
|
|
||||||
Open MCT is built using [`npm`](http://npmjs.com/) and [`webpack`](https://webpack.js.org/).
|
### Building the Open MCT Documentation Locally
|
||||||
|
Open MCT's documentation is generated by an
|
||||||
|
[npm](https://www.npmjs.com/)-based build. It has additional dependencies that
|
||||||
|
may not be available on every platform and thus is not covered in the standard
|
||||||
|
npm install. Ensure your system has [libcairo](http://cairographics.org/)
|
||||||
|
installed and then run the following commands:
|
||||||
|
|
||||||
See our documentation for a guide on [building Applications with Open MCT](https://github.com/nasa/openmct/blob/master/API.md#starting-an-open-mct-application).
|
* `npm install`
|
||||||
|
* `npm install canvas nomnoml`
|
||||||
|
* `npm run docs`
|
||||||
|
|
||||||
## Plugins
|
Documentation will be generated in `target/docs`.
|
||||||
|
|
||||||
Open MCT can be extended via plugins that make calls to the Open MCT API. A plugin is a group
|
## Deploying Open MCT
|
||||||
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
|
Open MCT is built using [`npm`](http://npmjs.com/)
|
||||||
written as plugins.
|
|
||||||
|
|
||||||
For information on writing plugins, please see [our API documentation](https://github.com/nasa/openmct/blob/master/API.md#plugins).
|
To build Open MCT for deployment:
|
||||||
|
|
||||||
|
`npm run prepare`
|
||||||
|
|
||||||
|
This will compile and minify JavaScript sources, as well as copy over assets.
|
||||||
|
The contents of the `dist` folder will contain a runnable Open MCT
|
||||||
|
instance (e.g. by starting an HTTP server in that directory), including:
|
||||||
|
|
||||||
|
* `openmct.js` - Open MCT source code.
|
||||||
|
* `openmct.css` - Basic styles to load to prevent a FOUC.
|
||||||
|
* `index.html`, an example to run Open MCT in the basic configuration.
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
Tests are written for [Jasmine 3](https://jasmine.github.io/api/3.1/global)
|
Tests are written for [Jasmine 3](http://jasmine.github.io/)
|
||||||
and run by [Karma](http://karma-runner.github.io). To run:
|
and run by [Karma](http://karma-runner.github.io). To run:
|
||||||
|
|
||||||
`npm test`
|
`npm test`
|
||||||
@ -94,9 +115,7 @@ naming convention is otherwise the same.)
|
|||||||
### Test Reporting
|
### Test Reporting
|
||||||
|
|
||||||
When `npm test` is run, test results will be written as HTML to
|
When `npm test` is run, test results will be written as HTML to
|
||||||
`dist/reports/tests/`. Code coverage information is written to `dist/reports/coverage`.
|
`target/tests`. Code coverage information is written to `target/coverage`.
|
||||||
|
|
||||||
Code Coverage Reports are available from [codecov.io](https://app.codecov.io/gh/nasa/openmct/)
|
|
||||||
|
|
||||||
# Glossary
|
# Glossary
|
||||||
|
|
||||||
@ -106,8 +125,11 @@ addressed (either by updating this glossary or changing code to reflect
|
|||||||
correct usage.) Other developer documentation, particularly in-line
|
correct usage.) Other developer documentation, particularly in-line
|
||||||
documentation, may presume an understanding of these terms.
|
documentation, may presume an understanding of these terms.
|
||||||
|
|
||||||
* _plugin_: A plugin is a removable, reusable grouping of software elements.
|
* _bundle_: A bundle is a removable, reusable grouping of software elements.
|
||||||
The application is composed of plugins.
|
The application is composed of bundles. Plug-ins are bundles. For more
|
||||||
|
information, refer to framework documentation (under `platform/framework`.)
|
||||||
|
* _capability_: An object which exposes dynamic behavior or non-persistent
|
||||||
|
state associated with a domain object.
|
||||||
* _composition_: In the context of a domain object, this refers to the set of
|
* _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
|
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
|
object's composition is the set of domain objects that should appear
|
||||||
@ -122,8 +144,13 @@ documentation, may presume an understanding of these terms.
|
|||||||
* _domain object_: A meaningful object to the user; a distinct thing in
|
* _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
|
the work support by Open MCT. Anything that appears in the left-hand
|
||||||
tree is a domain object.
|
tree is a domain object.
|
||||||
* _identifier_: A tuple consisting of a namespace and a key, which together uniquely
|
* _extension_: An extension is a unit of functionality exposed to the
|
||||||
identifies a domain object.
|
platform in a declarative fashion by a bundle. For more
|
||||||
|
information, refer to framework documentation (under `platform/framework`.)
|
||||||
|
* _id_: A string which uniquely identifies a domain object.
|
||||||
|
* _key_: When used as an object property, this refers to the machine-readable
|
||||||
|
identifier for a specific thing in a set of things. (Most often used in the
|
||||||
|
context of extensions or other similar application-specific object sets.)
|
||||||
* _model_: The persistent state associated with a domain object. A domain
|
* _model_: The persistent state associated with a domain object. A domain
|
||||||
object's model is a JavaScript object which can be converted to JSON
|
object's model is a JavaScript object which can be converted to JSON
|
||||||
without losing information (that is, it contains no methods.)
|
without losing information (that is, it contains no methods.)
|
||||||
@ -135,5 +162,7 @@ documentation, may presume an understanding of these terms.
|
|||||||
a user clicks on a domain object in the tree, they are _navigating_ to
|
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
|
it, and it is thereafter considered the _navigated_ object (until the
|
||||||
user makes another such choice.)
|
user makes another such choice.)
|
||||||
* _namespace_: A name used to identify a persistence store. A running open MCT
|
* _space_: A name used to identify a persistence store. Interactions with
|
||||||
application could potentially use multiple persistence stores, with the
|
persistence will generally involve a `space` parameter in some form, to
|
||||||
|
distinguish multiple persistence stores from one another (for cases
|
||||||
|
where there are multiple valid persistence locations available.)
|
||||||
|
31
SECURITY.md
@ -1,31 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
The Open MCT team secures our code base using a combination of code review, dependency review, and periodic security reviews. Static analysis performed during automated verification additionally safeguards against common coding errors which may result in vulnerabilities.
|
|
||||||
|
|
||||||
### Reporting a Vulnerability
|
|
||||||
|
|
||||||
For general defects, please for a [Bug Report](https://github.com/nasa/openmct/issues/new/choose)
|
|
||||||
|
|
||||||
To report a vulnerability for Open MCT please send a detailed report to [arc-dl-openmct](mailto:arc-dl-openmct@mail.nasa.gov).
|
|
||||||
|
|
||||||
See our [top-level security policy](https://github.com/nasa/openmct/security/policy) for additional information.
|
|
||||||
|
|
||||||
### CodeQL and LGTM
|
|
||||||
|
|
||||||
The [CodeQL GitHub Actions workflow](https://github.com/nasa/openmct/blob/master/.github/workflows/codeql-analysis.yml) is available to the public. To review the results, fork the repository and run the CodeQL workflow.
|
|
||||||
|
|
||||||
CodeQL is run for every pull-request in GitHub Actions.
|
|
||||||
|
|
||||||
The project is also monitored by [LGTM](https://lgtm.com/projects/g/nasa/openmct/) and is available to public.
|
|
||||||
|
|
||||||
### ESLint
|
|
||||||
|
|
||||||
Static analysis is run for every push on the master branch and every pull request on all branches in Github Actions.
|
|
||||||
|
|
||||||
For more information about ESLint, visit https://eslint.org/.
|
|
||||||
|
|
||||||
### General Support
|
|
||||||
|
|
||||||
For additional support, please open a [Github Discussion](https://github.com/nasa/openmct/discussions).
|
|
||||||
|
|
||||||
If you wish to report a cybersecurity incident or concern, please contact the NASA Security Operations Center either by phone at 1-877-627-2732 or via email address soc@nasa.gov.
|
|
28
app.js
@ -1,4 +1,4 @@
|
|||||||
/*global process*/
|
/*global require,process,console*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Usage:
|
* Usage:
|
||||||
@ -7,6 +7,7 @@
|
|||||||
* node app.js [options]
|
* node app.js [options]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
const options = require('minimist')(process.argv.slice(2));
|
const options = require('minimist')(process.argv.slice(2));
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const app = express();
|
const app = express();
|
||||||
@ -15,7 +16,7 @@ const request = require('request');
|
|||||||
|
|
||||||
// Defaults
|
// Defaults
|
||||||
options.port = options.port || options.p || 8080;
|
options.port = options.port || options.p || 8080;
|
||||||
options.host = options.host || 'localhost';
|
options.host = options.host || options.h || 'localhost';
|
||||||
options.directory = options.directory || options.D || '.';
|
options.directory = options.directory || options.D || '.';
|
||||||
|
|
||||||
// Show command line options
|
// Show command line options
|
||||||
@ -39,22 +40,13 @@ app.use('/proxyUrl', function proxyRequest(req, res, next) {
|
|||||||
}).on('error', next)).pipe(res);
|
}).on('error', next)).pipe(res);
|
||||||
});
|
});
|
||||||
|
|
||||||
class WatchRunPlugin {
|
|
||||||
apply(compiler) {
|
|
||||||
compiler.hooks.emit.tapAsync('WatchRunPlugin', (compilation, callback) => {
|
|
||||||
console.log('Begin compile at ' + new Date());
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const webpackConfig = require('./webpack.dev.js');
|
const webpackConfig = require('./webpack.config.js');
|
||||||
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
|
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
|
||||||
webpackConfig.plugins.push(new WatchRunPlugin());
|
webpackConfig.plugins.push(function() { this.plugin('watch-run', function(watching, callback) { console.log('Begin compile at ' + new Date()); callback(); }) });
|
||||||
|
|
||||||
webpackConfig.entry.openmct = [
|
webpackConfig.entry.openmct = [
|
||||||
'webpack-hot-middleware/client?reload=true',
|
'webpack-hot-middleware/client',
|
||||||
webpackConfig.entry.openmct
|
webpackConfig.entry.openmct
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -70,7 +62,9 @@ app.use(require('webpack-dev-middleware')(
|
|||||||
|
|
||||||
app.use(require('webpack-hot-middleware')(
|
app.use(require('webpack-hot-middleware')(
|
||||||
compiler,
|
compiler,
|
||||||
{}
|
{
|
||||||
|
|
||||||
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
// Expose index.html for development users.
|
// Expose index.html for development users.
|
||||||
@ -79,6 +73,6 @@ app.get('/', function (req, res) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Finally, open the HTTP server and log the instance to the console
|
// Finally, open the HTTP server and log the instance to the console
|
||||||
app.listen(options.port, options.host, function () {
|
app.listen(options.port, options.host, function() {
|
||||||
console.log('Open MCT application running at %s:%s', options.host, options.port);
|
console.log('Open MCT application running at %s:%s', options.host, options.port)
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
#*****************************************************************************
|
#*****************************************************************************
|
||||||
#* Open MCT, Copyright (c) 2014-2022, United States Government
|
#* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
#* as represented by the Administrator of the National Aeronautics and Space
|
#* as represented by the Administrator of the National Aeronautics and Space
|
||||||
#* Administration. All rights reserved.
|
#* Administration. All rights reserved.
|
||||||
#*
|
#*
|
||||||
|
29
codecov.yml
@ -1,29 +0,0 @@
|
|||||||
codecov:
|
|
||||||
require_ci_to_pass: false #This setting will update the bot regardless of whether or not tests pass
|
|
||||||
|
|
||||||
coverage:
|
|
||||||
status:
|
|
||||||
project:
|
|
||||||
default:
|
|
||||||
informational: true
|
|
||||||
patch:
|
|
||||||
default:
|
|
||||||
informational: true
|
|
||||||
precision: 2
|
|
||||||
round: down
|
|
||||||
range: "66...100"
|
|
||||||
|
|
||||||
ignore:
|
|
||||||
|
|
||||||
parsers:
|
|
||||||
gcov:
|
|
||||||
branch_detection:
|
|
||||||
conditional: true
|
|
||||||
loop: true
|
|
||||||
method: false
|
|
||||||
macro: false
|
|
||||||
|
|
||||||
comment:
|
|
||||||
layout: "reach,diff,flags,files,footer"
|
|
||||||
behavior: default
|
|
||||||
require_changes: false
|
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
Open MCT, Copyright (c) 2014-2022, United States Government
|
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
as represented by the Administrator of the National Aeronautics and Space
|
as represented by the Administrator of the National Aeronautics and Space
|
||||||
Administration. All rights reserved.
|
Administration. All rights reserved.
|
||||||
|
|
||||||
@ -18,4 +18,4 @@
|
|||||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
this source code distribution or the Licensing information page available
|
this source code distribution or the Licensing information page available
|
||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -18,4 +18,4 @@
|
|||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
|
232
docs/src/architecture/framework.md
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
# Overview
|
||||||
|
|
||||||
|
The framework layer's most basic responsibility is allowing individual
|
||||||
|
software components to communicate. The software components it recognizes
|
||||||
|
are:
|
||||||
|
|
||||||
|
* _Extensions_: Individual units of functionality that can be added to
|
||||||
|
or removed from Open MCT. _Extension categories_ distinguish what
|
||||||
|
type of functionality is being added/removed.
|
||||||
|
* _Bundles_: A grouping of related extensions
|
||||||
|
(named after an analogous concept from [OSGi](http://www.osgi.org/))
|
||||||
|
that may be added or removed as a group.
|
||||||
|
|
||||||
|
The framework layer operates by taking a set of active bundles, and
|
||||||
|
exposing extensions to one another as-needed, using
|
||||||
|
[dependency injection](https://en.wikipedia.org/wiki/Dependency_injection).
|
||||||
|
Extensions are responsible for declaring their dependencies in a
|
||||||
|
manner which the framework layer can understand.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: down
|
||||||
|
[Open MCT|
|
||||||
|
[Dependency injection framework]-->[Platform bundle #1]
|
||||||
|
[Dependency injection framework]-->[Platform bundle #2]
|
||||||
|
[Dependency injection framework]-->[Plugin bundle #1]
|
||||||
|
[Dependency injection framework]-->[Plugin bundle #2]
|
||||||
|
[Platform bundle #1|[Extensions]]
|
||||||
|
[Platform bundle #2|[Extensions]]
|
||||||
|
[Plugin bundle #1|[Extensions]]
|
||||||
|
[Plugin bundle #2|[Extensions]]
|
||||||
|
[Platform bundle #1]<->[Platform bundle #2]
|
||||||
|
[Plugin bundle #1]<->[Platform bundle #2]
|
||||||
|
[Plugin bundle #1]<->[Plugin bundle #2]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
The "dependency injection framework" in this case is
|
||||||
|
[AngularJS](https://angularjs.org/). Open MCT's framework layer
|
||||||
|
is really just a thin wrapper over Angular that recognizes the
|
||||||
|
concepts of bundles and extensions (as declared in JSON files) and
|
||||||
|
registering extensions with Angular. It additionally acts as a
|
||||||
|
mediator between Angular and [RequireJS](http://requirejs.org/),
|
||||||
|
which is used to load JavaScript sources which implement
|
||||||
|
extensions.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[Framework layer|
|
||||||
|
[AngularJS]<-[Framework Component]
|
||||||
|
[RequireJS]<-[Framework Component]
|
||||||
|
[Framework Component]1o-*[Bundles]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
It is worth noting that _no other components_ are "aware" of the
|
||||||
|
framework component directly; Angular and Require are _used by_ the
|
||||||
|
framework components, and extensions in various bundles will have
|
||||||
|
their dependencies satisfied by Angular as a consequence of registration
|
||||||
|
activities which were performed by the framework component.
|
||||||
|
|
||||||
|
|
||||||
|
## Application Initialization
|
||||||
|
|
||||||
|
The framework component initializes an Open MCT application following
|
||||||
|
a simple sequence of steps.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[<start> Start]->[<state> Load bundles.json]
|
||||||
|
[Load bundles.json]->[<state> Load bundle.json files]
|
||||||
|
[Load bundle.json files]->[<state> Resolve implementations]
|
||||||
|
[Resolve implementations]->[<state> Register with Angular]
|
||||||
|
[Register with Angular]->[<state> Bootstrap application]
|
||||||
|
[Bootstrap application]->[<end> End]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. __Loading bundles.json.__ A file named `bundles.json` is loaded to determine
|
||||||
|
which bundles to load. Bundles are given in this file as relative paths
|
||||||
|
which point to bundle directories.
|
||||||
|
2. __Load bundle.json files.__ Individual bundle definitions are loaded; a
|
||||||
|
`bundle.json` file is expected in each bundle directory.
|
||||||
|
2. __Resolving implementations.__ Any scripts which provide implementations for
|
||||||
|
extensions exposed by bundles are loaded, using RequireJS.
|
||||||
|
3. __Register with Angular.__ Resolved extensions are registered with Angular,
|
||||||
|
such that they can be used by the application at run-time. This stage
|
||||||
|
includes both registration of Angular built-ins (directives, controllers,
|
||||||
|
routes, constants, and services) as well as registration of non-Angular
|
||||||
|
extensions.
|
||||||
|
4. __Bootstrap application.__ Once all extensions have been registered,
|
||||||
|
the Angular application
|
||||||
|
[is bootstrapped](https://docs.angularjs.org/guide/bootstrap).
|
||||||
|
|
||||||
|
## Architectural Paradigm
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[Extension]
|
||||||
|
[Extension]o->[Dependency #1]
|
||||||
|
[Extension]o->[Dependency #2]
|
||||||
|
[Extension]o->[Dependency #3]
|
||||||
|
```
|
||||||
|
|
||||||
|
Open MCT's architecture relies on a simple premise: Individual units
|
||||||
|
(extensions) only have access to the dependencies they declare that they
|
||||||
|
need, and they acquire references to these dependencies via dependency
|
||||||
|
injection. This has several desirable traits:
|
||||||
|
|
||||||
|
* Programming to an interface is enforced. Any given dependency can be
|
||||||
|
swapped out for something which exposes an equivalent interface. This
|
||||||
|
improves flexibility against refactoring, simplifies testing, and
|
||||||
|
provides a common mechanism for extension and reconfiguration.
|
||||||
|
* The dependencies of a unit must be explicitly defined. This means that
|
||||||
|
it can be easily determined what a given unit's role is within the
|
||||||
|
larger system, in terms of what other components it will interact with.
|
||||||
|
It also helps to enforce good separation of concerns: When a set of
|
||||||
|
declared dependencies becomes long it is obvious, and this is usually
|
||||||
|
a sign that a given unit is involved in too many concerns and should
|
||||||
|
be refactored into smaller pieces.
|
||||||
|
* Individual units do not need to be aware of the framework; they need
|
||||||
|
only be aware of the interfaces to the components they specifically
|
||||||
|
use. This avoids introducing a ubiquitous dependency upon the framework
|
||||||
|
layer itself; it is plausible to modify or replace the framework
|
||||||
|
without making changes to individual software components which run upon
|
||||||
|
the framework.
|
||||||
|
|
||||||
|
A drawback to this approach is that it makes it difficult to define
|
||||||
|
"the architecture" of Open MCT, in terms of describing the specific
|
||||||
|
units that interact at run-time. The run-time architecture is determined
|
||||||
|
by the framework as the consequence of wiring together dependencies.
|
||||||
|
As such, the specific architecture of any given application built on
|
||||||
|
Open MCT can look very different.
|
||||||
|
|
||||||
|
Keeping that in mind, there are a few useful patterns supported by the
|
||||||
|
framework that are useful to keep in mind.
|
||||||
|
|
||||||
|
The specific service infrastructure provided by the platform is described
|
||||||
|
in the [Platform Architecture](platform.md).
|
||||||
|
|
||||||
|
## Extension Categories
|
||||||
|
|
||||||
|
One of the capabilities that the framework component layers on top of
|
||||||
|
AngularJS is support for many-to-one dependencies. That is, a specific
|
||||||
|
extension may declare a dependency to _all extensions of a specific
|
||||||
|
category_, instead of being limited to declaring specific dependencies.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: right
|
||||||
|
[Specific Extension] 1 o-> * [Extension of Some Category]
|
||||||
|
```
|
||||||
|
|
||||||
|
This is useful for introducing specific extension points to an application.
|
||||||
|
Some unit of software will depend upon all extensions of a given category
|
||||||
|
and integrate their behavior into the system in some fashion; plugin authors
|
||||||
|
can then add new extensions of that category to augment existing behaviors.
|
||||||
|
|
||||||
|
Some developers may be familiar with the use of registries to achieve
|
||||||
|
similar characteristics. This approach is similar, except that the registry
|
||||||
|
is effectively implicit whenever a new extension category is used or
|
||||||
|
depended-upon. This has some advantages over a more straightforward
|
||||||
|
registry-based approach:
|
||||||
|
|
||||||
|
* These many-to-one relationships are expressed as dependencies; an
|
||||||
|
extension category is registered as having dependencies on all individual
|
||||||
|
extensions of this category. This avoids ordering issues that may occur
|
||||||
|
with more conventional registries, which may be observed before all
|
||||||
|
dependencies are resolved.
|
||||||
|
* The need for service registries of specific types is removed, reducing
|
||||||
|
the number of interfaces to manage within the system. Groups of
|
||||||
|
extensions are provided as arrays.
|
||||||
|
|
||||||
|
## Composite Services
|
||||||
|
|
||||||
|
Composite services (registered via extension category `components`) are
|
||||||
|
a pattern supported by the framework. These allow service instances to
|
||||||
|
be built from multiple components at run-time; support for this pattern
|
||||||
|
allows additional bundles to introduce or modify behavior associated
|
||||||
|
with these services without modifying or replacing original service
|
||||||
|
instances.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: down
|
||||||
|
[<abstract> FooService]
|
||||||
|
[FooDecorator #1]--:>[FooService]
|
||||||
|
[FooDecorator #n]--:>[FooService]
|
||||||
|
[FooAggregator]--:>[FooService]
|
||||||
|
[FooProvider #1]--:>[FooService]
|
||||||
|
[FooProvider #n]--:>[FooService]
|
||||||
|
|
||||||
|
[FooDecorator #1]o->[<state> ...decorators...]
|
||||||
|
[...decorators...]o->[FooDecorator #n]
|
||||||
|
[FooDecorator #n]o->[FooAggregator]
|
||||||
|
[FooAggregator]o->[FooProvider #1]
|
||||||
|
[FooAggregator]o->[<state> ...providers...]
|
||||||
|
[FooAggregator]o->[FooProvider #n]
|
||||||
|
|
||||||
|
[FooDecorator #1]--[<note> Exposed as fooService]
|
||||||
|
```
|
||||||
|
|
||||||
|
In this pattern, components all implement an interface which is
|
||||||
|
standardized for that service. Components additionally declare
|
||||||
|
that they belong to one of three types:
|
||||||
|
|
||||||
|
* __Providers.__ A provider actually implements the behavior
|
||||||
|
(satisfies the contract) for that kind of service. For instance,
|
||||||
|
if a service is responsible for looking up documents by an identifier,
|
||||||
|
one provider may do so by querying a database, while another may
|
||||||
|
do so by reading a static JSON document. From the outside, either
|
||||||
|
provider would look the same (they expose the same interface) and
|
||||||
|
they could be swapped out easily.
|
||||||
|
* __Aggregator.__ An aggregator takes many providers and makes them
|
||||||
|
behave as one. Again, this implements the same interface as an
|
||||||
|
individual provider, so users of the service do not need to be
|
||||||
|
concerned about the difference between consulting many providers
|
||||||
|
and consulting one. Continuing with the example of a service that
|
||||||
|
looks up documents by identifiers, an aggregator here might consult
|
||||||
|
all providers, and return any document is found (perhaps picking one
|
||||||
|
over the other or merging documents if there are multiple matches.)
|
||||||
|
* __Decorators.__ A decorator exposes the same interface as other
|
||||||
|
components, but instead of fully implementing the behavior associated
|
||||||
|
with that kind of service, it only acts as an intermediary, delegating
|
||||||
|
the actual behavior to a different component. Decorators may transform
|
||||||
|
inputs or outputs, or initiate some side effects associated with a
|
||||||
|
service. This is useful if certain common behavior associated with a
|
||||||
|
service (caching, for instance) may be useful across many different
|
||||||
|
implementations of that same service.
|
||||||
|
|
||||||
|
The framework will register extensions in this category such that an
|
||||||
|
aggregator will depend on all of its providers, and decorators will
|
||||||
|
depend upon on one another in a chain. The result of this compositing step
|
||||||
|
(the last decorator, if any; otherwise the aggregator, if any;
|
||||||
|
otherwise a single provider) will be exposed as a single service that
|
||||||
|
other extensions can acquire through dependency injection. Because all
|
||||||
|
components of the same type of service expose the same interface, users
|
||||||
|
of that service do not need to be aware that they are talking to an
|
||||||
|
aggregator or a provider, for instance.
|
76
docs/src/architecture/index.md
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Introduction
|
||||||
|
|
||||||
|
The purpose of this document is to familiarize developers with the
|
||||||
|
overall architecture of Open MCT.
|
||||||
|
|
||||||
|
The target audience includes:
|
||||||
|
|
||||||
|
* _Platform maintainers_: Individuals involved in developing,
|
||||||
|
extending, and maintaining capabilities of the platform.
|
||||||
|
* _Integration developers_: Individuals tasked with integrated
|
||||||
|
Open MCT into a larger system, who need to understand
|
||||||
|
its inner workings sufficiently to complete this integration.
|
||||||
|
|
||||||
|
As the focus of this document is on architecture, whenever possible
|
||||||
|
implementation details (such as relevant API or JSON syntax) have been
|
||||||
|
omitted. These details may be found in the developer guide.
|
||||||
|
|
||||||
|
# Overview
|
||||||
|
|
||||||
|
Open MCT is client software: It runs in a web browser and
|
||||||
|
provides a user interface, while communicating with various
|
||||||
|
server-side resources through browser APIs.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: right
|
||||||
|
[Client|[Browser|[Open MCT]->[Browser APIs]]]
|
||||||
|
[Server|[Web services]]
|
||||||
|
[Client]<->[Server]
|
||||||
|
```
|
||||||
|
|
||||||
|
While Open MCT can be configured to run as a standalone client,
|
||||||
|
this is rarely very useful. Instead, it is intended to be used as a
|
||||||
|
display and interaction layer for information obtained from a
|
||||||
|
variety of back-end services. Doing so requires authoring or utilizing
|
||||||
|
adapter plugins which allow Open MCT to interact with these services.
|
||||||
|
|
||||||
|
Typically, the pattern here is to provide a known interface that
|
||||||
|
Open MCT can utilize, and implement it such that it interacts with
|
||||||
|
whatever back-end provides the relevant information.
|
||||||
|
Examples of back-ends that can be utilized in this fashion include
|
||||||
|
databases for the persistence of user-created objects, or sources of
|
||||||
|
telemetry data.
|
||||||
|
|
||||||
|
## Software Architecture
|
||||||
|
|
||||||
|
The simplest overview of Open MCT is to look at it as a "layered"
|
||||||
|
architecture, where each layer more clearly specifies the behavior
|
||||||
|
of the software.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: down
|
||||||
|
[Open MCT|
|
||||||
|
[Platform]<->[Application]
|
||||||
|
[Framework]->[Application]
|
||||||
|
[Framework]->[Platform]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
These layers are:
|
||||||
|
|
||||||
|
* [_Framework_](framework.md): The framework layer is responsible for
|
||||||
|
managing the interactions between application components. It has no
|
||||||
|
application-specific knowledge; at this layer, we have only
|
||||||
|
established an abstraction by which different software components
|
||||||
|
may communicate and/or interact.
|
||||||
|
* [_Platform_](platform.md): The platform layer defines the general look,
|
||||||
|
feel, and behavior of Open MCT. This includes user-facing components like
|
||||||
|
Browse mode and Edit mode, as well as underlying elements of the
|
||||||
|
information model and the general service infrastructure.
|
||||||
|
* _Application_: The application layer defines specific features of
|
||||||
|
an application built on Open MCT. This includes adapters to
|
||||||
|
specific back-ends, new types of things for users to create, and
|
||||||
|
new ways of visualizing objects within the system. This layer
|
||||||
|
typically consists of a mix of custom plug-ins to Open MCT,
|
||||||
|
as well as optional features (such as Plot view) included alongside
|
||||||
|
the platform.
|
726
docs/src/architecture/platform.md
Normal file
@ -0,0 +1,726 @@
|
|||||||
|
# Overview
|
||||||
|
|
||||||
|
The Open MCT platform utilizes the [framework layer](framework.md)
|
||||||
|
to provide an extensible baseline for applications which includes:
|
||||||
|
|
||||||
|
* A common user interface (and user interface paradigm) for dealing with
|
||||||
|
domain objects of various sorts.
|
||||||
|
* A variety of extension points for introducing new functionality
|
||||||
|
of various kinds within the context of the common user interface.
|
||||||
|
* A service infrastructure to support building additional components.
|
||||||
|
|
||||||
|
## Platform Architecture
|
||||||
|
|
||||||
|
While the framework provides a more general architectural paradigm for
|
||||||
|
building application, the platform adds more specificity by defining
|
||||||
|
additional extension types and allowing for integration with back end
|
||||||
|
components.
|
||||||
|
|
||||||
|
The run-time architecture of an Open MCT application can be categorized
|
||||||
|
into certain high-level tiers:
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[DOM]->[<state> AngularJS]
|
||||||
|
[AngularJS]->[Presentation Layer]
|
||||||
|
[Presentation Layer]->[Information Model]
|
||||||
|
[Presentation Layer]->[Service Infrastructure]
|
||||||
|
[Information Model]->[Service Infrastructure]
|
||||||
|
[Service Infrastructure]->[<state> Browser APIs]
|
||||||
|
[Browser APIs]->[Back-end]
|
||||||
|
```
|
||||||
|
|
||||||
|
Applications built using Open MCT may add or configure functionality
|
||||||
|
in __any of these tiers__.
|
||||||
|
|
||||||
|
* _DOM_: The rendered HTML document, composed from HTML templates which
|
||||||
|
have been processed by AngularJS and will be updated by AngularJS
|
||||||
|
to reflect changes from the presentation layer. User interactions
|
||||||
|
are initiated from here and invoke behavior in the presentation layer. HTML
|
||||||
|
templates are written in Angular’s template syntax; see the [Angular documentation on templates](https://docs.angularjs.org/guide/templates).
|
||||||
|
These describe the page as actually seen by the user. Conceptually,
|
||||||
|
stylesheets (controlling the look-and-feel of the rendered templates) belong
|
||||||
|
in this grouping as well.
|
||||||
|
* [_Presentation layer_](#presentation-layer): The presentation layer
|
||||||
|
is responsible for updating (and providing information to update)
|
||||||
|
the displayed state of the application. The presentation layer consists
|
||||||
|
primarily of _controllers_ and _directives_. The presentation layer is
|
||||||
|
concerned with inspecting the information model and preparing it for
|
||||||
|
display.
|
||||||
|
* [_Information model_](#information-model): Provides a common (within Open MCT
|
||||||
|
Web) set of interfaces for dealing with “things” domain objects within the
|
||||||
|
system. User-facing concerns in a Open MCT Web application are expressed as
|
||||||
|
domain objects; examples include folders (used to organize other domain
|
||||||
|
objects), layouts (used to build displays), or telemetry points (used as
|
||||||
|
handles for streams of remote measurements.) These domain objects expose a
|
||||||
|
common set of interfaces to allow reusable user interfaces to be built in the
|
||||||
|
presentation and template tiers; the specifics of these behaviors are then
|
||||||
|
mapped to interactions with underlying services.
|
||||||
|
* [_Service infrastructure_](#service-infrastructure): The service
|
||||||
|
infrastructure is responsible for providing the underlying general
|
||||||
|
functionality needed to support the information model. This includes
|
||||||
|
exposing underlying sets of extensions and mediating with the
|
||||||
|
back-end.
|
||||||
|
* _Back-end_: The back-end is out of the scope of Open MCT, except
|
||||||
|
for the interfaces which are utilized by adapters participating in the
|
||||||
|
service infrastructure. Includes the underlying persistence stores, telemetry
|
||||||
|
streams, and so forth which the Open MCT Web client is being used to interact
|
||||||
|
with.
|
||||||
|
|
||||||
|
## Application Start-up
|
||||||
|
|
||||||
|
Once the
|
||||||
|
[application has been initialized](Framework.md#application-initialization)
|
||||||
|
Open MCT primarily operates in an event-driven paradigm; various
|
||||||
|
events (mouse clicks, timers firing, receiving responses to XHRs) trigger
|
||||||
|
the invocation of functions, typically in the presentation layer for
|
||||||
|
user actions or in the service infrastructure for server responses.
|
||||||
|
|
||||||
|
The "main point of entry" into an initialized Open MCT application
|
||||||
|
is effectively the
|
||||||
|
[route](https://docs.angularjs.org/api/ngRoute/service/$route#example)
|
||||||
|
which is associated with the URL used to access Open MCT (or a
|
||||||
|
default route.) This route will be associated with a template which
|
||||||
|
will be displayed; this template will include references to directives
|
||||||
|
and controllers which will be interpreted by Angular and used to
|
||||||
|
initialize the state of the display in a manner which is backed by
|
||||||
|
both the information model and the service infrastructure.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[<start> Start]->[<state> page load]
|
||||||
|
[page load]->[<state> route selection]
|
||||||
|
[route selection]->[<state> compile, display template]
|
||||||
|
[compile, display template]->[Template]
|
||||||
|
[Template]->[<state> use Controllers]
|
||||||
|
[Template]->[<state> use Directives]
|
||||||
|
[use Controllers]->[Controllers]
|
||||||
|
[use Directives]->[Directives]
|
||||||
|
[Controllers]->[<state> consult information model]
|
||||||
|
[consult information model]->[<state> expose data]
|
||||||
|
[expose data]->[Angular]
|
||||||
|
[Angular]->[<state> update display]
|
||||||
|
[Directives]->[<state> add event listeners]
|
||||||
|
[Directives]->[<state> update display]
|
||||||
|
[add event listeners]->[<end> End]
|
||||||
|
[update display]->[<end> End]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Presentation Layer
|
||||||
|
|
||||||
|
The presentation layer of Open MCT is responsible for providing
|
||||||
|
information to display within templates, and for handling interactions
|
||||||
|
which are initiated from templated DOM elements. AngularJS acts as
|
||||||
|
an intermediary between the web page as the user sees it, and the
|
||||||
|
presentation layer implemented as Open MCT extensions.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[Presentation Layer|
|
||||||
|
[Angular built-ins|
|
||||||
|
[routes]
|
||||||
|
[controllers]
|
||||||
|
[directives]
|
||||||
|
[templates]
|
||||||
|
]
|
||||||
|
[Domain object representation|
|
||||||
|
[views]
|
||||||
|
[representations]
|
||||||
|
[representers]
|
||||||
|
[gestures]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Angular built-ins
|
||||||
|
|
||||||
|
Several extension categories in the presentation layer map directly
|
||||||
|
to primitives from AngularJS:
|
||||||
|
|
||||||
|
* [_Controllers_](https://docs.angularjs.org/guide/controller) provide
|
||||||
|
data to templates, and expose functionality that can be called from
|
||||||
|
templates.
|
||||||
|
* [_Directives_](https://docs.angularjs.org/guide/directive) effectively
|
||||||
|
extend HTML to provide custom behavior associated with specific
|
||||||
|
attributes and tags.
|
||||||
|
* [_Routes_](https://docs.angularjs.org/api/ngRoute/service/$route#example)
|
||||||
|
are used to associate specific URLs (including the fragment identifier)
|
||||||
|
with specific application states. (In Open MCT, these are used to
|
||||||
|
describe the mode of usage - e.g. browse or edit - as well as to
|
||||||
|
identify the object being used.)
|
||||||
|
* [_Templates_](https://docs.angularjs.org/guide/templates) are partial
|
||||||
|
HTML documents that will be rendered and kept up-to-date by AngularJS.
|
||||||
|
Open MCT introduces a custom `mct-include` directive which acts
|
||||||
|
as a wrapper around `ng-include` to allow templates to be referred
|
||||||
|
to by symbolic names.
|
||||||
|
|
||||||
|
## Domain object representation
|
||||||
|
|
||||||
|
The remaining extension categories in the presentation layer are specific
|
||||||
|
to displaying domain objects.
|
||||||
|
|
||||||
|
* _Representations_ are templates that will be used to display
|
||||||
|
domain objects in specific ways (e.g. "as a tree node.")
|
||||||
|
* _Views_ are representations which are exposed to the user as options
|
||||||
|
for displaying domain objects.
|
||||||
|
* _Representers_ are extensions which modify or augment the process
|
||||||
|
of representing domain objects generally (e.g. by attaching
|
||||||
|
gestures to them.)
|
||||||
|
* _Gestures_ provide associations between specific user actions
|
||||||
|
(expressed as DOM events) and resulting behavior upon domain objects
|
||||||
|
(typically expressed as members of the `actions` extension category)
|
||||||
|
that can be reused across domain objects. For instance, `drag` and
|
||||||
|
`drop` are both gestures associated with using drag-and-drop to
|
||||||
|
modify the composition of domain objects by interacting with their
|
||||||
|
representations.
|
||||||
|
|
||||||
|
# Information Model
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: right
|
||||||
|
[Information Model|
|
||||||
|
[DomainObject|
|
||||||
|
getId() : string
|
||||||
|
getModel() : object
|
||||||
|
getCapability(key : string) : Capability
|
||||||
|
hasCapability(key : string) : boolean
|
||||||
|
useCapability(key : string, args...) : *
|
||||||
|
]
|
||||||
|
[DomainObject] 1 +- 1 [Model]
|
||||||
|
[DomainObject] 1 o- * [Capability]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Domain objects are the most fundamental component of Open MCT's
|
||||||
|
information model. A domain object is some distinct thing relevant to a
|
||||||
|
user's work flow, such as a telemetry channel, display, or similar.
|
||||||
|
Open MCT is a tool for viewing, browsing, manipulating, and otherwise
|
||||||
|
interacting with a graph of domain objects.
|
||||||
|
|
||||||
|
A domain object should be conceived of as the union of the following:
|
||||||
|
|
||||||
|
* _Identifier_: A machine-readable string that uniquely identifies the
|
||||||
|
domain object within this application instance.
|
||||||
|
* _Model_: The persistent state of the domain object. A domain object's
|
||||||
|
model is a JavaScript object that can be losslessly converted to JSON.
|
||||||
|
* _Capabilities_: Dynamic behavior associated with the domain object.
|
||||||
|
Capabilities are JavaScript objects which provide additional methods
|
||||||
|
for interacting with the domain objects which expose those capabilities.
|
||||||
|
Not all domain objects expose all capabilities. The interface exposed
|
||||||
|
by any given capability will depend on its type (as identified
|
||||||
|
by the `key` argument.) For instance, a `persistence` capability
|
||||||
|
has a different interface from a `telemetry` capability. Using
|
||||||
|
capabilities requires some prior knowledge of their interface.
|
||||||
|
|
||||||
|
## Capabilities and Services
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: right
|
||||||
|
[DomainObject]o-[FooCapability]
|
||||||
|
[FooCapability]o-[FooService]
|
||||||
|
[FooService]o-[foos]
|
||||||
|
```
|
||||||
|
|
||||||
|
At run-time, the user is primarily concerned with interacting with
|
||||||
|
domain objects. These interactions are ultimately supported via back-end
|
||||||
|
services, but to allow customization per-object, these are often mediated
|
||||||
|
by capabilities.
|
||||||
|
|
||||||
|
A common pattern that emerges in the Open MCT Platform is as follows:
|
||||||
|
|
||||||
|
* A `DomainObject` has some particular behavior that will be supported
|
||||||
|
by a service.
|
||||||
|
* A `Capability` of that domain object will define that behavior,
|
||||||
|
_for that domain object_, supported by a service.
|
||||||
|
* A `Service` utilized by that capability will perform the actual behavior.
|
||||||
|
* An extension category will be utilized by that capability to determine
|
||||||
|
the set of possible behaviors.
|
||||||
|
|
||||||
|
Concrete examples of capabilities which follow this pattern
|
||||||
|
(or a subset of this pattern) include:
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: right
|
||||||
|
[DomainObject]1 o- *[Capability]
|
||||||
|
[Capability]<:--[TypeCapability]
|
||||||
|
[Capability]<:--[ActionCapability]
|
||||||
|
[Capability]<:--[PersistenceCapability]
|
||||||
|
[Capability]<:--[TelemetryCapability]
|
||||||
|
[TypeCapability]o-[TypeService]
|
||||||
|
[TypeService]o-[types]
|
||||||
|
[ActionCapability]o-[ActionService]
|
||||||
|
[ActionService]o-[actions]
|
||||||
|
[PersistenceCapability]o-[PersistenceService]
|
||||||
|
[TelemetryCapability]o-[TelemetryService]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Service Infrastructure
|
||||||
|
|
||||||
|
Most services exposed by the Open MCT platform follow the
|
||||||
|
[composite services](Framework.md#composite-services) to permit
|
||||||
|
a higher degree of flexibility in how a service can be modified
|
||||||
|
or customized for specific applications.
|
||||||
|
|
||||||
|
To simplify usage for plugin developers, the platform also usually
|
||||||
|
includes a provider implementation for these service type that consumes
|
||||||
|
some extension category. For instance, an `ActionService` provider is
|
||||||
|
included which depends upon extension category `actions`, and exposes
|
||||||
|
all actions declared as such to the system. As such, plugin developers
|
||||||
|
can simply implement the new actions they wish to be made available without
|
||||||
|
worrying about the details of composite services or implementing a new
|
||||||
|
`ActionService` provider; however, the ability to implement a new provider
|
||||||
|
remains useful when the expressive power of individual extensions is
|
||||||
|
insufficient.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[ Service Infrastructure |
|
||||||
|
[ObjectService]->[ModelService]
|
||||||
|
[ModelService]->[PersistenceService]
|
||||||
|
[ObjectService]->[CapabilityService]
|
||||||
|
[CapabilityService]->[capabilities]
|
||||||
|
[capabilities]->[TelemetryService]
|
||||||
|
[capabilities]->[PersistenceService]
|
||||||
|
[capabilities]->[TypeService]
|
||||||
|
[capabilities]->[ActionService]
|
||||||
|
[capabilities]->[ViewService]
|
||||||
|
[PersistenceService]->[<database> Document store]
|
||||||
|
[TelemetryService]->[<database> Telemetry source]
|
||||||
|
[ActionService]->[actions]
|
||||||
|
[ActionService]->[PolicyService]
|
||||||
|
[ViewService]->[PolicyService]
|
||||||
|
[ViewService]->[views]
|
||||||
|
[PolicyService]->[policies]
|
||||||
|
[TypeService]->[types]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
A short summary of the roles of these services:
|
||||||
|
|
||||||
|
* _[ObjectService](#object-service)_: Allows retrieval of domain objects by
|
||||||
|
their identifiers; in practice, often the main point of entry into the
|
||||||
|
[information model](#information-model).
|
||||||
|
* _[ModelService](#model-service)_: Provides domain object models, retrieved
|
||||||
|
by their identifier.
|
||||||
|
* _[CapabilityService](#capability-service)_: Provides capabilities, as they
|
||||||
|
apply to specific domain objects (as judged from their model.)
|
||||||
|
* _[TelemetryService](#telemetry-service)_: Provides access to historical
|
||||||
|
and real-time telemetry data.
|
||||||
|
* _[PersistenceService](#persistence-service)_: Provides the ability to
|
||||||
|
store and retrieve documents (such as domain object models.)
|
||||||
|
* _[ActionService](#action-service)_: Provides distinct user actions that
|
||||||
|
can take place within the system (typically, upon or using domain objects.)
|
||||||
|
* _[ViewService](#view-service)_: Provides views for domain objects. A view
|
||||||
|
is a user-selectable representation of a domain object (in practice, an
|
||||||
|
HTML template.)
|
||||||
|
* _[PolicyService](#policy-service)_: Handles decisions about which
|
||||||
|
behavior are allowed within certain specific contexts.
|
||||||
|
* _[TypeService](#type-service)_: Provides information to distinguish
|
||||||
|
different types of domain objects from one another within the system.
|
||||||
|
|
||||||
|
## Object Service
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: right
|
||||||
|
[<abstract> ObjectService|
|
||||||
|
getObjects(ids : Array.<string>) : Promise.<object.<string, DomainObject>>
|
||||||
|
]
|
||||||
|
[DomainObjectProvider]--:>[ObjectService]
|
||||||
|
[DomainObjectProvider]o-[ModelService]
|
||||||
|
[DomainObjectProvider]o-[CapabilityService]
|
||||||
|
```
|
||||||
|
|
||||||
|
As domain objects are central to Open MCT's information model,
|
||||||
|
acquiring domain objects is equally important.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: right
|
||||||
|
[<start> Start]->[<state> Look up models]
|
||||||
|
[<state> Look up models]->[<state> Look up capabilities]
|
||||||
|
[<state> Look up capabilities]->[<state> Instantiate DomainObject]
|
||||||
|
[<state> Instantiate DomainObject]->[<end> End]
|
||||||
|
```
|
||||||
|
|
||||||
|
Open MCT includes an implementation of an `ObjectService` which
|
||||||
|
satisfies this capability by:
|
||||||
|
|
||||||
|
* Consulting the [Model Service](#model-service) to acquire domain object
|
||||||
|
models by identifier.
|
||||||
|
* Passing these models to a [Capability Service](#capability-service) to
|
||||||
|
determine which capabilities are applicable.
|
||||||
|
* Combining these results together as [DomainObject](#information-model)
|
||||||
|
instances.
|
||||||
|
|
||||||
|
## Model Service
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: down
|
||||||
|
[<abstract> ModelService|
|
||||||
|
getModels(ids : Array.<string>) : Promise.<object.<string, object>>
|
||||||
|
]
|
||||||
|
[StaticModelProvider]--:>[ModelService]
|
||||||
|
[RootModelProvider]--:>[ModelService]
|
||||||
|
[PersistedModelProvider]--:>[ModelService]
|
||||||
|
[ModelAggregator]--:>[ModelService]
|
||||||
|
[CachingModelDecorator]--:>[ModelService]
|
||||||
|
[MissingModelDecorator]--:>[ModelService]
|
||||||
|
|
||||||
|
[MissingModelDecorator]o-[CachingModelDecorator]
|
||||||
|
[CachingModelDecorator]o-[ModelAggregator]
|
||||||
|
[ModelAggregator]o-[StaticModelProvider]
|
||||||
|
[ModelAggregator]o-[RootModelProvider]
|
||||||
|
[ModelAggregator]o-[PersistedModelProvider]
|
||||||
|
|
||||||
|
[PersistedModelProvider]o-[PersistenceService]
|
||||||
|
[RootModelProvider]o-[roots]
|
||||||
|
[StaticModelProvider]o-[models]
|
||||||
|
```
|
||||||
|
|
||||||
|
The platform's model service is responsible for providing domain object
|
||||||
|
models (effectively, JSON documents describing the persistent state
|
||||||
|
associated with domain objects.) These are retrieved by identifier.
|
||||||
|
|
||||||
|
The platform includes multiple components of this variety:
|
||||||
|
|
||||||
|
* `PersistedModelProvider` looks up domain object models from
|
||||||
|
a persistence store (the [`PersistenceService`](#persistence-service));
|
||||||
|
this is how user-created and user-modified
|
||||||
|
domain object models are retrieved.
|
||||||
|
* `RootModelProvider` provides domain object models that have been
|
||||||
|
declared via the `roots` extension category. These will appear at the
|
||||||
|
top level of the tree hierarchy in the user interface.
|
||||||
|
* `StaticModelProvider` provides domain object models that have been
|
||||||
|
declared via the `models` extension category. This is useful for
|
||||||
|
allowing plugins to expose new domain objects declaratively.
|
||||||
|
* `ModelAggregator` merges together the results from multiple providers.
|
||||||
|
If multiple providers return models for the same domain object,
|
||||||
|
the most recently modified version (as determined by the `modified`
|
||||||
|
property of the model) is chosen.
|
||||||
|
* `CachingModelDecorator` caches model instances in memory. This
|
||||||
|
ensures that only a single instance of a domain object model is
|
||||||
|
present at any given time within the application, and prevent
|
||||||
|
redundant retrievals.
|
||||||
|
* `MissingModelDecorator` adds in placeholders when no providers
|
||||||
|
have returned domain object models for a specific identifier. This
|
||||||
|
allows the user to easily see that something was expected to be
|
||||||
|
present, but wasn't.
|
||||||
|
|
||||||
|
## Capability Service
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: down
|
||||||
|
[<abstract> CapabilityService|
|
||||||
|
getCapabilities(model : object) : object.<string, Function>
|
||||||
|
]
|
||||||
|
[CoreCapabilityProvider]--:>[CapabilityService]
|
||||||
|
[QueuingPersistenceCapabilityDecorator]--:>[CapabilityService]
|
||||||
|
|
||||||
|
[CoreCapabilityProvider]o-[capabilities]
|
||||||
|
[QueuingPersistenceCapabilityDecorator]o-[CoreCapabilityProvider]
|
||||||
|
```
|
||||||
|
|
||||||
|
The capability service is responsible for determining which capabilities
|
||||||
|
are applicable for a given domain object, based on its model. Primarily,
|
||||||
|
this is handled by the `CoreCapabilityProvider`, which examines
|
||||||
|
capabilities exposed via the `capabilities` extension category.
|
||||||
|
|
||||||
|
Additionally, `platform/persistence/queue` decorates the persistence
|
||||||
|
capability specifically to batch persistence attempts among multiple
|
||||||
|
objects (this allows failures to be recognized and handled in groups.)
|
||||||
|
|
||||||
|
## Telemetry Service
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[<abstract> TelemetryService|
|
||||||
|
requestData(requests : Array.<TelemetryRequest>) : Promise.<object>
|
||||||
|
subscribe(requests : Array.<TelemetryRequest>) : Function
|
||||||
|
]<--:[TelemetryAggregator]
|
||||||
|
```
|
||||||
|
|
||||||
|
The telemetry service is responsible for acquiring telemetry data.
|
||||||
|
|
||||||
|
Notably, the platform does not include any providers for
|
||||||
|
`TelemetryService`; applications built on Open MCT will need to
|
||||||
|
implement a provider for this service if they wish to expose telemetry
|
||||||
|
data. This is usually the most important step for integrating Open MCT
|
||||||
|
into an existing telemetry system.
|
||||||
|
|
||||||
|
Requests for telemetry data are usually initiated in the
|
||||||
|
[presentation layer](#presentation-layer) by some `Controller` referenced
|
||||||
|
from a view. The `telemetryHandler` service is most commonly used (although
|
||||||
|
one could also use an object's `telemetry` capability directly) as this
|
||||||
|
handles capability delegation, by which a domain object such as a Telemetry
|
||||||
|
Panel can declare that its `telemetry` capability should be handled by the
|
||||||
|
objects it contains. Ultimately, the request for historical data and the
|
||||||
|
new subscriptions will reach the `TelemetryService`, and, by way of the
|
||||||
|
provider(s) which are present for that `TelemetryService`, will pass the
|
||||||
|
same requests to the back-end.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[<start> Start]->[Controller]
|
||||||
|
[Controller]->[<state> declares object of interest]
|
||||||
|
[declares object of interest]->[TelemetryHandler]
|
||||||
|
[TelemetryHandler]->[<state> requests telemetry from capabilities]
|
||||||
|
[TelemetryHandler]->[<state> subscribes to telemetry using capabilities]
|
||||||
|
[requests telemetry from capabilities]->[TelemetryCapability]
|
||||||
|
[subscribes to telemetry using capabilities]->[TelemetryCapability]
|
||||||
|
[TelemetryCapability]->[<state> requests telemetry]
|
||||||
|
[TelemetryCapability]->[<state> subscribes to telemetry]
|
||||||
|
[requests telemetry]->[TelemetryService]
|
||||||
|
[subscribes to telemetry]->[TelemetryService]
|
||||||
|
[TelemetryService]->[<state> issues request]
|
||||||
|
[TelemetryService]->[<state> updates subscriptions]
|
||||||
|
[TelemetryService]->[<state> listens for real-time data]
|
||||||
|
[issues request]->[<database> Telemetry Back-end]
|
||||||
|
[updates subscriptions]->[Telemetry Back-end]
|
||||||
|
[listens for real-time data]->[Telemetry Back-end]
|
||||||
|
[Telemetry Back-end]->[<end> End]
|
||||||
|
```
|
||||||
|
|
||||||
|
The back-end, in turn, is expected to provide whatever historical
|
||||||
|
telemetry is available to satisfy the request that has been issue.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[<start> Start]->[<database> Telemetry Back-end]
|
||||||
|
[Telemetry Back-end]->[<state> transmits historical telemetry]
|
||||||
|
[transmits historical telemetry]->[TelemetryService]
|
||||||
|
[TelemetryService]->[<state> packages telemetry, fulfills requests]
|
||||||
|
[packages telemetry, fulfills requests]->[TelemetryCapability]
|
||||||
|
[TelemetryCapability]->[<state> unpacks telemetry per-object, fulfills request]
|
||||||
|
[unpacks telemetry per-object, fulfills request]->[TelemetryHandler]
|
||||||
|
[TelemetryHandler]->[<state> exposes data]
|
||||||
|
[TelemetryHandler]->[<state> notifies controller]
|
||||||
|
[exposes data]->[Controller]
|
||||||
|
[notifies controller]->[Controller]
|
||||||
|
[Controller]->[<state> prepares data for template]
|
||||||
|
[prepares data for template]->[Template]
|
||||||
|
[Template]->[<state> displays data]
|
||||||
|
[displays data]->[<end> End]
|
||||||
|
```
|
||||||
|
|
||||||
|
One peculiarity of this approach is that we package many responses
|
||||||
|
together at once in the `TelemetryService`, then unpack these in the
|
||||||
|
`TelemetryCapability`, then repackage these in the `TelemetryHandler`.
|
||||||
|
The rationale for this is as follows:
|
||||||
|
|
||||||
|
* In the `TelemetryService`, we want to have the ability to combine
|
||||||
|
multiple requests into one call to the back-end, as many back-ends
|
||||||
|
will support this. It follows that we give the response as a single
|
||||||
|
object, packages in a manner that allows responses to individual
|
||||||
|
requests to be easily identified.
|
||||||
|
* In the `TelemetryCapability`, we want to provide telemetry for a
|
||||||
|
_single object_, so the telemetry data gets unpacked. This allows
|
||||||
|
for the unpacking of data to be handled in a single place, and
|
||||||
|
also permits a flexible substitution method; domain objects may have
|
||||||
|
implementations of the `telemetry` capability that do not use the
|
||||||
|
`TelemetryService` at all, while still maintaining compatibility
|
||||||
|
with any presentation layer code written to utilize this capability.
|
||||||
|
(This is true of capabilities generally.)
|
||||||
|
* In the `TelemetryHandler`, we want to group multiple responses back
|
||||||
|
together again to make it easy for the presentation layer to consume.
|
||||||
|
In this case, the grouping is different from what may have occurred
|
||||||
|
in the `TelemetryService`; this grouping is based on what is expected
|
||||||
|
to be useful _in a specific view_. The `TelemetryService`
|
||||||
|
may be receiving requests from multiple views.
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[<start> Start]->[<database> Telemetry Back-end]
|
||||||
|
[Telemetry Back-end]->[<state> notifies client of new data]
|
||||||
|
[notifies client of new data]->[TelemetryService]
|
||||||
|
[TelemetryService]->[<choice> relevant subscribers?]
|
||||||
|
[relevant subscribers?] yes ->[<state> notify subscribers]
|
||||||
|
[relevant subscribers?] no ->[<state> ignore]
|
||||||
|
[ignore]->[<end> Ignored]
|
||||||
|
[notify subscribers]->[TelemetryCapability]
|
||||||
|
[TelemetryCapability]->[<state> notify listener]
|
||||||
|
[notify listener]->[TelemetryHandler]
|
||||||
|
[TelemetryHandler]->[<state> exposes data]
|
||||||
|
[TelemetryHandler]->[<state> notifies controller]
|
||||||
|
[exposes data]->[Controller]
|
||||||
|
[notifies controller]->[Controller]
|
||||||
|
[Controller]->[<state> prepares data for template]
|
||||||
|
[prepares data for template]->[Template]
|
||||||
|
[Template]->[<state> displays data]
|
||||||
|
[displays data]->[<end> End]
|
||||||
|
```
|
||||||
|
|
||||||
|
The flow of real-time data is similar, and is handled by a sequence
|
||||||
|
of callbacks between the presentation layer component which is
|
||||||
|
interested in data and the telemetry service. Providers in the
|
||||||
|
telemetry service listen to the back-end for new data (via whatever
|
||||||
|
mechanism their specific back-end supports), package this data in
|
||||||
|
the same manner as historical data, and pass that to the callbacks
|
||||||
|
which are associated with relevant requests.
|
||||||
|
|
||||||
|
## Persistence Service
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#direction: right
|
||||||
|
[<abstract> PersistenceService|
|
||||||
|
listSpaces() : Promise.<Array.<string>>
|
||||||
|
listObjects() : Promise.<Array.<string>>
|
||||||
|
createObject(space : string, key : string, document : object) : Promise.<boolean>
|
||||||
|
readObject(space : string, key : string, document : object) : Promise.<object>
|
||||||
|
updateObject(space : string, key : string, document : object) : Promise.<boolean>
|
||||||
|
deleteObject(space : string, key : string, document : object) : Promise.<boolean>
|
||||||
|
]
|
||||||
|
|
||||||
|
[ElasticPersistenceProvider]--:>[PersistenceService]
|
||||||
|
[ElasticPersistenceProvider]->[<database> ElasticSearch]
|
||||||
|
|
||||||
|
[CouchPersistenceProvider]--:>[PersistenceService]
|
||||||
|
[CouchPersistenceProvider]->[<database> CouchDB]
|
||||||
|
```
|
||||||
|
|
||||||
|
Closely related to the notion of domain objects models is their
|
||||||
|
persistence. The `PersistenceService` allows these to be saved
|
||||||
|
and loaded. (Currently, this capability is only used for domain
|
||||||
|
object models, but the interface has been designed without this idea
|
||||||
|
in mind; other kinds of documents could be saved and loaded in the
|
||||||
|
same manner.)
|
||||||
|
|
||||||
|
There is no single definitive implementation of a `PersistenceService` in
|
||||||
|
the platform. Optional adapters are provided to store and load documents
|
||||||
|
from CouchDB and ElasticSearch, respectively; plugin authors may also
|
||||||
|
write additional adapters to utilize different back end technologies.
|
||||||
|
|
||||||
|
## Action Service
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[ActionService|
|
||||||
|
getActions(context : ActionContext) : Array.<Action>
|
||||||
|
]
|
||||||
|
[ActionProvider]--:>[ActionService]
|
||||||
|
[CreateActionProvider]--:>[ActionService]
|
||||||
|
[ActionAggregator]--:>[ActionService]
|
||||||
|
[LoggingActionDecorator]--:>[ActionService]
|
||||||
|
[PolicyActionDecorator]--:>[ActionService]
|
||||||
|
|
||||||
|
[LoggingActionDecorator]o-[PolicyActionDecorator]
|
||||||
|
[PolicyActionDecorator]o-[ActionAggregator]
|
||||||
|
[ActionAggregator]o-[ActionProvider]
|
||||||
|
[ActionAggregator]o-[CreateActionProvider]
|
||||||
|
|
||||||
|
[ActionProvider]o-[actions]
|
||||||
|
[CreateActionProvider]o-[TypeService]
|
||||||
|
[PolicyActionDecorator]o-[PolicyService]
|
||||||
|
```
|
||||||
|
|
||||||
|
Actions are discrete tasks or behaviors that can be initiated by a user
|
||||||
|
upon or using a domain object. Actions may appear as menu items or
|
||||||
|
buttons in the user interface, or may be triggered by certain gestures.
|
||||||
|
|
||||||
|
Responsibilities of platform components of the action service are as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
* `ActionProvider` exposes actions registered via extension category
|
||||||
|
`actions`, supporting simple addition of new actions. Actions are
|
||||||
|
filtered down to match action contexts based on criteria defined as
|
||||||
|
part of an action's extension definition.
|
||||||
|
* `CreateActionProvider` provides the various Create actions which
|
||||||
|
populate the Create menu. These are driven by the available types,
|
||||||
|
so do not map easily to extension category `actions`; instead, these
|
||||||
|
are generated after looking up which actions are available from the
|
||||||
|
[`TypeService`](#type-service).
|
||||||
|
* `ActionAggregator` merges together actions from multiple providers.
|
||||||
|
* `PolicyActionDecorator` enforces the `action` policy category by
|
||||||
|
filtering out actions which violate this policy, as determined by
|
||||||
|
consulting the [`PolicyService`](#policy-service).
|
||||||
|
* `LoggingActionDecorator` wraps exposed actions and writes to the
|
||||||
|
console when they are performed.
|
||||||
|
|
||||||
|
## View Service
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[ViewService|
|
||||||
|
getViews(domainObject : DomainObject) : Array.<View>
|
||||||
|
]
|
||||||
|
[ViewProvider]--:>[ViewService]
|
||||||
|
[PolicyViewDecorator]--:>[ViewService]
|
||||||
|
|
||||||
|
[ViewProvider]o-[views]
|
||||||
|
[PolicyViewDecorator]o-[ViewProvider]
|
||||||
|
```
|
||||||
|
|
||||||
|
The view service provides views that are relevant to a specified domain
|
||||||
|
object. A "view" is a user-selectable visualization of a domain object.
|
||||||
|
|
||||||
|
The responsibilities of components of the view service are as follows:
|
||||||
|
|
||||||
|
* `ViewProvider` exposes views registered via extension category
|
||||||
|
`views`, supporting simple addition of new views. Views are
|
||||||
|
filtered down to match domain objects based on criteria defined as
|
||||||
|
part of a view's extension definition.
|
||||||
|
* `PolicyViewDecorator` enforces the `view` policy category by
|
||||||
|
filtering out views which violate this policy, as determined by
|
||||||
|
consulting the [`PolicyService`](#policy-service).
|
||||||
|
|
||||||
|
## Policy Service
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[PolicyService|
|
||||||
|
allow(category : string, candidate : object, context : object, callback? : Function) : boolean
|
||||||
|
]
|
||||||
|
[PolicyProvider]--:>[PolicyService]
|
||||||
|
[PolicyProvider]o-[policies]
|
||||||
|
```
|
||||||
|
|
||||||
|
The policy service provides a general-purpose extensible decision-making
|
||||||
|
mechanism; plugins can add new extensions of category `policies` to
|
||||||
|
modify decisions of a known category.
|
||||||
|
|
||||||
|
Often, the policy service is referenced from a decorator for another
|
||||||
|
service, to filter down the results of using that service based on some
|
||||||
|
appropriate policy category.
|
||||||
|
|
||||||
|
The policy provider works by looking up all registered policy extensions
|
||||||
|
which are relevant to a particular _category_, then consulting each in
|
||||||
|
order to see if they allow a particular _candidate_ in a particular
|
||||||
|
_context_; the types for the `candidate` and `context` arguments will
|
||||||
|
vary depending on the `category`. Any one policy may disallow the
|
||||||
|
decision as a whole.
|
||||||
|
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[<start> Start]->[<state> is something allowed?]
|
||||||
|
[is something allowed?]->[PolicyService]
|
||||||
|
[PolicyService]->[<state> look up relevant policies by category]
|
||||||
|
[look up relevant policies by category]->[<state> consult policy #1]
|
||||||
|
[consult policy #1]->[Policy #1]
|
||||||
|
[Policy #1]->[<choice> policy #1 allows?]
|
||||||
|
[policy #1 allows?] no ->[<state> decision disallowed]
|
||||||
|
[policy #1 allows?] yes ->[<state> consult policy #2]
|
||||||
|
[consult policy #2]->[Policy #2]
|
||||||
|
[Policy #2]->[<choice> policy #2 allows?]
|
||||||
|
[policy #2 allows?] no ->[<state> decision disallowed]
|
||||||
|
[policy #2 allows?] yes ->[<state> consult policy #3]
|
||||||
|
[consult policy #3]->[<state> ...]
|
||||||
|
[...]->[<state> consult policy #n]
|
||||||
|
[consult policy #n]->[Policy #n]
|
||||||
|
[Policy #n]->[<choice> policy #n allows?]
|
||||||
|
[policy #n allows?] no ->[<state> decision disallowed]
|
||||||
|
[policy #n allows?] yes ->[<state> decision allowed]
|
||||||
|
[decision disallowed]->[<end> Disallowed]
|
||||||
|
[decision allowed]->[<end> Allowed]
|
||||||
|
```
|
||||||
|
|
||||||
|
The policy decision is effectively an "and" operation over the individual
|
||||||
|
policy decisions: That is, all policies must agree to allow a particular
|
||||||
|
policy decision, and the first policy to disallow a decision will cause
|
||||||
|
the entire decision to be disallowed. As a consequence of this, policies
|
||||||
|
should generally be written with a default behavior of "allow", and
|
||||||
|
should only disallow the specific circumstances they are intended to
|
||||||
|
disallow.
|
||||||
|
|
||||||
|
## Type Service
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[TypeService|
|
||||||
|
listTypes() : Array.<Type>
|
||||||
|
getType(key : string) : Type
|
||||||
|
]
|
||||||
|
[TypeProvider]--:>[TypeService]
|
||||||
|
[TypeProvider]o-[types]
|
||||||
|
```
|
||||||
|
|
||||||
|
The type service provides metadata about the different types of domain
|
||||||
|
objects that exist within an Open MCT application. The platform
|
||||||
|
implementation reads these types in from extension category `types`
|
||||||
|
and wraps them in a JavaScript interface.
|
3
docs/src/design/index.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Design proposals:
|
||||||
|
|
||||||
|
* [API Redesign](proposals/APIRedesign.md)
|
338
docs/src/design/planning/APIRefactor.md
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
# API Refactoring
|
||||||
|
|
||||||
|
This document summarizes a path toward implementing API changes
|
||||||
|
from the [API Redesign](../proposals/APIRedesign.md) for Open MCT
|
||||||
|
v1.0.0.
|
||||||
|
|
||||||
|
# Goals
|
||||||
|
|
||||||
|
These plans are intended to minimize:
|
||||||
|
|
||||||
|
* Waste; avoid allocating effort to temporary changes.
|
||||||
|
* Downtime; avoid making changes in large increments that blocks
|
||||||
|
delivery of new features for substantial periods of time.
|
||||||
|
* Risk; ensure that changes can be validated quickly, avoid putting
|
||||||
|
large effort into changes that have not been validated.
|
||||||
|
|
||||||
|
# Plan
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
#comment: This diagram is in nomnoml syntax and should be rendered.
|
||||||
|
#comment: See https://github.com/nasa/openmctweb/issues/264#issuecomment-167166471
|
||||||
|
|
||||||
|
|
||||||
|
[<start> Start]->[<state> Imperative bundle registration]
|
||||||
|
|
||||||
|
[<state> Imperative bundle registration]->[<state> Build and packaging]
|
||||||
|
[<state> Imperative bundle registration]->[<state> Refactor API]
|
||||||
|
|
||||||
|
[<state> Build and packaging |
|
||||||
|
[<start> Start]->[<state> Incorporate a build step]
|
||||||
|
[<state> Incorporate a build step |
|
||||||
|
[<start> Start]->[<state> Choose package manager]
|
||||||
|
[<start> Start]->[<state> Choose build system]
|
||||||
|
[<state> Choose build system]<->[<state> Choose package manager]
|
||||||
|
[<state> Choose package manager]->[<state> Implement]
|
||||||
|
[<state> Choose build system]->[<state> Implement]
|
||||||
|
[<state> Implement]->[<end> End]
|
||||||
|
]->[<state> Separate repositories]
|
||||||
|
[<state> Separate repositories]->[<end> End]
|
||||||
|
]->[<state> Release candidacy]
|
||||||
|
|
||||||
|
|
||||||
|
[<start> Start]->[<state> Design registration API]
|
||||||
|
|
||||||
|
[<state> Design registration API |
|
||||||
|
[<start> Start]->[<state> Decide on role of Angular]
|
||||||
|
[<state> Decide on role of Angular]->[<state> Design API]
|
||||||
|
[<state> Design API]->[<choice> Passes review?]
|
||||||
|
[<choice> Passes review?] no ->[<state> Design API]
|
||||||
|
[<choice> Passes review?]-> yes [<end> End]
|
||||||
|
]->[<state> Refactor API]
|
||||||
|
|
||||||
|
[<state> Refactor API |
|
||||||
|
[<start> Start]->[<state> Imperative extension registration]
|
||||||
|
[<state> Imperative extension registration]->[<state> Refactor individual extensions]
|
||||||
|
|
||||||
|
[<state> Refactor individual extensions |
|
||||||
|
[<start> Start]->[<state> Prioritize]
|
||||||
|
[<state> Prioritize]->[<choice> Sufficient value added?]
|
||||||
|
[<choice> Sufficient value added?] no ->[<end> End]
|
||||||
|
[<choice> Sufficient value added?] yes ->[<state> Design]
|
||||||
|
[<state> Design]->[<choice> Passes review?]
|
||||||
|
[<choice> Passes review?] no ->[<state> Design]
|
||||||
|
[<choice> Passes review?]-> yes [<state> Implement]
|
||||||
|
[<state> Implement]->[<end> End]
|
||||||
|
]->[<state> Remove legacy bundle support]
|
||||||
|
|
||||||
|
[<state> Remove legacy bundle support]->[<end> End]
|
||||||
|
]->[<state> Release candidacy]
|
||||||
|
|
||||||
|
[<state> Release candidacy |
|
||||||
|
[<start> Start]->[<state> Verify |
|
||||||
|
[<start> Start]->[<choice> API well-documented?]
|
||||||
|
[<start> Start]->[<choice> API well-tested?]
|
||||||
|
[<choice> API well-documented?]-> no [<state> Write documentation]
|
||||||
|
[<choice> API well-documented?] yes ->[<end> End]
|
||||||
|
[<state> Write documentation]->[<choice> API well-documented?]
|
||||||
|
[<choice> API well-tested?]-> no [<state> Write test cases]
|
||||||
|
[<choice> API well-tested?]-> yes [<end> End]
|
||||||
|
[<state> Write test cases]->[<choice> API well-tested?]
|
||||||
|
]
|
||||||
|
[<start> Start]->[<state> Validate |
|
||||||
|
[<start> Start]->[<choice> Passes review?]
|
||||||
|
[<start> Start]->[<state> Use internally]
|
||||||
|
[<state> Use internally]->[<choice> Proves useful?]
|
||||||
|
[<choice> Passes review?]-> no [<state> Address feedback]
|
||||||
|
[<state> Address feedback]->[<choice> Passes review?]
|
||||||
|
[<choice> Passes review?] yes -> [<end> End]
|
||||||
|
[<choice> Proves useful?] yes -> [<end> End]
|
||||||
|
[<choice> Proves useful?] no -> [<state> Fix problems]
|
||||||
|
[<state> Fix problems]->[<state> Use internally]
|
||||||
|
]
|
||||||
|
[<state> Validate]->[<end> End]
|
||||||
|
[<state> Verify]->[<end> End]
|
||||||
|
]->[<state> Release]
|
||||||
|
|
||||||
|
[<state> Release]->[<end> End]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 1. Imperative bundle registration
|
||||||
|
|
||||||
|
Register whole bundles imperatively, using their current format.
|
||||||
|
|
||||||
|
For example, in each bundle add a `bundle.js` file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
define([
|
||||||
|
'mctRegistry',
|
||||||
|
'json!bundle.json'
|
||||||
|
], function (mctRegistry, bundle) {
|
||||||
|
mctRegistry.install(bundle, "path/to/bundle");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `mctRegistry.install` is placeholder API that wires into the
|
||||||
|
existing bundle registration mechanisms. The main point of entry
|
||||||
|
would need to be adapted to clearly depend on these bundles
|
||||||
|
(in the require sense of a dependency), and the framework layer
|
||||||
|
would need to implement and integrate with this transitional
|
||||||
|
API.
|
||||||
|
|
||||||
|
Benefits:
|
||||||
|
|
||||||
|
* Achieves an API Redesign goal with minimal immediate effort.
|
||||||
|
* Conversion to an imperative syntax may be trivially automated.
|
||||||
|
* Minimal change; reuse existing bundle definitions, primarily.
|
||||||
|
* Allows early validation of switch to imperative; unforeseen
|
||||||
|
consequences of the change may be detected at this point.
|
||||||
|
* Allows implementation effort to progress in parallel with decisions
|
||||||
|
about API changes, including fundamental ones such as the role of
|
||||||
|
Angular. May act in some sense as a prototype to inform those
|
||||||
|
decisions.
|
||||||
|
* Creates a location (framework layer) where subsequent changes to
|
||||||
|
the manner in which extensions are registered may be centralized.
|
||||||
|
When there is a one-to-one correspondence between the existing
|
||||||
|
form of an extension and its post-refactor form, adapters can be
|
||||||
|
written here to defer the task of making changes ubiquitously
|
||||||
|
throughout bundles, allowing for earlier validation and
|
||||||
|
verification of those changes, and avoiding ubiquitous changes
|
||||||
|
which might require us to go dark. (Mitigates
|
||||||
|
["greenfield paradox"](http://stepaheadsoftware.blogspot.com/2012/09/greenfield-or-refactor-legacy-code-base.html);
|
||||||
|
want to add value with new API but don't want to discard value
|
||||||
|
of tested/proven legacy codebase.)
|
||||||
|
|
||||||
|
Detriments:
|
||||||
|
|
||||||
|
* Requires transitional API to be implemented/supported; this is
|
||||||
|
waste. May mitigate this by time-bounding the effort put into
|
||||||
|
this step to ensure that waste is minimal.
|
||||||
|
|
||||||
|
Note that API changes at this point do not meaningfully reflect
|
||||||
|
the desired 1.0.0 API, so no API reviews are necessary.
|
||||||
|
|
||||||
|
## Step 2. Incorporate a build step
|
||||||
|
|
||||||
|
After the previous step is completed, there should be a
|
||||||
|
straightforward dependency graph among AMD modules, and an
|
||||||
|
imperative (albeit transitional) API allowing for other plugins
|
||||||
|
to register themselves. This should allow for a build step to
|
||||||
|
be included in a straightforward fashion.
|
||||||
|
|
||||||
|
Some goals for this build step:
|
||||||
|
|
||||||
|
* Compile (and, preferably, optimize/minify) Open MCT
|
||||||
|
sources into a single `.js` file.
|
||||||
|
* It is desirable to do the same for HTML sources, but
|
||||||
|
may wish to defer this until a subsequent refactoring
|
||||||
|
step if appropriate.
|
||||||
|
* Provide non-code assets in a format that can be reused by
|
||||||
|
derivative projects in a straightforward fashion.
|
||||||
|
|
||||||
|
Should also consider which dependency/packaging manager should
|
||||||
|
be used by dependent projects to obtain Open MCT. Approaches
|
||||||
|
include:
|
||||||
|
|
||||||
|
1. Plain `npm`. Dependents then declare their dependency with
|
||||||
|
`npm` and utilize built sources and assets in a documented
|
||||||
|
fashion. (Note that there are
|
||||||
|
[documented challenges](http://blog.npmjs.org/post/101775448305/npm-and-front-end-packaging)
|
||||||
|
in using `npm` in this fashion.)
|
||||||
|
2. Build with `npm`, but recommend dependents install using
|
||||||
|
`bower`, as this is intended for front-end development. This may
|
||||||
|
require checking in built products, however, which
|
||||||
|
we wish to avoid (this could be solved by maintaining
|
||||||
|
a separate repository for built products.)
|
||||||
|
|
||||||
|
In all cases, there is a related question of which build system
|
||||||
|
to use for asset generation/management and compilation/minification/etc.
|
||||||
|
|
||||||
|
1. [`webpack`](https://webpack.github.io/)
|
||||||
|
is well-suited in principle, as it is specifically
|
||||||
|
designed for modules with non-JS dependencies. However,
|
||||||
|
there may be limitations and/or undesired behavior here
|
||||||
|
(for instance, CSS dependencies get in-lined as style tags,
|
||||||
|
removing our ability to control ordering) so it may
|
||||||
|
2. `gulp` or `grunt`. Commonplace, but both still require
|
||||||
|
non-trivial coding and/or configuration in order to produce
|
||||||
|
appropriate build artifacts.
|
||||||
|
3. [Just `npm`](http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/).
|
||||||
|
Reduces the amount of tooling being used, but may introduce
|
||||||
|
some complexity (e.g. custom scripts) to the build process,
|
||||||
|
and may reduce portability.
|
||||||
|
|
||||||
|
## Step 3. Separate repositories
|
||||||
|
|
||||||
|
Refactor existing applications built on Open MCT such that they
|
||||||
|
are no longer forks, but instead separate projects with a dependency
|
||||||
|
on the built artifacts from Step 2.
|
||||||
|
|
||||||
|
Note that this is achievable already using `bower` (see `warp-bower`
|
||||||
|
branch at http://developer.nasa.gov/mct/warp for an example.)
|
||||||
|
However, changes involved in switching to an imperative API and
|
||||||
|
introducing a build process may change (and should simplify) the
|
||||||
|
approach used to utilize Open MCT as a dependency, so these
|
||||||
|
changes should be introduced first.
|
||||||
|
|
||||||
|
## Step 4. Design registration API
|
||||||
|
|
||||||
|
Design the registration API that will replace declarative extension
|
||||||
|
categories and extensions (including Angular built-ins and composite
|
||||||
|
services.)
|
||||||
|
|
||||||
|
This may occur in parallel with implementation steps.
|
||||||
|
|
||||||
|
It will be necessary
|
||||||
|
to have a decision about the role of Angular at this point; are extensions
|
||||||
|
registered via provider configuration (Angular), or directly in some
|
||||||
|
exposed registry?
|
||||||
|
|
||||||
|
Success criteria here should be based on peer review. Scope of peer
|
||||||
|
review should be based on perceived risk/uncertainty surrounding
|
||||||
|
proposed changes, to avoid waste; may wish to limit this review to
|
||||||
|
the internal team. (The extent to which external
|
||||||
|
feedback is available is limited, but there is an inherent timeliness
|
||||||
|
to external review; need to balance this.)
|
||||||
|
|
||||||
|
Benefits:
|
||||||
|
|
||||||
|
* Solves the "general case" early, allowing for early validation.
|
||||||
|
|
||||||
|
Note that in specific cases, it may be desirable to refactor some
|
||||||
|
current "extension category" in a manner that will not appear as
|
||||||
|
registries, _or_ to locate these in different
|
||||||
|
namespaces, _or_ to remove/replace certain categories entirely.
|
||||||
|
This work is deferred intentionally to allow for a solution of the
|
||||||
|
general case.
|
||||||
|
|
||||||
|
## Step 5. Imperative extension registration
|
||||||
|
|
||||||
|
Register individual extensions imperatively, implementing API changes
|
||||||
|
from the previous step. At this stage, _usage_ of the API may be confined
|
||||||
|
to a transitional adapter in the framework layer; bundles may continue
|
||||||
|
to utilize the transitional API for registering extensions in the
|
||||||
|
legacy format.
|
||||||
|
|
||||||
|
An important, ongoing sub-task here will be to discover and define dependencies
|
||||||
|
among bundles. Composite services and extension categories are presently
|
||||||
|
"implicit"; after the API redesign, these will become "explicit", insofar
|
||||||
|
as some specific component will be responsible for creating any registries.
|
||||||
|
As such, "bundles" which _use_ specific registries will need to have an
|
||||||
|
enforceable dependency (e.g. require) upon those "bundles" which
|
||||||
|
_declare_ those registries.
|
||||||
|
|
||||||
|
## Step 6. Refactor individual extensions
|
||||||
|
|
||||||
|
Refactor individual extension categories and/or services that have
|
||||||
|
been identified as needing changes. This includes, but is not
|
||||||
|
necessarily limited to:
|
||||||
|
|
||||||
|
* Views/Representations/Templates (refactored into "components.")
|
||||||
|
* Capabilities (refactored into "roles", potentially.)
|
||||||
|
* Telemetry (from `TelemetrySeries` to `TelemetryService`.)
|
||||||
|
|
||||||
|
Changes should be made one category at a time (either serially
|
||||||
|
or separately in parallel) and should involve a tight cycle of:
|
||||||
|
|
||||||
|
1. Prioritization/reprioritization; highest-value API improvements
|
||||||
|
should be done first.
|
||||||
|
2. Design.
|
||||||
|
3. Review. Refactoring individual extensions will require significant
|
||||||
|
effort (likely the most significant effort in the process) so changes
|
||||||
|
should be validated early to minimize risk/waste.
|
||||||
|
4. Implementation. These changes will not have a one-to-one relationship
|
||||||
|
with existing extensions, so changes cannot be centralized; usages
|
||||||
|
will need to be updated across all "bundles" instead of centralized
|
||||||
|
in a legacy adapter. If changes are of sufficient complexity, some
|
||||||
|
planning should be done to spread out the changes incrementally.
|
||||||
|
|
||||||
|
By necessity, these changes may break functionality in applications
|
||||||
|
built using Open MCT. On a case-by-case basis, should consider
|
||||||
|
providing temporary "legacy support" to allow downstream updates
|
||||||
|
to occur as a separate task; the relevant trade here is between
|
||||||
|
waste/effort required to maintain legacy support, versus the
|
||||||
|
downtime which may be introduced by making these changes simultaneously
|
||||||
|
across several repositories.
|
||||||
|
|
||||||
|
|
||||||
|
## Step 7. Remove legacy bundle support
|
||||||
|
|
||||||
|
Update bundles to remove any usages of legacy support for bundles
|
||||||
|
(including that used by dependent projects.) Then, remove legacy
|
||||||
|
support from Open MCT.
|
||||||
|
|
||||||
|
## Step 8. Release candidacy
|
||||||
|
|
||||||
|
Once API changes are complete, Open MCT should enter a release
|
||||||
|
candidacy cycle. Important things to look at here:
|
||||||
|
|
||||||
|
* Are changes really complete?
|
||||||
|
* Are they sufficiently documented?
|
||||||
|
* Are they sufficiently tested?
|
||||||
|
* Are changes really sufficient?
|
||||||
|
* Do reviewers think they are usable?
|
||||||
|
* Does the development team find them useful in practice? This
|
||||||
|
will require calendar time to ascertain; should allocate time
|
||||||
|
for this, particularly in alignment with the sprint/release
|
||||||
|
cycle.
|
||||||
|
* Has learning curve been measurably decreased? Comparing a to-do
|
||||||
|
list tutorial to [other examples(http://todomvc.com/) could
|
||||||
|
provide an empirical basis to this. How much code is required?
|
||||||
|
How much explanation is required? How many dependencies must
|
||||||
|
be installed before initial setup?
|
||||||
|
* Does the API offer sufficient power to implement the extensions we
|
||||||
|
anticipate?
|
||||||
|
* Any open API-related issues which should block a 1.0.0 release?
|
||||||
|
|
||||||
|
Any problems identified during release candidacy will require
|
||||||
|
subsequent design changes and planning.
|
||||||
|
|
||||||
|
## Step 9. Release
|
||||||
|
|
||||||
|
Once API changes have been verified and validated, proceed
|
||||||
|
with release, including:
|
||||||
|
|
||||||
|
* Tagging as version 1.0.0 (at an appropriate time in the
|
||||||
|
sprint/release cycle.)
|
||||||
|
* Close any open issues which have been resolved (or made obsolete)
|
||||||
|
by API changes.
|
1282
docs/src/design/proposals/APIRedesign.md
Normal file
251
docs/src/design/proposals/APIRedesign_PeteRichards.md
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
|
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
|
||||||
|
|
||||||
|
- [Reducing interface depth (the bundle.json version)](#reducing-interface-depth-the-bundlejson-version)
|
||||||
|
- [Imperitive component registries](#imperative-component-registries)
|
||||||
|
- [Get rid of "extension category" concept.](#get-rid-of-extension-category-concept)
|
||||||
|
- [Reduce number and depth of extension points](#reduce-number-and-depth-of-extension-points)
|
||||||
|
- [Composite services should not be the default](#composite-services-should-not-be-the-default)
|
||||||
|
- [Get rid of views, representations, and templates.](#get-rid-of-views-representations-and-templates)
|
||||||
|
- [Reducing interface depth (The angular discussion)](#reducing-interface-depth-the-angular-discussion)
|
||||||
|
- [More angular: for all services](#more-angular-for-all-services)
|
||||||
|
- [Less angular: only for views](#less-angular-only-for-views)
|
||||||
|
- [Standard packaging and build system](#standard-packaging-and-build-system)
|
||||||
|
- [Use systemjs for module loading](#use-systemjs-for-module-loading)
|
||||||
|
- [Use gulp or grunt for standard tooling](#use-gulp-or-grunt-for-standard-tooling)
|
||||||
|
- [Package openmctweb as single versioned file.](#package-openmctweb-as-single-versioned-file)
|
||||||
|
- [Misc Improvements](#misc-improvements)
|
||||||
|
- [Refresh on navigation](#refresh-on-navigation)
|
||||||
|
- [Move persistence adapter to promise rejection.](#move-persistence-adapter-to-promise-rejection)
|
||||||
|
- [Remove bulk requests from providers](#remove-bulk-requests-from-providers)
|
||||||
|
- [Notes on current API proposals:](#notes-on-current-api-proposals)
|
||||||
|
- [[1] Footnote: The angular debacle](#1-footnote-the-angular-debacle)
|
||||||
|
- ["Do or do not, there is no try"](#do-or-do-not-there-is-no-try)
|
||||||
|
- [A lack of commitment](#a-lack-of-commitment)
|
||||||
|
- [Commitment is good!](#commitment-is-good)
|
||||||
|
|
||||||
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
|
|
||||||
|
# Reducing interface depth (the bundle.json version)
|
||||||
|
|
||||||
|
## Imperative component registries
|
||||||
|
|
||||||
|
Transition component registries to javascript, get rid of bundle.json and bundles.json. Prescribe a method for application configuration, but allow flexibility in how application configuration is defined.
|
||||||
|
|
||||||
|
Register components in an imperative fashion, see angularApp.factory, angularApp.controller, etc. Alternatively, implement our own application object with new registries and it's own form of registering objects.
|
||||||
|
|
||||||
|
## Get rid of "extension category" concept.
|
||||||
|
|
||||||
|
The concept of an "extension category" is itself an extraneous concept-- an extra layer of interface depth, an extra thing to learn before you can say "hello world". Extension points should be clearly supported and documented with whatever interfaces make sense. Developers who wish to add something that is conceptually equivalent to an extension category can do so directly, in the manner that suites their needs, without us forcing a common method on them.
|
||||||
|
|
||||||
|
## Reduce number and depth of extension points
|
||||||
|
|
||||||
|
Clearly specify supported extension points (e.g. persistence, model providers, telemetry providers, routes, time systems), but don't claim that the system has a clear and perfect repeatable solution for unknown extension types. New extension categories can be implemented in whatever way makes sense, without prescribing "the one and only system for managing extensions".
|
||||||
|
|
||||||
|
The underlying problem here is we are predicting needs for extension points where none exist-- if we try and design the extension system before we know how it is used, we design the wrong thing and have to rewrite it later.
|
||||||
|
|
||||||
|
## Composite services should not be the default
|
||||||
|
|
||||||
|
Understanding composite services, and describing services as composite services can confuse developers. Aggregators are implemented once and forgotten, while decorators tend to be hacky, brittle solutions that are generally needed to avoid circular imports. While composite services are a useful construct, it reduces interface depth to implement them as registries + typed providers.
|
||||||
|
|
||||||
|
You can write a provider (provides "thing x" for "inputs y") with a simple interface. A provider has two or more methods:
|
||||||
|
* a method which takes "inputs y" and returns True if it knows how to provide "thing x", false otherwise.
|
||||||
|
* one or more methods which provide "thing x" for objects of "inputs y".
|
||||||
|
|
||||||
|
Actually checking whether a provider can respond to a request before asking it to do work allows for faster failure and clearer errors when no providers match the request.
|
||||||
|
|
||||||
|
## Get rid of views, representations, and templates.
|
||||||
|
|
||||||
|
Templates are an implementation detail that should be handled by module loaders. Views and representations become "components," and a new concept, "routes", is used to exposing specific views to end users.
|
||||||
|
|
||||||
|
`components` - building blocks for views, have clear inputs and outputs, and can be coupled to other components when it makes sense. (e.g. parent-child components such as menu and menu item), but should have ZERO knowledge of our data models or telemetry apis. They should define data models that enable them to do their job well while still being easy to test.
|
||||||
|
|
||||||
|
`routes` - a view type for a given domain object, e.g. a plot, table, display layout, etc. Can be described as "whatever shows in the main screen when you are viewing an object." Handle loading of data from a domain object and passing that data to the view components. Routes should support editing as it makes sense in their own context.
|
||||||
|
|
||||||
|
To facilitate testing:
|
||||||
|
|
||||||
|
* routes should be testable without having to test the actual view.
|
||||||
|
* components should be independently testable with zero knowledge of our data models or telemetry APIs.
|
||||||
|
|
||||||
|
Component code should be organized side by side, such as:
|
||||||
|
|
||||||
|
```
|
||||||
|
app
|
||||||
|
|- components
|
||||||
|
|- productDetail
|
||||||
|
| |- productDetail.js
|
||||||
|
| |- productDetail.css
|
||||||
|
| |- productDetail.html
|
||||||
|
| |- productDetailSpec.js
|
||||||
|
|- productList
|
||||||
|
|- checkout
|
||||||
|
|- wishlist
|
||||||
|
```
|
||||||
|
|
||||||
|
Components are not always reusable, and we shouldn't be overly concerned with making them so. If components are heavily reused, they should either be moved to a platform feature (e.g. notifications, indicators), or broken off as an external dependency (e.g. publish mct-plot as mct-plot.js).
|
||||||
|
|
||||||
|
|
||||||
|
# Reducing interface depth (The angular discussion)
|
||||||
|
|
||||||
|
Two options here: use more angular, use less angular. Wrapping angular methods does not reduce interface depth and must be avoided.
|
||||||
|
|
||||||
|
The primary issue with angular is duplications of concerns-- both angular and the openmctweb platform implement the same tools side by side and it can be hard to comprehend-- it increases interface depth. For other concerns, see footnotes[1].
|
||||||
|
|
||||||
|
Wrapping angular methods for non-view related code is confusing to developers because of the random constraints angular places on these items-- developers ultimately have to understand both angular DI and our framework. For example, it's not possible to name the topic service "topicService" because angular expects Services to be implemented by Providers, which is different than our expectation.
|
||||||
|
|
||||||
|
To reduce interface depth, we can replace our own provider and registry patterns with angular patterns, or we can only utilize angular view logic, and only use our own DI patterns.
|
||||||
|
|
||||||
|
## More angular: for all services
|
||||||
|
|
||||||
|
Increasing our commitment to angular would mean using more of the angular factories, services, etc, and less of our home grown tools. We'd implement our services and extension points as angular providers, and make them configurable via app.config.
|
||||||
|
|
||||||
|
As an example, registering a specific type of model provider in angular would look like:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
mct.provider('model', modelProvider() { /* implementation */});
|
||||||
|
|
||||||
|
mct.config(['modelProvider', function (modelProvider) {
|
||||||
|
modelProvider.providers.push(RootModelProvider);
|
||||||
|
}]);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Less angular: only for views
|
||||||
|
|
||||||
|
If we wish to use less angular, I would recommend discontinuing use of all angular components that are not view related-- services, factories, $http, etc, and implementing them in our own paradigm. Otherwise, we end up with layered interfaces-- one of the goals we would like to avoid.
|
||||||
|
|
||||||
|
|
||||||
|
# Standard packaging and build system
|
||||||
|
|
||||||
|
Standardize the packaging and build system, and completely separate the core platform from deployments. Prescribe a starting point for deployments, but allow flexibility.
|
||||||
|
|
||||||
|
## Use systemjs for module loading
|
||||||
|
|
||||||
|
Allow developers to use whatever module loading system they'd like to use, while still supporting all standard cases. We should also use this system for loading assets (css, scss, html templates), which makes it easier to implement a single file deployment using standard build tooling.
|
||||||
|
|
||||||
|
## Use gulp or grunt for standard tooling
|
||||||
|
|
||||||
|
Using gulp or grunt as a task runner would bring us in line with standard web developer workflows and help standardize rendering, deployment, and packaging. Additional tools can be added to the workflow at low cost, simplifying the setup of developer environments.
|
||||||
|
|
||||||
|
Gulp and grunt provide useful developer tooling such as live reload, automatic scss/less/etc compilation, and ease of extensibility for standard production build processes. They're key in decoupling code.
|
||||||
|
|
||||||
|
## Package openmctweb as single versioned file.
|
||||||
|
|
||||||
|
Deployments should depend on a specific version of openmctweb, but otherwise be allowed to have their own deployment and development toolsets.
|
||||||
|
|
||||||
|
Customizations and deployments of openmctweb should not use the same build tooling as the core platform; instead they should be free to use their own build tools as they wish. (We would provide a template for an application, based on our experience with warp-for-rp and vista)
|
||||||
|
|
||||||
|
Installation and utilization of openmctweb should be as simple as downloading the js file, including it in your own html page, and then initializing an app and running it. If a developer would prefer, they could use bower or npm to handle installation.
|
||||||
|
|
||||||
|
Then, if we're using imperative methods for extending the application we can use the following for basic customization:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="//localhost/openmctweb.js"></script>
|
||||||
|
<script>
|
||||||
|
// can configure from object
|
||||||
|
var myApp = new OpenMCTWeb({
|
||||||
|
persitence: {
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
type: 'elastic',
|
||||||
|
uri: 'http://someElasticHost/'
|
||||||
|
} // ...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// alternative configurations
|
||||||
|
myApp.persistence.addProvider(MyPersistenceAdapter);
|
||||||
|
myApp.model.addProvider(someProviderObject);
|
||||||
|
|
||||||
|
// Removing via method
|
||||||
|
myApp.persistence.removeProvider('some method for removing functionality');
|
||||||
|
// directly mutating providers
|
||||||
|
myApp.persistence.providers = [ThisProviderStandsAlone];
|
||||||
|
//
|
||||||
|
myApp.run();
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
This packaging reduces the complexity of managing multiple deployed versions, and also allows us to provide users with incredibly simple tutorials-- they can use whatever tooling they like. For instance, a hello world tutorial may take the option of "exposing a new object in the tree".
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var myApp = new OpenMCTWeb();
|
||||||
|
myApp.roots.addRoot({
|
||||||
|
id: 'myRoot',
|
||||||
|
name: 'Hello World!',
|
||||||
|
});
|
||||||
|
myApp.routes.setDefault('myRoot');
|
||||||
|
myApp.run();
|
||||||
|
```
|
||||||
|
|
||||||
|
# Misc Improvements
|
||||||
|
|
||||||
|
## Refresh on navigation
|
||||||
|
In cases where navigation events change the entire screen, we should be using routes and location changes to navigate between objects. We should be using href for all navigation events.
|
||||||
|
|
||||||
|
At the same time, navigating should refresh state of every visible object. A properly configured persistence store will handle caching with standard cache headers and 304 not modified responses, which will provide good performance of object reloads, while helping us ensure that objects are always in sync between clients.
|
||||||
|
|
||||||
|
View state (say, the expanded tree nodes) should not be tied to caching of data-- it should be something we intentionally persist and restore with each navigation. Data (such as object definitions) should be reloaded from server as necessary to restore state.
|
||||||
|
|
||||||
|
## Move persistence adapter to promise rejection.
|
||||||
|
Simple: reject on fail, resolve on success.
|
||||||
|
|
||||||
|
## Remove bulk requests from providers
|
||||||
|
|
||||||
|
Aggregators can request multiple things at once, but individual providers should only have to implement handling at the level of a single request. Each provider can implement it's own internal batching, but it should support making requests at a finer level of detail.
|
||||||
|
|
||||||
|
Excessive wrapping of code with $q.all causes additional digest cycles and decreased performance.
|
||||||
|
|
||||||
|
For example, instead of every telemetry provider responding to a given telemetry request, aggregators should route each request to the first provider that can fulfill that request.
|
||||||
|
|
||||||
|
|
||||||
|
# Notes on current API proposals:
|
||||||
|
|
||||||
|
* [RequireJS for Dependency Injection](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#requirejs-as-dependency-injector): requires other topics to be discussed first.
|
||||||
|
* [Arbitrary HTML Views](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#arbitrary-html-views): think there is a place for it, requires other topics to be discussed first.
|
||||||
|
* [Wrap Angular Services](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#wrap-angular-services): No, this is bad.
|
||||||
|
* [Bundle definitions in Javascript](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#bundle-declarations-in-javascript): Points to a solution, but ultimately requires more discussion.
|
||||||
|
* [pass around a dependency injector](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#pass-around-a-dependency-injector): No.
|
||||||
|
* [remove partial constructors](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#remove-partial-constructors): Yes, this should be superseded by another proposal though. The entire concept was a messy solution to dependency injection issues caused by declarative syntax.
|
||||||
|
* [Rename views to applications](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#rename-views-to-applications): Points to a problem that needs to be solved but I think the name is bad.
|
||||||
|
* [Provide classes for extensions](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#provide-classes-for-extensions): Yes, in specific places
|
||||||
|
* [Normalize naming conventions](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#normalize-naming-conventions): Yes.
|
||||||
|
* [Expose no third-party APIs](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#expose-no-third-party-apis): Completely disagree, points to a real problem with poor angular integration.
|
||||||
|
* [Register Extensions as Instances instead of Constructors](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#register-extensions-as-instances-instead-of-constructors): Superseded by the fact that we should not hope to implement a generic construct.
|
||||||
|
* [Remove capability delegation](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#remove-capability-delegation): Yes.
|
||||||
|
* [Nomenclature Change](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#nomenclature-change): Yes, hope to discuss the implications of this more clearly in other proposals.
|
||||||
|
* [Capabilities as mixins](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#capabilities-as-mixins): Yes.
|
||||||
|
* [Remove appliesTo methods](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#remove-applies-to-methods): No-- I think some level of this is necessary. I think a more holistic approach to policy is needed. it's a rather complicated system.
|
||||||
|
* [Revise telemetry API](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#revise-telemetry-api): If we can rough out and agree to the specifics, then Yes. Needs discussion.
|
||||||
|
* [Allow composite services to fail gracefully](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#allow-composite-services-to-fail-gracefully): No. As mentioned above, I think composite services themselves should be eliminated for a more purpose bound tool.
|
||||||
|
* [Plugins as angular modules](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#plugins-as-angular-modules): Should we decide to embrace Angular completely, I would support this. Otherwise, no.
|
||||||
|
* [Contextual Injection](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#contextual-injection): No, don't see a need.
|
||||||
|
* [Add New Abstractions for Actions](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#add-new-abstractions-for-actions): Worth a discussion.
|
||||||
|
* [Add gesture handlers](https://github.com/nasa/openmctweb/blob/api-redesign/docs/src/design/proposals/APIRedesign.md#add-gesture-handlers): Yes if we can agree on details. We need a platform implementation that is easy to use, but we should not reinvent the wheel.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [1] Footnote: The angular debacle
|
||||||
|
|
||||||
|
## "Do or do not, there is no try"
|
||||||
|
|
||||||
|
A commonly voiced concern of embracing angular is the possibility of becoming dependent on a third party framework. This concern is itself detrimental-- if we're afraid of becoming dependent on a third party framework, then we will do a bad job of using the framework, and inevitably will want to stop using it.
|
||||||
|
|
||||||
|
If we're using a framework, we need to use it fully, or not use it at all.
|
||||||
|
|
||||||
|
## A lack of commitment
|
||||||
|
|
||||||
|
A number of the concerns we heard from developers and interns can be attributed to the tenuous relationship between the OpenMCTWeb platform and angular. We claimed to be angular, but we weren't really angular. Instead, we are caught between our incomplete framework paradigm and the angular paradigm. In many cases we reinvented the wheel or worked around functionality that angular provides, and ended up in a more confusing state.
|
||||||
|
|
||||||
|
## Commitment is good!
|
||||||
|
|
||||||
|
We could just be an application that is built with angular.
|
||||||
|
|
||||||
|
An application that is modular and extensible not because it reinvents tools for providing modularity and extensibility, but because it reuses existing tools for modularity and extensibility.
|
||||||
|
|
||||||
|
There are benefits to buying into the angular paradigm: shift documentation burden to external project, engage a larger talent pool available both as voluntary open source contributors and as experienced developers for hire, and gain access to an ecosystem of tools that we can use to increase the speed of development.
|
||||||
|
|
||||||
|
There are negatives too: Angular is a monolith, it has performance concerns, and an unclear future. If we can't live with it, we should look at alternatives.
|
||||||
|
|
164
docs/src/design/proposals/ImperativePlugins.md
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
# Imperative Plugins
|
||||||
|
|
||||||
|
This is a design proposal for handling
|
||||||
|
[bundle declarations in JavaScript](
|
||||||
|
APIRedesign.md#bundle-declarations-in-javascript).
|
||||||
|
|
||||||
|
## Developer Use Cases
|
||||||
|
|
||||||
|
Developers will want to use bundles/plugins to (in rough order
|
||||||
|
of occurrence):
|
||||||
|
|
||||||
|
1. Add new extension instances.
|
||||||
|
2. Use existing services
|
||||||
|
3. Add new service implementations.
|
||||||
|
4. Decorate service implementations.
|
||||||
|
5. Decorate extension instances.
|
||||||
|
6. Add new types of services.
|
||||||
|
7. Add new extension categories.
|
||||||
|
|
||||||
|
Notably, bullets 4 and 5 above are currently handled implicitly,
|
||||||
|
which has been cited as a source of confusion.
|
||||||
|
|
||||||
|
## Interfaces
|
||||||
|
|
||||||
|
Two base classes may be used to satisfy these use cases:
|
||||||
|
|
||||||
|
* The `CompositeServiceFactory` provides composite service instances.
|
||||||
|
Decorators may be added; the approach used for compositing may be
|
||||||
|
modified; and individual services may be registered to support compositing.
|
||||||
|
* The `ExtensionRegistry` allows for the simpler case where what is desired
|
||||||
|
is an array of all instances of some kind of thing within the system.
|
||||||
|
|
||||||
|
Note that additional developer use cases may be supported by using the
|
||||||
|
more general-purpose `Registry`
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[Factory.<T, V>
|
||||||
|
|
|
||||||
|
- factoryFn : function (V) : T
|
||||||
|
|
|
||||||
|
+ decorate(decoratorFn : function (T, V) : T, options? : RegistrationOptions)
|
||||||
|
]-:>[function (V) : T]
|
||||||
|
|
||||||
|
[RegistrationOptions |
|
||||||
|
+ priority : number or string
|
||||||
|
]
|
||||||
|
|
||||||
|
[Registry.<T, V>
|
||||||
|
|
|
||||||
|
- compositorFn : function (Array.<T>) : V
|
||||||
|
|
|
||||||
|
+ register(item : T, options? : RegistrationOptions)
|
||||||
|
+ composite(compositorFn : function (Array.<T>) : V, options? : RegistrationOptions)
|
||||||
|
]-:>[Factory.<V, Void>]
|
||||||
|
[Factory.<V, Void>]-:>[Factory.<T, V>]
|
||||||
|
|
||||||
|
[ExtensionRegistry.<T>]-:>[Registry.<T, Array.<T>>]
|
||||||
|
[Registry.<T, Array.<T>>]-:>[Registry.<T, V>]
|
||||||
|
|
||||||
|
[CompositeServiceFactory.<T>]-:>[Registry.<T, T>]
|
||||||
|
[Registry.<T, T>]-:>[Registry.<T, V>]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### 1. Add new extension instances.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Instance-style registration
|
||||||
|
mct.types.register(new mct.Type({
|
||||||
|
key: "timeline",
|
||||||
|
name: "Timeline",
|
||||||
|
description: "A container for activities ordered in time."
|
||||||
|
});
|
||||||
|
|
||||||
|
// Factory-style registration
|
||||||
|
mct.actions.register(function (domainObject) {
|
||||||
|
return new RemoveAction(domainObject);
|
||||||
|
}, { priority: 200 });
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Use existing services
|
||||||
|
|
||||||
|
```js
|
||||||
|
mct.actions.register(function (domainObject) {
|
||||||
|
var dialogService = mct.ui.dialogServiceFactory();
|
||||||
|
return new PropertiesAction(dialogService, domainObject);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Add new service implementations
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Instance-style registration
|
||||||
|
mct.persistenceServiceFactory.register(new LocalPersistenceService());
|
||||||
|
|
||||||
|
// Factory-style registration
|
||||||
|
mct.persistenceServiceFactory.register(function () {
|
||||||
|
var $http = angular.injector(['ng']).get('$http');
|
||||||
|
return new LocalPersistenceService($http);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Decorate service implementations
|
||||||
|
|
||||||
|
```js
|
||||||
|
mct.modelServiceFactory.decorate(function (modelService) {
|
||||||
|
return new CachingModelDecorator(modelService);
|
||||||
|
}, { priority: 100 });
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Decorate extension instances
|
||||||
|
|
||||||
|
```js
|
||||||
|
mct.capabilities.decorate(function (capabilities) {
|
||||||
|
return capabilities.map(decorateIfApplicable);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
This use case is not well-supported by these API changes. The most
|
||||||
|
common case for decoration is capabilities, which are under reconsideration;
|
||||||
|
should consider handling decoration of capabilities in a different way.
|
||||||
|
|
||||||
|
### 6. Add new types of services
|
||||||
|
|
||||||
|
```js
|
||||||
|
myModule.myServiceFactory = new mct.CompositeServiceFactory();
|
||||||
|
|
||||||
|
// In cases where a custom composition strategy is desired
|
||||||
|
myModule.myServiceFactory.composite(function (services) {
|
||||||
|
return new MyServiceCompositor(services);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Add new extension categories.
|
||||||
|
|
||||||
|
```js
|
||||||
|
myModule.hamburgers = new mct.ExtensionRegistry();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Evaluation
|
||||||
|
|
||||||
|
### Benefits
|
||||||
|
|
||||||
|
* Encourages separation of registration from declaration (individual
|
||||||
|
components are decoupled from the manner in which they are added
|
||||||
|
to the architecture.)
|
||||||
|
* Minimizes "magic." Dependencies are acquired, managed, and exposed
|
||||||
|
using plain-old-JavaScript without any dependency injector present
|
||||||
|
to obfuscate what is happening.
|
||||||
|
* Offers comparable expressive power to existing APIs; can still
|
||||||
|
extend the behavior of platform components in a variety of ways.
|
||||||
|
* Does not force or limit formalisms to use;
|
||||||
|
|
||||||
|
### Detriments
|
||||||
|
|
||||||
|
* Does not encourage separation of dependency acquisition from
|
||||||
|
declaration; that is, it would be quite natural using this API
|
||||||
|
to acquire references to services during the constructor call
|
||||||
|
to an extension or service. But, passing these in as constructor
|
||||||
|
arguments is preferred (to separate implementation from architecture.)
|
||||||
|
* Adds (negligible?) boilerplate relative to declarative syntax.
|
||||||
|
* Relies on factories, increasing number of interfaces to be concerned
|
||||||
|
with.
|
138
docs/src/design/proposals/Roles.md
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# Roles
|
||||||
|
|
||||||
|
Roles are presented as an alternative formulation to capabilities
|
||||||
|
(dynamic behavior associated with individual domain objects.)
|
||||||
|
|
||||||
|
Specific goals here:
|
||||||
|
|
||||||
|
* Dependencies of individual scripts should be clear.
|
||||||
|
* Domain objects should be able to selectively exhibit a wide
|
||||||
|
variety of behaviors.
|
||||||
|
|
||||||
|
## Developer Use Cases
|
||||||
|
|
||||||
|
1. Checking for the existence of behavior.
|
||||||
|
2. Using behavior.
|
||||||
|
3. Augmenting existing behaviors.
|
||||||
|
4. Overriding existing behaviors.
|
||||||
|
5. Adding new behaviors.
|
||||||
|
|
||||||
|
## Overview of Proposed Solution
|
||||||
|
|
||||||
|
Remove `getCapability` from domain objects; add roles as external
|
||||||
|
services which can be applied to domain objects.
|
||||||
|
|
||||||
|
## Interfaces
|
||||||
|
|
||||||
|
```nomnoml
|
||||||
|
[Factory.<T, V>
|
||||||
|
|
|
||||||
|
- factoryFn : function (V) : T
|
||||||
|
|
|
||||||
|
+ decorate(decoratorFn : function (T, V) : T, options? : RegistrationOptions)
|
||||||
|
]-:>[function (V) : T]
|
||||||
|
|
||||||
|
[RegistrationOptions |
|
||||||
|
+ priority : number or string
|
||||||
|
]<:-[RoleOptions |
|
||||||
|
+ validate : function (DomainObject) : boolean
|
||||||
|
]
|
||||||
|
|
||||||
|
[Role.<T> |
|
||||||
|
+ validate(domainObject : DomainObject) : boolean
|
||||||
|
+ decorate(decoratorFn : function (T, V) : T, options? : RoleOptions)
|
||||||
|
]-:>[Factory.<T, DomainObject>]
|
||||||
|
[Factory.<T, DomainObject>]-:>[Factory.<T, V>]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### 1. Checking for the existence of behavior
|
||||||
|
|
||||||
|
```js
|
||||||
|
function PlotViewPolicy(telemetryRole) {
|
||||||
|
this.telemetryRole = telemetryRole;
|
||||||
|
}
|
||||||
|
PlotViewPolicy.prototype.allow = function (view, domainObject) {
|
||||||
|
return this.telemetryRole.validate(domainObject);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Using behavior
|
||||||
|
|
||||||
|
```js
|
||||||
|
PropertiesAction.prototype.perform = function () {
|
||||||
|
var mutation = this.mutationRole(this.domainObject);
|
||||||
|
return this.showDialog.then(function (newModel) {
|
||||||
|
return mutation.mutate(function () {
|
||||||
|
return newModel;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Augmenting existing behaviors
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Non-Angular style
|
||||||
|
mct.roles.persistenceRole.decorate(function (persistence) {
|
||||||
|
return new DecoratedPersistence(persistence);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Angular style
|
||||||
|
myModule.decorate('persistenceRole', ['$delegate', function ($delegate) {
|
||||||
|
return new DecoratedPersistence(persistence);
|
||||||
|
}]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Overriding existing behaviors
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Non-Angular style
|
||||||
|
mct.roles.persistenceRole.decorate(function (persistence, domainObject) {
|
||||||
|
return domainObject.getModel().type === 'someType' ?
|
||||||
|
new DifferentPersistence(domainObject) :
|
||||||
|
persistence;
|
||||||
|
}, {
|
||||||
|
validate: function (domainObject, next) {
|
||||||
|
return domainObject.getModel().type === 'someType' || next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Adding new behaviors
|
||||||
|
|
||||||
|
```js
|
||||||
|
function FooRole() {
|
||||||
|
mct.Role.apply(this, [function (domainObject) {
|
||||||
|
return new Foo(domainObject);
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
FooRole.prototype = Object.create(mct.Role.prototype);
|
||||||
|
|
||||||
|
FooRole.prototype.validate = function (domainObject) {
|
||||||
|
return domainObject.getModel().type === 'some-type';
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
myModule.roles.fooRole = new FooRole();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Evaluation
|
||||||
|
|
||||||
|
### Benefits
|
||||||
|
|
||||||
|
* Simplifies/standardizes augmentation or replacement of behavior associated
|
||||||
|
with specific domain objects.
|
||||||
|
* Minimizes number of abstractions; roles are just factories.
|
||||||
|
* Clarifies dependencies; roles used must be declared/acquired in the
|
||||||
|
same manner as services.
|
||||||
|
|
||||||
|
### Detriments
|
||||||
|
|
||||||
|
* Externalizes functionality which is conceptually associated with a
|
||||||
|
domain object.
|
||||||
|
* Relies on factories, increasing number of interfaces to be concerned
|
||||||
|
with.
|
2456
docs/src/guide/index.md
Normal file
@ -22,5 +22,16 @@
|
|||||||
* The [Development Process](process/) document describes the
|
* The [Development Process](process/) document describes the
|
||||||
Open MCT software development cycle.
|
Open MCT software development cycle.
|
||||||
|
|
||||||
* The [Tutorials](https://github.com/nasa/openmct-tutorial) give examples of extending the platform to add
|
## Legacy Documentation
|
||||||
|
|
||||||
|
As we transition to a new API, the following documentation for the old API
|
||||||
|
(which is supported during the transtion) may be useful as well:
|
||||||
|
|
||||||
|
* The [Architecture Overview](architecture/) describes the concepts used
|
||||||
|
throughout Open MCT, and gives a high level overview of the platform's design.
|
||||||
|
|
||||||
|
* The [Developer's Guide](guide/) goes into more detail about how to use the
|
||||||
|
platform and the functionality that it provides.
|
||||||
|
|
||||||
|
* The [Tutorials](tutorials/) give examples of extending the platform to add
|
||||||
functionality, and integrate with data sources.
|
functionality, and integrate with data sources.
|
||||||
|
@ -73,11 +73,11 @@ acceptance testing (e.g. by resolving any blockers found); any
|
|||||||
resources not needed for this effort should be used to begin work
|
resources not needed for this effort should be used to begin work
|
||||||
for the subsequent sprint.
|
for the subsequent sprint.
|
||||||
|
|
||||||
| Week | Mon | Tue | Wed | Thu | Fri |
|
| Week | Mon | Tue | Wed | Thu | Fri |
|
||||||
|:-----:|:-------------------------:|:------:|:---:|:----------------------------:|:-------------------------------------:|
|
|:-----:|:-------------------------:|:------:|:---:|:----------------------------:|:-----------:|
|
||||||
| __1__ | Sprint plan | Tag-up | | | |
|
| __1__ | Sprint plan | Tag-up | | | |
|
||||||
| __2__ | | Tag-up | | | Code freeze and sprint branch |
|
| __2__ | | Tag-up | | | Code freeze |
|
||||||
| __3__ | Per-sprint testing | Triage | | _Per-sprint testing*_ | Ship and merge sprint branch to master|
|
| __3__ | Per-sprint testing | Triage | | _Per-sprint testing*_ | Ship |
|
||||||
|
|
||||||
* If necessary.
|
* If necessary.
|
||||||
|
|
||||||
@ -105,20 +105,14 @@ emphasis on testing.
|
|||||||
that team may begin work for that sprint during the
|
that team may begin work for that sprint during the
|
||||||
third week, since testing and blocker resolution is unlikely
|
third week, since testing and blocker resolution is unlikely
|
||||||
to require all available resources.
|
to require all available resources.
|
||||||
* Testing success criteria identified per issue (where necessary). This could be in the form of acceptance tests on the issue or detailing performance tests, for example.
|
|
||||||
* __Tag-up.__ Check in and status update among development team.
|
* __Tag-up.__ Check in and status update among development team.
|
||||||
May amend plan for sprint as-needed.
|
May amend plan for sprint as-needed.
|
||||||
* __Code freeze.__ Any new work from this sprint
|
* __Code freeze.__ Any new work from this sprint
|
||||||
(features, bug fixes, enhancements) must be integrated by the
|
(features, bug fixes, enhancements) must be integrated by the
|
||||||
end of the second week of the sprint. After code freeze, a sprint
|
end of the second week of the sprint. After code freeze
|
||||||
branch will be created (and until the end of the sprint) the only
|
(and until the end of the sprint) the only changes that should be
|
||||||
changes that should be merged into the sprint branch should
|
merged into the master branch should directly address issues
|
||||||
directly address issues needed to pass acceptance testing.
|
needed to pass acceptance testing.
|
||||||
During this time, any other feature development will continue to
|
|
||||||
be merged into the master branch for the next sprint.
|
|
||||||
* __Sprint branch merge to master.__ After acceptance testing, the sprint branch
|
|
||||||
will be merged back to the master branch. Any code conflicts that
|
|
||||||
arise will be resolved by the team.
|
|
||||||
* [__Per-release Testing.__](testing/plan.md#per-release-testing)
|
* [__Per-release Testing.__](testing/plan.md#per-release-testing)
|
||||||
Structured testing with predefined
|
Structured testing with predefined
|
||||||
success criteria. No release should ship without passing
|
success criteria. No release should ship without passing
|
||||||
@ -132,8 +126,8 @@ emphasis on testing.
|
|||||||
* [__Testathon.__](testing/plan.md#user-testing)
|
* [__Testathon.__](testing/plan.md#user-testing)
|
||||||
Multi-user testing, involving as many users as
|
Multi-user testing, involving as many users as
|
||||||
is feasible, plus development team. Open-ended; should verify
|
is feasible, plus development team. Open-ended; should verify
|
||||||
completed work from this sprint using the sprint branch, test
|
completed work from this sprint, test exploratorily for
|
||||||
exploratorily for regressions, et cetera.
|
regressions, et cetera.
|
||||||
* [__Long-Duration Test.__](testing/plan.md#long-duration-testing) A
|
* [__Long-Duration Test.__](testing/plan.md#long-duration-testing) A
|
||||||
test to verify that the software remains
|
test to verify that the software remains
|
||||||
stable after running for longer durations. May include some
|
stable after running for longer durations. May include some
|
||||||
@ -149,7 +143,7 @@ emphasis on testing.
|
|||||||
Subset of Pre-release Testing
|
Subset of Pre-release Testing
|
||||||
which should be performed before shipping at the end of any
|
which should be performed before shipping at the end of any
|
||||||
sprint. Time is allocated for a second round of
|
sprint. Time is allocated for a second round of
|
||||||
Pre-release Testing if the first round is not passed. Smoke tests collected from issues/PRs
|
Pre-release Testing if the first round is not passed.
|
||||||
* __Triage.__ Team reviews issues from acceptance testing and uses
|
* __Triage.__ Team reviews issues from acceptance testing and uses
|
||||||
success criteria to determine whether or not they should block
|
success criteria to determine whether or not they should block
|
||||||
release, then formulates a plan to address these issues before
|
release, then formulates a plan to address these issues before
|
||||||
|
@ -7,5 +7,9 @@ documents:
|
|||||||
process points are repeated during development.
|
process points are repeated during development.
|
||||||
* The [Version Guide](version.md) describes version numbering for
|
* The [Version Guide](version.md) describes version numbering for
|
||||||
Open MCT (both semantics and process.)
|
Open MCT (both semantics and process.)
|
||||||
* The [Test Plan](testing/plan.md) summarizes the approaches used
|
* Testing is described in two documents:
|
||||||
to test Open MCT.
|
* The [Test Plan](testing/plan.md) summarizes the approaches used
|
||||||
|
to test Open MCT.
|
||||||
|
* The [Test Procedures](testing/procedures.md) document what
|
||||||
|
specific tests are performed to verify correctness, and how
|
||||||
|
they should be carried out.
|
||||||
|
@ -19,7 +19,7 @@ Testing for Open MCT includes:
|
|||||||
|
|
||||||
Manual, non-rigorous testing of the software and/or specific features
|
Manual, non-rigorous testing of the software and/or specific features
|
||||||
of interest. Verifies that the software runs and that basic functionality
|
of interest. Verifies that the software runs and that basic functionality
|
||||||
is present. The outcome of Smoke Testing should be a simplified list of Acceptance Tests which could be executed by another team member with sufficient context.
|
is present.
|
||||||
|
|
||||||
### Unit Testing
|
### Unit Testing
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ User testing will focus on the following activities:
|
|||||||
* General "trying to break things."
|
* General "trying to break things."
|
||||||
|
|
||||||
During user testing, users will
|
During user testing, users will
|
||||||
[report issues](https://github.com/nasa/openmct/issues/new/choose)
|
[report issues](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
|
||||||
as they are encountered.
|
as they are encountered.
|
||||||
|
|
||||||
Desired outcomes of user testing are:
|
Desired outcomes of user testing are:
|
||||||
@ -71,7 +71,7 @@ usage. After twenty-four hours, the software is evaluated for:
|
|||||||
at the start of the test? Is it as responsive?
|
at the start of the test? Is it as responsive?
|
||||||
|
|
||||||
Any defects or unexpected behavior identified during testing should be
|
Any defects or unexpected behavior identified during testing should be
|
||||||
[reported as issues](https://github.com/nasa/openmct/issues/new/choose)
|
[reported as issues](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
|
||||||
and reviewed for severity.
|
and reviewed for severity.
|
||||||
|
|
||||||
## Test Performance
|
## Test Performance
|
||||||
@ -125,22 +125,3 @@ A release is not closed until both categories have been performed on
|
|||||||
the latest snapshot of the software, _and_ no issues labelled as
|
the latest snapshot of the software, _and_ no issues labelled as
|
||||||
["blocker" or "critical"](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
|
["blocker" or "critical"](https://github.com/nasa/openmctweb/blob/master/CONTRIBUTING.md#issue-reporting)
|
||||||
remain open.
|
remain open.
|
||||||
|
|
||||||
### Testathons
|
|
||||||
Testathons can be used as a means of performing per-sprint and per-release testing.
|
|
||||||
|
|
||||||
#### Timing
|
|
||||||
For per-sprint testing, a testathon is typically performed at the beginning of the third week of a sprint, and again later that week to verify any fixes. For per-release testing, a testathon is typically performed prior to any formal testing processes that are applicable to that release.
|
|
||||||
|
|
||||||
#### Process
|
|
||||||
|
|
||||||
1. Prior to the scheduled testathon, a list will be compiled of all issues that are closed and unverified.
|
|
||||||
2. For each issue, testers should review the associated PR for testing instructions. See the contributing guide for instructions on [pull requests](https://github.com/nasa/openmct/blob/master/CONTRIBUTING.md#merging).
|
|
||||||
3. As each issue is verified via testing, any team members testing it should leave a comment on that issue indicating that it has been verified fixed.
|
|
||||||
4. If a bug is found that relates to an issue being tested, notes should be included on the associated issue, and the issue should be reopened. Bug notes should include reproduction steps.
|
|
||||||
5. For any bugs that are not obviously related to any of the issues under test, a new issue should be created with details about the bug, including reproduction steps. If unsure about whether a bug relates to an issue being tested, just create a new issue.
|
|
||||||
6. At the end of the testathon, triage will take place, where all tested issues will be reviewed.
|
|
||||||
7. If verified fixed, an issue will remain closed, and will have the “unverified” label removed.
|
|
||||||
8. For any bugs found, a severity will be assigned.
|
|
||||||
9. A second testathon will be scheduled for later in the week that will aim to address all issues identified as blockers, as well as any other issues scoped by the team during triage.
|
|
||||||
10. Any issues that were not tested will remain "unverified" and will be picked up in the next testathon.
|
|
||||||
|
169
docs/src/process/testing/procedures.md
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
# Test Procedures
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
This document is intended to be used:
|
||||||
|
|
||||||
|
* By testers, to verify that Open MCT behaves as specified.
|
||||||
|
* By the development team, to document new test cases and to provide
|
||||||
|
guidance on how to author these.
|
||||||
|
|
||||||
|
## Writing Procedures
|
||||||
|
|
||||||
|
### Template
|
||||||
|
|
||||||
|
Procedures for individual tests should use the following template,
|
||||||
|
adapted from [https://swehb.nasa.gov/display/7150/SWE-114]().
|
||||||
|
|
||||||
|
Property | Value
|
||||||
|
---------------|---------------------------------------------------------------
|
||||||
|
Test ID |
|
||||||
|
Relevant reqs. |
|
||||||
|
Prerequisites |
|
||||||
|
Test input |
|
||||||
|
Instructions |
|
||||||
|
Expectation |
|
||||||
|
Eval. criteria |
|
||||||
|
|
||||||
|
For multi-line descriptions, use an asterisk or similar indicator to refer
|
||||||
|
to a longer-form description below.
|
||||||
|
|
||||||
|
#### Example Procedure - Edit a Layout
|
||||||
|
|
||||||
|
Property | Value
|
||||||
|
---------------|---------------------------------------------------------------
|
||||||
|
Test ID | MCT-TEST-000X - Edit a layout
|
||||||
|
Relevant reqs. | MCT-EDIT-000Y
|
||||||
|
Prerequisites | Create a layout, as in MCT-TEST-000Z
|
||||||
|
Test input | Domain object database XYZ
|
||||||
|
Instructions | See below *
|
||||||
|
Expectation | Change to editing context †
|
||||||
|
Eval. criteria | Visual inspection
|
||||||
|
|
||||||
|
* Follow the following steps:
|
||||||
|
|
||||||
|
1. Verify that the created layout is currently navigated-to,
|
||||||
|
as in MCT-TEST-00ZZ.
|
||||||
|
2. Click the Edit button, identified by a pencil icon and the text "Edit"
|
||||||
|
displayed on hover.
|
||||||
|
|
||||||
|
† Right-hand viewing area should be surrounded by a dashed
|
||||||
|
blue border when a domain object is being edited.
|
||||||
|
|
||||||
|
### Guidelines
|
||||||
|
|
||||||
|
Test procedures should be written assuming minimal prior knowledge of the
|
||||||
|
application: Non-standard terms should only be used when they are documented
|
||||||
|
in [the glossary](#glossary), and shorthands used for user actions should
|
||||||
|
be accompanied by useful references to test procedures describing those
|
||||||
|
actions (when available) or descriptions in user documentation.
|
||||||
|
|
||||||
|
Test cases should be narrow in scope; if a list of steps is excessively
|
||||||
|
long (or must be written vaguely to be kept short) it should be broken
|
||||||
|
down into multiple tests which reference one another.
|
||||||
|
|
||||||
|
All requirements satisfied by Open MCT should be verifiable using
|
||||||
|
one or more test procedures.
|
||||||
|
|
||||||
|
## Glossary
|
||||||
|
|
||||||
|
This section will contain terms used in test procedures. This may link to
|
||||||
|
a common glossary, to avoid replication of content.
|
||||||
|
|
||||||
|
## Procedures
|
||||||
|
|
||||||
|
This section will contain specific test procedures. Presently, procedures
|
||||||
|
are placeholders describing general patterns for setting up and conducting
|
||||||
|
testing.
|
||||||
|
|
||||||
|
### User Testing Setup
|
||||||
|
|
||||||
|
These procedures describes a general pattern for setting up for user
|
||||||
|
testing. Specific deployments should customize this pattern with
|
||||||
|
relevant data and any additional steps necessary.
|
||||||
|
|
||||||
|
Property | Value
|
||||||
|
---------------|---------------------------------------------------------------
|
||||||
|
Test ID | MCT-TEST-SETUP0 - User Testing Setup
|
||||||
|
Relevant reqs. | TBD
|
||||||
|
Prerequisites | Build of relevant components
|
||||||
|
Test input | Exemplary database; exemplary telemetry data set
|
||||||
|
Instructions | See below
|
||||||
|
Expectation | Able to load application in a web browser (Google Chrome)
|
||||||
|
Eval. criteria | Visual inspection
|
||||||
|
|
||||||
|
Instructions:
|
||||||
|
|
||||||
|
1. Start telemetry server.
|
||||||
|
2. Start ElasticSearch.
|
||||||
|
3. Restore database snapshot to ElasticSearch.
|
||||||
|
4. Start telemetry playback.
|
||||||
|
5. Start HTTP server for client sources.
|
||||||
|
|
||||||
|
### User Test Procedures
|
||||||
|
|
||||||
|
Specific user test cases have not yet been authored. In their absence,
|
||||||
|
user testing is conducted by:
|
||||||
|
|
||||||
|
* Reviewing the text of issues from the issue tracker to understand the
|
||||||
|
desired behavior, and exercising this behavior in the running application.
|
||||||
|
(For instance, by following steps to reproduce from the original issue.)
|
||||||
|
* Issues which appear to be resolved should be marked as such with comments
|
||||||
|
on the original issue (e.g. "verified during user testing MM/DD/YYYY".)
|
||||||
|
* Issues which appear not to have been resolved should be reopened with an
|
||||||
|
explanation of what unexpected behavior has been observed.
|
||||||
|
* In cases where an issue appears resolved as-worded but other related
|
||||||
|
undesirable behavior is observed during testing, a new issue should be
|
||||||
|
opened, and linked to from a comment in the original issues.
|
||||||
|
* General usage of new features and/or existing features which have undergone
|
||||||
|
recent changes. Defects or problems with usability should be documented
|
||||||
|
by filing issues in the issue tracker.
|
||||||
|
* Open-ended testing to discover defects, identify usability issues, and
|
||||||
|
generate feature requests.
|
||||||
|
|
||||||
|
### Long-Duration Testing
|
||||||
|
|
||||||
|
The purpose of long-duration testing is to identify performance issues
|
||||||
|
and/or other defects which are sensitive to the amount of time the
|
||||||
|
application is kept running. (Memory leaks, for instance.)
|
||||||
|
|
||||||
|
Property | Value
|
||||||
|
---------------|---------------------------------------------------------------
|
||||||
|
Test ID | MCT-TEST-LDT0 - Long-duration Testing
|
||||||
|
Relevant reqs. | TBD
|
||||||
|
Prerequisites | MCT-TEST-SETUP0
|
||||||
|
Test input | (As for test setup.)
|
||||||
|
Instructions | See "Instructions" below *
|
||||||
|
Expectation | See "Expectations" below †
|
||||||
|
Eval. criteria | Visual inspection
|
||||||
|
|
||||||
|
* Instructions:
|
||||||
|
|
||||||
|
1. Start `top` or a similar tool to measure CPU usage and memory utilization.
|
||||||
|
2. Open several user-created displays (as many as would be realistically
|
||||||
|
opened during actual usage in a stressing case) in some combination of
|
||||||
|
separate tabs and windows (approximately as many tabs-per-window as
|
||||||
|
total windows.)
|
||||||
|
3. Ensure that playback data is set to run continuously for at least 24 hours
|
||||||
|
(e.g. on a loop.)
|
||||||
|
4. Record CPU usage and memory utilization.
|
||||||
|
5. In at least one tab, try some general user interface gestures and make
|
||||||
|
notes about the subjective experience of using the application. (Particularly,
|
||||||
|
the degree of responsiveness.)
|
||||||
|
6. Leave client displays open for 24 hours.
|
||||||
|
7. Record CPU usage and memory utilization again.
|
||||||
|
8. Make additional notes about the subjective experience of using the
|
||||||
|
application (again, particularly responsiveness.)
|
||||||
|
9. Check logs for any unexpected warnings or errors.
|
||||||
|
|
||||||
|
† Expectations:
|
||||||
|
|
||||||
|
* At the end of the test, CPU usage and memory usage should both be similar
|
||||||
|
to their levels at the start of the test.
|
||||||
|
* At the end of the test, subjective usage of the application should not
|
||||||
|
be observably different from the way it was at the start of the test.
|
||||||
|
(In particular, responsiveness should not decrease.)
|
||||||
|
* Logs should not contain any unexpected warnings or errors ("expected"
|
||||||
|
warnings or errors are those that have been documented and prioritized
|
||||||
|
as known issues, or those that are explained by transient conditions
|
||||||
|
external to the software, such as network outages.)
|
@ -92,60 +92,47 @@ should update (or delegate the task of updating) Open MCT version
|
|||||||
numbers by the following process:
|
numbers by the following process:
|
||||||
|
|
||||||
1. Update version number in `package.json`
|
1. Update version number in `package.json`
|
||||||
1. Checkout branch created for the last sprint that has been successfully tested.
|
1. Remove `-SNAPSHOT` suffix.
|
||||||
2. Remove a `-SNAPSHOT` suffix from the version in `package.json`.
|
2. Verify that resulting version number meets semantic versioning
|
||||||
3. Verify that resulting version number meets semantic versioning
|
requirements relative to previous stable version. Increment if
|
||||||
requirements relative to previous stable version. Increment the
|
necessary.
|
||||||
version number if necessary.
|
3. If version is considered unstable (which may be the case during
|
||||||
4. If version is considered unstable (which may be the case during
|
|
||||||
the first three sprints of a release), apply a new suffix per
|
the first three sprints of a release), apply a new suffix per
|
||||||
[Version Numbering](#version-numbering) guidance above.
|
[Version Numbering](#version-numbering) guidance above.
|
||||||
2. Tag the release.
|
2. Tag the release.
|
||||||
1. Commit changes to `package.json` on the new branch created in
|
1. Commit changes to `package.json` on the `master` branch.
|
||||||
the previous step.
|
|
||||||
The commit message should reference the sprint being closed,
|
The commit message should reference the sprint being closed,
|
||||||
preferably by a URL reference to the associated Milestone in
|
preferably by a URL reference to the associated Milestone in
|
||||||
GitHub.
|
GitHub.
|
||||||
2. Verify that build still completes, that application passes
|
2. Verify that build still completes, that application passes
|
||||||
smoke-testing, and that only differences from tested versions
|
smoke-testing, and that only differences from tested versions
|
||||||
are the changes to version number above.
|
are the changes to version number above.
|
||||||
3. Push the new branch.
|
3. Push the `master` branch.
|
||||||
4. Tag this commit with the version number, prepending the letter "v".
|
4. Tag this commit with the version number, prepending the letter "v".
|
||||||
(e.g. `git tag v0.9.3-alpha`)
|
(e.g. `git tag v0.9.3-alpha`)
|
||||||
5. Push the tag to GitHub. (e.g. `git push origin v0.9.3-alpha`).
|
5. Push the tag to GitHub. (e.g. `git push origin v0.9.3-alpha`).
|
||||||
3. Upload a release archive.
|
3. Upload a release archive.
|
||||||
1. Use the [GitHub release interface](https://github.com/nasa/openmct/releases)
|
1. Run `npm pack` to generate the archive.
|
||||||
|
2. Use the [GitHub release interface](https://github.com/nasa/openmct/releases)
|
||||||
to draft a new release.
|
to draft a new release.
|
||||||
2. Choose the existing tag for the new version (created and pushed above.)
|
3. Choose the existing tag for the new version (created and pushed above.)
|
||||||
Enter the tag name as the release name as well; see existing releases
|
Enter the tag name as the release name as well; see existing releases
|
||||||
for examples. (e.g. `Open MCT v0.9.3-alpha`)
|
for examples.
|
||||||
3. Designate the release as a "pre-release" as appropriate (for instance,
|
4. Attach the release archive.
|
||||||
|
5. Designate the release as a "pre-release" as appropriate (for instance,
|
||||||
when the version number has been suffixed as unstable, or when
|
when the version number has been suffixed as unstable, or when
|
||||||
the version number is below 1.0.0.)
|
the version number is below 1.0.0.)
|
||||||
4. Add release notes including any breaking changes, enhancements,
|
4. Restore snapshot status in `package.json`
|
||||||
bug fixes with solutions in brief.
|
1. Remove any suffix from the version number, or increment the
|
||||||
5. Publish the release.
|
_patch_ version if there is no suffix.
|
||||||
4. Publish the release to npm
|
2. Append a `-SNAPSHOT` suffix.
|
||||||
1. Login to npm
|
3. Commit changes to `package.json` on the `master` branch.
|
||||||
2. Checkout the tag created in the previous step.
|
|
||||||
3. In `package.json` change package to be public (private: false)
|
|
||||||
4. Test the package before publishing by doing `npm publish --dry-run`
|
|
||||||
if necessary.
|
|
||||||
5. Publish the package to the npmjs registry (e.g. `npm publish --access public`)
|
|
||||||
NOTE: Use the `--tag unstable` flag to the npm publishj if this is a prerelease.
|
|
||||||
6. Confirm the package has been published (e.g. `https://www.npmjs.com/package/openmct`)
|
|
||||||
5. Update snapshot status in `package.json`
|
|
||||||
1. Create a new branch off the `master` branch.
|
|
||||||
2. Remove any suffix from the version number,
|
|
||||||
or increment the _patch_ version if there is no suffix.
|
|
||||||
3. Append a `-SNAPSHOT` suffix.
|
|
||||||
4. Commit changes to `package.json` on the `master` branch.
|
|
||||||
The commit message should reference the sprint being opened,
|
The commit message should reference the sprint being opened,
|
||||||
preferably by a URL reference to the associated Milestone in
|
preferably by a URL reference to the associated Milestone in
|
||||||
GitHub.
|
GitHub.
|
||||||
5. Verify that build still completes, that application passes
|
4. Verify that build still completes, that application passes
|
||||||
smoke-testing.
|
smoke-testing.
|
||||||
6. Create a PR to be merged into the `master` branch.
|
5. Push the `master` branch.
|
||||||
|
|
||||||
Projects dependent on Open MCT being co-developed by the Open MCT
|
Projects dependent on Open MCT being co-developed by the Open MCT
|
||||||
team should follow a similar process, except that they should
|
team should follow a similar process, except that they should
|
||||||
|
BIN
docs/src/tutorials/images/add-task.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
docs/src/tutorials/images/bar-plot-2.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
docs/src/tutorials/images/bar-plot-3.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
docs/src/tutorials/images/bar-plot-4.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
docs/src/tutorials/images/bar-plot.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
docs/src/tutorials/images/chrome.png
Normal file
After Width: | Height: | Size: 140 KiB |
BIN
docs/src/tutorials/images/remove-task.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docs/src/tutorials/images/telemetry-1.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
docs/src/tutorials/images/telemetry-2.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
docs/src/tutorials/images/telemetry-3.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
docs/src/tutorials/images/todo-edit.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
docs/src/tutorials/images/todo-list.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
docs/src/tutorials/images/todo-restyled.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
docs/src/tutorials/images/todo-selection.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
docs/src/tutorials/images/todo.png
Normal file
After Width: | Height: | Size: 43 KiB |
3309
docs/src/tutorials/index.md
Normal file
@ -1,4 +0,0 @@
|
|||||||
/* eslint-disable no-undef */
|
|
||||||
module.exports = {
|
|
||||||
"extends": ["plugin:playwright/playwright-test"]
|
|
||||||
};
|
|
@ -1,5 +0,0 @@
|
|||||||
version: 2
|
|
||||||
snapshot:
|
|
||||||
widths: [1024, 2000]
|
|
||||||
min-height: 1440 # px
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
|||||||
/* eslint-disable no-undef */
|
|
||||||
// playwright.config.js
|
|
||||||
// @ts-check
|
|
||||||
|
|
||||||
const { devices } = require('@playwright/test');
|
|
||||||
|
|
||||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
|
||||||
const config = {
|
|
||||||
retries: 2,
|
|
||||||
testDir: 'tests',
|
|
||||||
timeout: 90 * 1000,
|
|
||||||
webServer: {
|
|
||||||
command: 'npm run start',
|
|
||||||
port: 8080,
|
|
||||||
timeout: 200 * 1000,
|
|
||||||
reuseExistingServer: !process.env.CI
|
|
||||||
},
|
|
||||||
workers: 2, //Limit to 2 for CircleCI Agent
|
|
||||||
use: {
|
|
||||||
baseURL: 'http://localhost:8080/',
|
|
||||||
headless: true,
|
|
||||||
ignoreHTTPSErrors: true,
|
|
||||||
screenshot: 'on',
|
|
||||||
trace: 'on',
|
|
||||||
video: 'on'
|
|
||||||
},
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: 'chrome',
|
|
||||||
use: {
|
|
||||||
browserName: 'chromium',
|
|
||||||
...devices['Desktop Chrome']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'MMOC',
|
|
||||||
use: {
|
|
||||||
browserName: 'chromium',
|
|
||||||
viewport: {
|
|
||||||
width: 2560,
|
|
||||||
height: 1440
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*{
|
|
||||||
name: 'ipad',
|
|
||||||
use: {
|
|
||||||
browserName: 'webkit',
|
|
||||||
...devices['iPad (gen 7) landscape'] // Complete List https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/deviceDescriptorsSource.json
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
],
|
|
||||||
reporter: [
|
|
||||||
['list'],
|
|
||||||
['junit', { outputFile: 'test-results/results.xml' }],
|
|
||||||
['allure-playwright'],
|
|
||||||
['github']
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = config;
|
|
@ -1,60 +0,0 @@
|
|||||||
/* eslint-disable no-undef */
|
|
||||||
// playwright.config.js
|
|
||||||
// @ts-check
|
|
||||||
|
|
||||||
const { devices } = require('@playwright/test');
|
|
||||||
|
|
||||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
|
||||||
const config = {
|
|
||||||
retries: 0,
|
|
||||||
testDir: 'tests',
|
|
||||||
timeout: 30 * 1000,
|
|
||||||
webServer: {
|
|
||||||
command: 'npm run start',
|
|
||||||
port: 8080,
|
|
||||||
timeout: 120 * 1000,
|
|
||||||
reuseExistingServer: !process.env.CI
|
|
||||||
},
|
|
||||||
workers: 1,
|
|
||||||
use: {
|
|
||||||
browserName: "chromium",
|
|
||||||
baseURL: 'http://localhost:8080/',
|
|
||||||
headless: false,
|
|
||||||
ignoreHTTPSErrors: true,
|
|
||||||
screenshot: 'on',
|
|
||||||
trace: 'on',
|
|
||||||
video: 'on'
|
|
||||||
},
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: 'chrome',
|
|
||||||
use: {
|
|
||||||
browserName: 'chromium',
|
|
||||||
...devices['Desktop Chrome']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'MMOC',
|
|
||||||
use: {
|
|
||||||
browserName: 'chromium',
|
|
||||||
viewport: {
|
|
||||||
width: 2560,
|
|
||||||
height: 1440
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*{
|
|
||||||
name: 'ipad',
|
|
||||||
use: {
|
|
||||||
browserName: 'webkit',
|
|
||||||
...devices['iPad (gen 7) landscape'] // Complete List https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/deviceDescriptorsSource.json
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
],
|
|
||||||
reporter: [
|
|
||||||
['list'],
|
|
||||||
['allure-playwright']
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = config;
|
|
@ -1,33 +0,0 @@
|
|||||||
/* eslint-disable no-undef */
|
|
||||||
// playwright.config.js
|
|
||||||
// @ts-check
|
|
||||||
|
|
||||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
|
||||||
const config = {
|
|
||||||
retries: 0,
|
|
||||||
testDir: 'tests',
|
|
||||||
timeout: 90 * 1000,
|
|
||||||
workers: 1,
|
|
||||||
webServer: {
|
|
||||||
command: 'npm run start',
|
|
||||||
port: 8080,
|
|
||||||
timeout: 200 * 1000,
|
|
||||||
reuseExistingServer: !process.env.CI
|
|
||||||
},
|
|
||||||
use: {
|
|
||||||
browserName: "chromium",
|
|
||||||
baseURL: 'http://localhost:8080/',
|
|
||||||
headless: true,
|
|
||||||
ignoreHTTPSErrors: true,
|
|
||||||
screenshot: 'on',
|
|
||||||
trace: 'off',
|
|
||||||
video: 'on'
|
|
||||||
},
|
|
||||||
reporter: [
|
|
||||||
['list'],
|
|
||||||
['junit', { outputFile: 'test-results/results.xml' }],
|
|
||||||
['allure-playwright']
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = config;
|
|
@ -1,48 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
This test suite is dedicated to tests which verify the basic operations surrounding conditionSets.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const { test, expect } = require('@playwright/test');
|
|
||||||
|
|
||||||
test.describe('condition set', () => {
|
|
||||||
test('create new button `condition set` creates new condition object', async ({ page }) => {
|
|
||||||
//Go to baseURL
|
|
||||||
await page.goto('/', { waitUntil: 'networkidle' });
|
|
||||||
|
|
||||||
//Click the Create button
|
|
||||||
await page.click('button:has-text("Create")');
|
|
||||||
|
|
||||||
// Click text=Condition Set
|
|
||||||
await page.click('text=Condition Set');
|
|
||||||
|
|
||||||
// Click text=OK
|
|
||||||
await Promise.all([
|
|
||||||
page.waitForNavigation(/*{ url: 'http://localhost:8080/#/browse/mine/dab945d4-5a84-480e-8180-222b4aa730fa?tc.mode=fixed&tc.startBound=1639696164435&tc.endBound=1639697964435&tc.timeSystem=utc&view=conditionSet.view' }*/),
|
|
||||||
page.click('text=OK')
|
|
||||||
]);
|
|
||||||
|
|
||||||
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set');
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,49 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
This test suite is dedicated to tests which can quickly verify that any openmct installation is
|
|
||||||
operable and that any type of testing can proceed.
|
|
||||||
|
|
||||||
Ideally, smoke tests should make zero assumptions about how and where they are run. This makes them
|
|
||||||
more resilient to change and therefor a better indicator of failure. Smoke tests will also run quickly
|
|
||||||
as they cover a very "thin surface" of functionality.
|
|
||||||
|
|
||||||
When deciding between authoring new smoke tests or functional tests, ask yourself "would I feel
|
|
||||||
comfortable running this test during a live mission?" Avoid creating or deleting Domain Objects.
|
|
||||||
Make no assumptions about the order that elements appear in the DOM.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const { test, expect } = require('@playwright/test');
|
|
||||||
|
|
||||||
test('Verify that the create button appears and that the Folder Domain Object is available for selection', async ({ page }) => {
|
|
||||||
|
|
||||||
//Go to baseURL
|
|
||||||
await page.goto('/', { waitUntil: 'networkidle' });
|
|
||||||
|
|
||||||
//Click the Create button
|
|
||||||
await page.click('button:has-text("Create")');
|
|
||||||
|
|
||||||
// Verify that Create Folder appears in the dropdown
|
|
||||||
const locator = page.locator(':nth-match(:text("Folder"), 2)');
|
|
||||||
await expect(locator).toBeEnabled();
|
|
||||||
});
|
|
@ -1,113 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Collection of Visual Tests set to run in a default context. The tests within this suite
|
|
||||||
are only meant to run against openmct's app.js started by `npm run start` within the
|
|
||||||
`./e2e/playwright-visual.config.js` file.
|
|
||||||
|
|
||||||
These should only use functional expect statements to verify assumptions about the state
|
|
||||||
in a test and not for functional verification of correctness. Visual tests are not supposed
|
|
||||||
to "fail" on assertions. Instead, they should be used to detect changes between builds or branches.
|
|
||||||
|
|
||||||
Note: Larger testsuite sizes are OK due to the setup time associated with these tests.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const { test, expect } = require('@playwright/test');
|
|
||||||
const percySnapshot = require('@percy/playwright');
|
|
||||||
const path = require('path');
|
|
||||||
const sinon = require('sinon');
|
|
||||||
|
|
||||||
const VISUAL_GRACE_PERIOD = 5 * 1000; //Lets the application "simmer" before the snapshot is taken
|
|
||||||
|
|
||||||
// Snippet from https://github.com/microsoft/playwright/issues/6347#issuecomment-965887758
|
|
||||||
// Will replace with cy.clock() equivalent
|
|
||||||
test.beforeEach(async ({ context }) => {
|
|
||||||
await context.addInitScript({
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
path: path.join(__dirname, '../../..', './node_modules/sinon/pkg/sinon.js')
|
|
||||||
});
|
|
||||||
await context.addInitScript(() => {
|
|
||||||
window.__clock = sinon.useFakeTimers(); //Set browser clock to UNIX Epoch
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Visual - Root and About', async ({ page }) => {
|
|
||||||
// Go to baseURL
|
|
||||||
await page.goto('/', { waitUntil: 'networkidle' });
|
|
||||||
|
|
||||||
// Verify that Create button is actionable
|
|
||||||
const createButtonLocator = page.locator('button:has-text("Create")');
|
|
||||||
await expect(createButtonLocator).toBeEnabled();
|
|
||||||
|
|
||||||
// Take a snapshot of the Dashboard
|
|
||||||
await page.waitForTimeout(VISUAL_GRACE_PERIOD);
|
|
||||||
await percySnapshot(page, 'Root');
|
|
||||||
|
|
||||||
// Click About button
|
|
||||||
await page.click('.l-shell__app-logo');
|
|
||||||
|
|
||||||
// Modify the Build information in 'about' to be consistent run-over-run
|
|
||||||
const versionInformationLocator = page.locator('ul.t-info.l-info.s-info');
|
|
||||||
await expect(versionInformationLocator).toBeEnabled();
|
|
||||||
await versionInformationLocator.evaluate(node => node.innerHTML = '<li>Version: visual-snapshot</li> <li>Build Date: Mon Nov 15 2021 08:07:51 GMT-0800 (Pacific Standard Time)</li> <li>Revision: 93049cdbc6c047697ca204893db9603b864b8c9f</li> <li>Branch: master</li>');
|
|
||||||
|
|
||||||
// Take a snapshot of the About modal
|
|
||||||
await page.waitForTimeout(VISUAL_GRACE_PERIOD);
|
|
||||||
await percySnapshot(page, 'About');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Visual - Default Condition Set', async ({ page }) => {
|
|
||||||
//Go to baseURL
|
|
||||||
await page.goto('/', { waitUntil: 'networkidle' });
|
|
||||||
|
|
||||||
//Click the Create button
|
|
||||||
await page.click('button:has-text("Create")');
|
|
||||||
|
|
||||||
// Click text=Condition Set
|
|
||||||
await page.click('text=Condition Set');
|
|
||||||
|
|
||||||
// Click text=OK
|
|
||||||
await page.click('text=OK');
|
|
||||||
|
|
||||||
// Take a snapshot of the newly created Condition Set object
|
|
||||||
await page.waitForTimeout(VISUAL_GRACE_PERIOD);
|
|
||||||
await percySnapshot(page, 'Default Condition Set');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Visual - Default Condition Widget', async ({ page }) => {
|
|
||||||
//Go to baseURL
|
|
||||||
await page.goto('/', { waitUntil: 'networkidle' });
|
|
||||||
|
|
||||||
//Click the Create button
|
|
||||||
await page.click('button:has-text("Create")');
|
|
||||||
|
|
||||||
// Click text=Condition Widget
|
|
||||||
await page.click('text=Condition Widget');
|
|
||||||
|
|
||||||
// Click text=OK
|
|
||||||
await page.click('text=OK');
|
|
||||||
|
|
||||||
// Take a snapshot of the newly created Condition Widget object
|
|
||||||
await page.waitForTimeout(VISUAL_GRACE_PERIOD);
|
|
||||||
await percySnapshot(page, 'Default Condition Widget');
|
|
||||||
});
|
|
@ -1,96 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining EventTelemetryProvider. Created by chacskaylo on 06/18/2015.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import messages from './transcript.json';
|
|
||||||
|
|
||||||
class EventTelemetryProvider {
|
|
||||||
constructor() {
|
|
||||||
this.defaultSize = 25;
|
|
||||||
}
|
|
||||||
|
|
||||||
generateData(firstObservedTime, count, startTime, duration, name) {
|
|
||||||
const millisecondsSinceStart = startTime - firstObservedTime;
|
|
||||||
const utc = Math.floor(startTime / duration) * duration;
|
|
||||||
const ind = count % messages.length;
|
|
||||||
const message = messages[ind] + " - [" + millisecondsSinceStart + "]";
|
|
||||||
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
utc,
|
|
||||||
message
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsRequest(domainObject) {
|
|
||||||
return domainObject.type === 'eventGenerator';
|
|
||||||
}
|
|
||||||
|
|
||||||
supportsSubscribe(domainObject) {
|
|
||||||
return domainObject.type === 'eventGenerator';
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe(domainObject, callback) {
|
|
||||||
const duration = domainObject.telemetry.duration * 1000;
|
|
||||||
const firstObservedTime = Date.now();
|
|
||||||
let count = 0;
|
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
const startTime = Date.now();
|
|
||||||
const datum = this.generateData(firstObservedTime, count, startTime, duration, domainObject.name);
|
|
||||||
count += 1;
|
|
||||||
callback(datum);
|
|
||||||
}, duration);
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
clearInterval(interval);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
request(domainObject, options) {
|
|
||||||
let start = options.start;
|
|
||||||
const end = Math.min(Date.now(), options.end); // no future values
|
|
||||||
const duration = domainObject.telemetry.duration * 1000;
|
|
||||||
const size = options.size ? options.size : this.defaultSize;
|
|
||||||
const data = [];
|
|
||||||
const firstObservedTime = Date.now();
|
|
||||||
let count = 0;
|
|
||||||
|
|
||||||
if (options.strategy === 'latest' || options.size === 1) {
|
|
||||||
start = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (start <= end && data.length < size) {
|
|
||||||
const startTime = Date.now() + count;
|
|
||||||
data.push(this.generateData(firstObservedTime, count, startTime, duration, domainObject.name));
|
|
||||||
start += duration;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EventTelemetryProvider;
|
|
80
example/eventGenerator/bundle.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define([
|
||||||
|
"./src/EventTelemetryProvider",
|
||||||
|
'legacyRegistry'
|
||||||
|
], function (
|
||||||
|
EventTelemetryProvider,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
legacyRegistry.register("example/eventGenerator", {
|
||||||
|
"name": "Event Message Generator",
|
||||||
|
"description": "For development use. Creates sample event message data that mimics a live data stream.",
|
||||||
|
"extensions": {
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"implementation": EventTelemetryProvider,
|
||||||
|
"type": "provider",
|
||||||
|
"provides": "telemetryService",
|
||||||
|
"depends": [
|
||||||
|
"$q",
|
||||||
|
"$timeout"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"key": "eventGenerator",
|
||||||
|
"name": "Event Message Generator",
|
||||||
|
"cssClass": "icon-folder-new",
|
||||||
|
"description": "For development use. Creates sample event message data that mimics a live data stream.",
|
||||||
|
"priority": 10,
|
||||||
|
"features": "creation",
|
||||||
|
"model": {
|
||||||
|
"telemetry": {}
|
||||||
|
},
|
||||||
|
"telemetry": {
|
||||||
|
"source": "eventGenerator",
|
||||||
|
"domains": [
|
||||||
|
{
|
||||||
|
"key": "utc",
|
||||||
|
"name": "Timestamp",
|
||||||
|
"format": "utc"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"key": "message",
|
||||||
|
"name": "Message",
|
||||||
|
"format": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -1,69 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
import EventMessageGeneratorPlugin from './plugin.js';
|
|
||||||
import {
|
|
||||||
createOpenMct,
|
|
||||||
resetApplicationState
|
|
||||||
} from '../../src/utils/testing';
|
|
||||||
|
|
||||||
describe('the plugin', () => {
|
|
||||||
let openmct;
|
|
||||||
const mockDomainObject = {
|
|
||||||
identifier: {
|
|
||||||
namespace: '',
|
|
||||||
key: 'some-value'
|
|
||||||
},
|
|
||||||
telemetry: {
|
|
||||||
duration: 0
|
|
||||||
},
|
|
||||||
type: 'eventGenerator'
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach((done) => {
|
|
||||||
const options = {};
|
|
||||||
openmct = createOpenMct();
|
|
||||||
openmct.install(new EventMessageGeneratorPlugin(options));
|
|
||||||
openmct.on('start', done);
|
|
||||||
openmct.startHeadless();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await resetApplicationState(openmct);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('the plugin', () => {
|
|
||||||
it("supports subscription", (done) => {
|
|
||||||
const unsubscribe = openmct.telemetry.subscribe(mockDomainObject, (telemetry) => {
|
|
||||||
expect(telemetry).not.toEqual(null);
|
|
||||||
expect(telemetry.message).toContain('CC: Eagle, Houston');
|
|
||||||
expect(unsubscribe).not.toEqual(null);
|
|
||||||
unsubscribe();
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("supports requests", async () => {
|
|
||||||
const telemetry = await openmct.telemetry.request(mockDomainObject);
|
|
||||||
expect(telemetry[0].message).toContain('CC: Eagle, Houston');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
62
example/eventGenerator/src/EventTelemetry.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining EventTelemetry.
|
||||||
|
* Created by chacskaylo on 06/18/2015.
|
||||||
|
* Modified by shale on 06/23/2015.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
['../data/transcript.json'],
|
||||||
|
function (messages) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var firstObservedTime = Date.now();
|
||||||
|
|
||||||
|
function EventTelemetry(request, interval) {
|
||||||
|
|
||||||
|
var latestObservedTime = Date.now(),
|
||||||
|
count = Math.floor((latestObservedTime - firstObservedTime) / interval),
|
||||||
|
generatorData = {};
|
||||||
|
|
||||||
|
generatorData.getPointCount = function () {
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
generatorData.getDomainValue = function (i, domain) {
|
||||||
|
return i * interval +
|
||||||
|
(domain !== 'delta' ? firstObservedTime : 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
generatorData.getRangeValue = function (i, range) {
|
||||||
|
var domainDelta = this.getDomainValue(i) - firstObservedTime,
|
||||||
|
ind = i % messages.length;
|
||||||
|
return messages[ind] + " - [" + domainDelta.toString() + "]";
|
||||||
|
};
|
||||||
|
|
||||||
|
return generatorData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EventTelemetry;
|
||||||
|
}
|
||||||
|
);
|
121
example/eventGenerator/src/EventTelemetryProvider.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define,Promise*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining EventTelemetryProvider. Created by chacskaylo on 06/18/2015.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
["./EventTelemetry"],
|
||||||
|
function (EventTelemetry) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function EventTelemetryProvider($q, $timeout) {
|
||||||
|
var
|
||||||
|
subscriptions = [],
|
||||||
|
genInterval = 1000,
|
||||||
|
generating = false,
|
||||||
|
id = Math.random() * 100000;
|
||||||
|
|
||||||
|
//
|
||||||
|
function matchesSource(request) {
|
||||||
|
return request.source === "eventGenerator";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used internally; this will be repacked by doPackage
|
||||||
|
function generateData(request) {
|
||||||
|
//console.log("generateData " + (Date.now() - startTime).toString());
|
||||||
|
return {
|
||||||
|
key: request.key,
|
||||||
|
telemetry: new EventTelemetry(request, genInterval)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
function doPackage(results) {
|
||||||
|
var packaged = {};
|
||||||
|
results.forEach(function (result) {
|
||||||
|
packaged[result.key] = result.telemetry;
|
||||||
|
});
|
||||||
|
// Format as expected (sources -> keys -> telemetry)
|
||||||
|
return { eventGenerator: packaged };
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestTelemetry(requests) {
|
||||||
|
return $timeout(function () {
|
||||||
|
return doPackage(requests.filter(matchesSource).map(generateData));
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubscriptions(timeout) {
|
||||||
|
subscriptions.forEach(function (subscription) {
|
||||||
|
var requests = subscription.requests;
|
||||||
|
subscription.callback(doPackage(
|
||||||
|
requests.filter(matchesSource).map(generateData)
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function startGenerating() {
|
||||||
|
generating = true;
|
||||||
|
$timeout(function () {
|
||||||
|
handleSubscriptions();
|
||||||
|
if (generating && subscriptions.length > 0) {
|
||||||
|
startGenerating();
|
||||||
|
} else {
|
||||||
|
generating = false;
|
||||||
|
}
|
||||||
|
}, genInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
function subscribe(callback, requests) {
|
||||||
|
var subscription = {
|
||||||
|
callback: callback,
|
||||||
|
requests: requests
|
||||||
|
};
|
||||||
|
function unsubscribe() {
|
||||||
|
subscriptions = subscriptions.filter(function (s) {
|
||||||
|
return s !== subscription;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
subscriptions.push(subscription);
|
||||||
|
if (!generating) {
|
||||||
|
startGenerating();
|
||||||
|
}
|
||||||
|
|
||||||
|
return unsubscribe;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
requestTelemetry: requestTelemetry,
|
||||||
|
subscribe: subscribe
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return EventTelemetryProvider;
|
||||||
|
}
|
||||||
|
);
|
@ -1,110 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
import EventEmitter from 'EventEmitter';
|
|
||||||
import uuid from 'uuid';
|
|
||||||
import createExampleUser from './exampleUserCreator';
|
|
||||||
|
|
||||||
export default class ExampleUserProvider extends EventEmitter {
|
|
||||||
constructor(openmct) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.openmct = openmct;
|
|
||||||
this.user = undefined;
|
|
||||||
this.loggedIn = false;
|
|
||||||
this.autoLoginUser = undefined;
|
|
||||||
|
|
||||||
this.ExampleUser = createExampleUser(this.openmct.user.User);
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoggedIn() {
|
|
||||||
return this.loggedIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
autoLogin(username) {
|
|
||||||
this.autoLoginUser = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentUser() {
|
|
||||||
if (this.loggedIn) {
|
|
||||||
return Promise.resolve(this.user);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._login().then(() => this.user);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasRole(roleId) {
|
|
||||||
if (!this.loggedIn) {
|
|
||||||
Promise.resolve(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve(this.user.getRoles().includes(roleId));
|
|
||||||
}
|
|
||||||
|
|
||||||
_login() {
|
|
||||||
const id = uuid();
|
|
||||||
|
|
||||||
// for testing purposes, this will skip the form, this wouldn't be used in
|
|
||||||
// a normal authentication process
|
|
||||||
if (this.autoLoginUser) {
|
|
||||||
this.user = new this.ExampleUser(id, this.autoLoginUser, ['example-role']);
|
|
||||||
this.loggedIn = true;
|
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
const formStructure = {
|
|
||||||
title: "Login",
|
|
||||||
sections: [
|
|
||||||
{
|
|
||||||
rows: [
|
|
||||||
{
|
|
||||||
key: "username",
|
|
||||||
control: "textfield",
|
|
||||||
name: "Username",
|
|
||||||
pattern: "\\S+",
|
|
||||||
required: true,
|
|
||||||
cssClass: "l-input-lg",
|
|
||||||
value: ''
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
buttons: {
|
|
||||||
submit: {
|
|
||||||
label: 'Login'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.openmct.forms.showForm(formStructure).then(
|
|
||||||
(info) => {
|
|
||||||
this.user = new this.ExampleUser(id, info.username, ['example-role']);
|
|
||||||
this.loggedIn = true;
|
|
||||||
},
|
|
||||||
() => { // user canceled, setting a default username
|
|
||||||
this.user = new this.ExampleUser(id, 'Pat', ['example-role']);
|
|
||||||
this.loggedIn = true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
89
example/export/ExportTelemetryAsCSVAction.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define([], function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An example of using the `exportService`; queries for telemetry
|
||||||
|
* and provides the results as a CSV file.
|
||||||
|
* @param {platform/exporters.ExportService} exportService the
|
||||||
|
* service which will handle the CSV export
|
||||||
|
* @param {ActionContext} context the action's context
|
||||||
|
* @constructor
|
||||||
|
* @memberof example/export
|
||||||
|
* @implements {Action}
|
||||||
|
*/
|
||||||
|
function ExportTelemetryAsCSVAction(exportService, context) {
|
||||||
|
this.exportService = exportService;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportTelemetryAsCSVAction.prototype.perform = function () {
|
||||||
|
var context = this.context,
|
||||||
|
domainObject = context.domainObject,
|
||||||
|
telemetry = domainObject.getCapability("telemetry"),
|
||||||
|
metadata = telemetry.getMetadata(),
|
||||||
|
domains = metadata.domains,
|
||||||
|
ranges = metadata.ranges,
|
||||||
|
exportService = this.exportService;
|
||||||
|
|
||||||
|
function getName(domainOrRange) {
|
||||||
|
return domainOrRange.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
telemetry.requestData({}).then(function (series) {
|
||||||
|
var headers = domains.map(getName).concat(ranges.map(getName)),
|
||||||
|
rows = [],
|
||||||
|
row,
|
||||||
|
i;
|
||||||
|
|
||||||
|
function copyDomainsToRow(row, index) {
|
||||||
|
domains.forEach(function (domain) {
|
||||||
|
row[domain.name] = series.getDomainValue(index, domain.key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyRangesToRow(row, index) {
|
||||||
|
ranges.forEach(function (range) {
|
||||||
|
row[range.name] = series.getRangeValue(index, range.key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < series.getPointCount(); i += 1) {
|
||||||
|
row = {};
|
||||||
|
copyDomainsToRow(row, i);
|
||||||
|
copyRangesToRow(row, i);
|
||||||
|
rows.push(row);
|
||||||
|
}
|
||||||
|
exportService.exportCSV(rows, { headers: headers });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ExportTelemetryAsCSVAction.appliesTo = function (context) {
|
||||||
|
return context.domainObject &&
|
||||||
|
context.domainObject.hasCapability("telemetry");
|
||||||
|
};
|
||||||
|
|
||||||
|
return ExportTelemetryAsCSVAction;
|
||||||
|
});
|
45
example/export/bundle.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define([
|
||||||
|
'legacyRegistry',
|
||||||
|
'./ExportTelemetryAsCSVAction'
|
||||||
|
], function (legacyRegistry, ExportTelemetryAsCSVAction) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
legacyRegistry.register("example/export", {
|
||||||
|
"name": "Example of using CSV Export",
|
||||||
|
"extensions": {
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"key": "example.export",
|
||||||
|
"name": "Export Telemetry as CSV",
|
||||||
|
"implementation": ExportTelemetryAsCSVAction,
|
||||||
|
"category": "contextual",
|
||||||
|
"cssClass": "icon-download",
|
||||||
|
"depends": [ "exportService" ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -19,27 +19,35 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
import WebPageViewProvider from './WebPageViewProvider.js';
|
define([
|
||||||
|
"./src/ExampleFormController",
|
||||||
|
'legacyRegistry'
|
||||||
|
], function (
|
||||||
|
ExampleFormController,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
export default function plugin() {
|
legacyRegistry.register("example/forms", {
|
||||||
return function install(openmct) {
|
"name": "Declarative Forms example",
|
||||||
openmct.objectViews.addProvider(new WebPageViewProvider(openmct));
|
"sources": "src",
|
||||||
|
"extensions": {
|
||||||
openmct.types.addType('webPage', {
|
"controllers": [
|
||||||
name: "Web Page",
|
|
||||||
description: "Embed a web page or web-based image in a resizeable window component. Note that the URL being embedded must allow iframing.",
|
|
||||||
creatable: true,
|
|
||||||
cssClass: 'icon-page',
|
|
||||||
form: [
|
|
||||||
{
|
{
|
||||||
"key": "url",
|
"key": "ExampleFormController",
|
||||||
"name": "URL",
|
"implementation": ExampleFormController,
|
||||||
"control": "textfield",
|
"depends": [
|
||||||
"required": true,
|
"$scope"
|
||||||
"cssClass": "l-input-lg"
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"templateUrl": "templates/exampleForm.html"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
}
|
||||||
};
|
});
|
||||||
}
|
});
|
42
example/forms/res/templates/exampleForm.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
Administration. All rights reserved.
|
||||||
|
|
||||||
|
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
|
||||||
|
Open MCT includes source code licensed under additional open source
|
||||||
|
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
this source code distribution or the Licensing information page available
|
||||||
|
at runtime from the About dialog for additional information.
|
||||||
|
-->
|
||||||
|
<div ng-controller="ExampleFormController">
|
||||||
|
<mct-toolbar structure="toolbar"
|
||||||
|
ng-model="state"
|
||||||
|
name="aToolbar"></mct-toolbar>
|
||||||
|
|
||||||
|
<mct-form structure="form"
|
||||||
|
ng-model="state"
|
||||||
|
class="validates"
|
||||||
|
name="aForm"></mct-form>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Dirty: {{aForm.$dirty}}</li>
|
||||||
|
<li>Valid: {{aForm.$valid}}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<textarea>
|
||||||
|
{{state | json}}
|
||||||
|
</textarea>
|
||||||
|
</pre>
|
||||||
|
</div>
|
182
example/forms/src/ExampleFormController.js
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define,window*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function ExampleFormController($scope) {
|
||||||
|
$scope.state = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.toolbar = {
|
||||||
|
name: "An example toolbar.",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
description: "First section",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: "X",
|
||||||
|
description: "X coordinate",
|
||||||
|
control: "textfield",
|
||||||
|
pattern: "^\\d+$",
|
||||||
|
disabled: true,
|
||||||
|
size: 2,
|
||||||
|
key: "x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Y",
|
||||||
|
description: "Y coordinate",
|
||||||
|
control: "textfield",
|
||||||
|
pattern: "^\\d+$",
|
||||||
|
size: 2,
|
||||||
|
key: "y"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "W",
|
||||||
|
description: "Cell width",
|
||||||
|
control: "textfield",
|
||||||
|
pattern: "^\\d+$",
|
||||||
|
size: 2,
|
||||||
|
key: "w"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "H",
|
||||||
|
description: "Cell height",
|
||||||
|
control: "textfield",
|
||||||
|
pattern: "^\\d+$",
|
||||||
|
size: 2,
|
||||||
|
key: "h"
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Second section",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
control: "button",
|
||||||
|
csslass: "icon-save",
|
||||||
|
click: function () {
|
||||||
|
window.alert("Save");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "button",
|
||||||
|
csslass: "icon-x",
|
||||||
|
description: "Button B",
|
||||||
|
click: function () {
|
||||||
|
window.alert("Cancel");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "button",
|
||||||
|
csslass: "icon-trash",
|
||||||
|
description: "Button C",
|
||||||
|
disabled: true,
|
||||||
|
click: function () {
|
||||||
|
window.alert("Delete");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
control: "color",
|
||||||
|
key: "color"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.form = {
|
||||||
|
name: "An example form.",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
name: "First section",
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
name: "Check me",
|
||||||
|
control: "checkbox",
|
||||||
|
key: "checkMe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enter your name",
|
||||||
|
required: true,
|
||||||
|
control: "textfield",
|
||||||
|
key: "yourName"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enter a number",
|
||||||
|
control: "textfield",
|
||||||
|
pattern: "^\\d+$",
|
||||||
|
key: "aNumber"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Second section",
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
name: "Pick a date",
|
||||||
|
required: true,
|
||||||
|
description: "Enter date in form YYYY-DDD",
|
||||||
|
control: "datetime",
|
||||||
|
key: "aDate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Choose something",
|
||||||
|
control: "select",
|
||||||
|
options: [
|
||||||
|
{ name: "Hats", value: "hats" },
|
||||||
|
{ name: "Bats", value: "bats" },
|
||||||
|
{ name: "Cats", value: "cats" },
|
||||||
|
{ name: "Mats", value: "mats" }
|
||||||
|
],
|
||||||
|
key: "aChoice"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Choose something",
|
||||||
|
control: "select",
|
||||||
|
required: true,
|
||||||
|
options: [
|
||||||
|
{ name: "Hats", value: "hats" },
|
||||||
|
{ name: "Bats", value: "bats" },
|
||||||
|
{ name: "Cats", value: "cats" },
|
||||||
|
{ name: "Mats", value: "mats" }
|
||||||
|
],
|
||||||
|
key: "aRequiredChoice"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExampleFormController;
|
||||||
|
}
|
||||||
|
);
|
@ -9,8 +9,7 @@ define([
|
|||||||
values: [
|
values: [
|
||||||
{
|
{
|
||||||
key: "name",
|
key: "name",
|
||||||
name: "Name",
|
name: "Name"
|
||||||
format: "string"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "utc",
|
key: "utc",
|
||||||
@ -28,29 +27,9 @@ define([
|
|||||||
domain: 2
|
domain: 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "cos",
|
|
||||||
name: "Cosine",
|
|
||||||
unit: "deg",
|
|
||||||
formatString: '%0.2f',
|
|
||||||
hints: {
|
|
||||||
domain: 3
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Need to enable "LocalTimeSystem" plugin to make use of this
|
|
||||||
// {
|
|
||||||
// key: "local",
|
|
||||||
// name: "Time",
|
|
||||||
// format: "local-format",
|
|
||||||
// source: "utc",
|
|
||||||
// hints: {
|
|
||||||
// domain: 3
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
key: "sin",
|
key: "sin",
|
||||||
name: "Sine",
|
name: "Sine",
|
||||||
unit: "Hz",
|
|
||||||
formatString: '%0.2f',
|
formatString: '%0.2f',
|
||||||
hints: {
|
hints: {
|
||||||
range: 1
|
range: 1
|
||||||
@ -59,7 +38,6 @@ define([
|
|||||||
{
|
{
|
||||||
key: "cos",
|
key: "cos",
|
||||||
name: "Cosine",
|
name: "Cosine",
|
||||||
unit: "deg",
|
|
||||||
formatString: '%0.2f',
|
formatString: '%0.2f',
|
||||||
hints: {
|
hints: {
|
||||||
range: 2
|
range: 2
|
||||||
@ -71,8 +49,7 @@ define([
|
|||||||
values: [
|
values: [
|
||||||
{
|
{
|
||||||
key: "name",
|
key: "name",
|
||||||
name: "Name",
|
name: "Name"
|
||||||
format: "string"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "utc",
|
key: "utc",
|
||||||
@ -82,15 +59,6 @@ define([
|
|||||||
domain: 1
|
domain: 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "local",
|
|
||||||
name: "Time",
|
|
||||||
format: "utc",
|
|
||||||
source: "utc",
|
|
||||||
hints: {
|
|
||||||
domain: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "state",
|
key: "state",
|
||||||
source: "value",
|
source: "value",
|
||||||
@ -119,22 +87,22 @@ define([
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function GeneratorMetadataProvider() {
|
function GeneratorMetadataProvider() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneratorMetadataProvider.prototype.supportsMetadata = function (domainObject) {
|
GeneratorMetadataProvider.prototype.supportsMetadata = function (domainObject) {
|
||||||
return Object.prototype.hasOwnProperty.call(METADATA_BY_TYPE, domainObject.type);
|
return METADATA_BY_TYPE.hasOwnProperty(domainObject.type);
|
||||||
};
|
};
|
||||||
|
|
||||||
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
|
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
|
||||||
return Object.assign(
|
return _.extend(
|
||||||
{},
|
{},
|
||||||
domainObject.telemetry,
|
domainObject.telemetry,
|
||||||
METADATA_BY_TYPE[domainObject.type]
|
METADATA_BY_TYPE[domainObject.type]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return GeneratorMetadataProvider;
|
return GeneratorMetadataProvider;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -31,7 +31,6 @@ define([
|
|||||||
period: 10,
|
period: 10,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
dataRateInHz: 1,
|
dataRateInHz: 1,
|
||||||
randomness: 0,
|
|
||||||
phase: 0
|
phase: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,7 +53,6 @@ define([
|
|||||||
'offset',
|
'offset',
|
||||||
'dataRateInHz',
|
'dataRateInHz',
|
||||||
'phase',
|
'phase',
|
||||||
'randomness'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
request = request || {};
|
request = request || {};
|
||||||
@ -62,23 +60,18 @@ define([
|
|||||||
var workerRequest = {};
|
var workerRequest = {};
|
||||||
|
|
||||||
props.forEach(function (prop) {
|
props.forEach(function (prop) {
|
||||||
if (domainObject.telemetry && Object.prototype.hasOwnProperty.call(domainObject.telemetry, prop)) {
|
if (domainObject.telemetry && domainObject.telemetry.hasOwnProperty(prop)) {
|
||||||
workerRequest[prop] = domainObject.telemetry[prop];
|
workerRequest[prop] = domainObject.telemetry[prop];
|
||||||
}
|
}
|
||||||
|
if (request && request.hasOwnProperty(prop)) {
|
||||||
if (request && Object.prototype.hasOwnProperty.call(request, prop)) {
|
|
||||||
workerRequest[prop] = request[prop];
|
workerRequest[prop] = request[prop];
|
||||||
}
|
}
|
||||||
|
if (!workerRequest.hasOwnProperty(prop)) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(workerRequest, prop)) {
|
|
||||||
workerRequest[prop] = REQUEST_DEFAULTS[prop];
|
workerRequest[prop] = REQUEST_DEFAULTS[prop];
|
||||||
}
|
}
|
||||||
|
|
||||||
workerRequest[prop] = Number(workerRequest[prop]);
|
workerRequest[prop] = Number(workerRequest[prop]);
|
||||||
});
|
});
|
||||||
|
|
||||||
workerRequest.name = domainObject.name;
|
workerRequest.name = domainObject.name;
|
||||||
|
|
||||||
return workerRequest;
|
return workerRequest;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -86,13 +79,11 @@ define([
|
|||||||
var workerRequest = this.makeWorkerRequest(domainObject, request);
|
var workerRequest = this.makeWorkerRequest(domainObject, request);
|
||||||
workerRequest.start = request.start;
|
workerRequest.start = request.start;
|
||||||
workerRequest.end = request.end;
|
workerRequest.end = request.end;
|
||||||
|
|
||||||
return this.workerInterface.request(workerRequest);
|
return this.workerInterface.request(workerRequest);
|
||||||
};
|
};
|
||||||
|
|
||||||
GeneratorProvider.prototype.subscribe = function (domainObject, callback) {
|
GeneratorProvider.prototype.subscribe = function (domainObject, callback) {
|
||||||
var workerRequest = this.makeWorkerRequest(domainObject, {});
|
var workerRequest = this.makeWorkerRequest(domainObject, {});
|
||||||
|
|
||||||
return this.workerInterface.subscribe(workerRequest, callback);
|
return this.workerInterface.subscribe(workerRequest, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -19,6 +19,7 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
|
|
||||||
@ -26,47 +27,35 @@ define([
|
|||||||
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var PURPLE = {
|
var RED = {
|
||||||
sin: 2.2,
|
sin: 0.9,
|
||||||
cos: 2.2
|
|
||||||
},
|
|
||||||
RED = {
|
|
||||||
sin: 0.9,
|
|
||||||
cos: 0.9
|
cos: 0.9
|
||||||
},
|
},
|
||||||
ORANGE = {
|
|
||||||
sin: 0.7,
|
|
||||||
cos: 0.7
|
|
||||||
},
|
|
||||||
YELLOW = {
|
YELLOW = {
|
||||||
sin: 0.5,
|
sin: 0.5,
|
||||||
cos: 0.5
|
cos: 0.5
|
||||||
},
|
},
|
||||||
CYAN = {
|
|
||||||
sin: 0.45,
|
|
||||||
cos: 0.45
|
|
||||||
},
|
|
||||||
LIMITS = {
|
LIMITS = {
|
||||||
rh: {
|
rh: {
|
||||||
cssClass: "is-limit--upr is-limit--red",
|
cssClass: "s-limit-upr s-limit-red",
|
||||||
low: RED,
|
low: RED,
|
||||||
high: Number.POSITIVE_INFINITY,
|
high: Number.POSITIVE_INFINITY,
|
||||||
name: "Red High"
|
name: "Red High"
|
||||||
},
|
},
|
||||||
rl: {
|
rl: {
|
||||||
cssClass: "is-limit--lwr is-limit--red",
|
cssClass: "s-limit-lwr s-limit-red",
|
||||||
high: -RED,
|
high: -RED,
|
||||||
low: Number.NEGATIVE_INFINITY,
|
low: Number.NEGATIVE_INFINITY,
|
||||||
name: "Red Low"
|
name: "Red Low"
|
||||||
},
|
},
|
||||||
yh: {
|
yh: {
|
||||||
cssClass: "is-limit--upr is-limit--yellow",
|
cssClass: "s-limit-upr s-limit-yellow",
|
||||||
low: YELLOW,
|
low: YELLOW,
|
||||||
high: RED,
|
high: RED,
|
||||||
name: "Yellow High"
|
name: "Yellow High"
|
||||||
},
|
},
|
||||||
yl: {
|
yl: {
|
||||||
cssClass: "is-limit--lwr is-limit--yellow",
|
cssClass: "s-limit-lwr s-limit-yellow",
|
||||||
low: -RED,
|
low: -RED,
|
||||||
high: -YELLOW,
|
high: -YELLOW,
|
||||||
name: "Yellow Low"
|
name: "Yellow Low"
|
||||||
@ -85,19 +74,16 @@ define([
|
|||||||
return {
|
return {
|
||||||
evaluate: function (datum, valueMetadata) {
|
evaluate: function (datum, valueMetadata) {
|
||||||
var range = valueMetadata && valueMetadata.key;
|
var range = valueMetadata && valueMetadata.key;
|
||||||
|
|
||||||
if (datum[range] > RED[range]) {
|
if (datum[range] > RED[range]) {
|
||||||
return LIMITS.rh;
|
return LIMITS.rh;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datum[range] < -RED[range]) {
|
if (datum[range] < -RED[range]) {
|
||||||
return LIMITS.rl;
|
return LIMITS.rl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datum[range] > YELLOW[range]) {
|
if (datum[range] > YELLOW[range]) {
|
||||||
return LIMITS.yh;
|
return LIMITS.yh;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datum[range] < -YELLOW[range]) {
|
if (datum[range] < -YELLOW[range]) {
|
||||||
return LIMITS.yl;
|
return LIMITS.yl;
|
||||||
}
|
}
|
||||||
@ -105,70 +91,5 @@ define([
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
SinewaveLimitProvider.prototype.getLimits = function (domainObject) {
|
|
||||||
|
|
||||||
return {
|
|
||||||
limits: function () {
|
|
||||||
return Promise.resolve({
|
|
||||||
WATCH: {
|
|
||||||
low: {
|
|
||||||
color: "cyan",
|
|
||||||
sin: -CYAN.sin,
|
|
||||||
cos: -CYAN.cos
|
|
||||||
},
|
|
||||||
high: {
|
|
||||||
color: "cyan",
|
|
||||||
...CYAN
|
|
||||||
}
|
|
||||||
},
|
|
||||||
WARNING: {
|
|
||||||
low: {
|
|
||||||
color: "yellow",
|
|
||||||
sin: -YELLOW.sin,
|
|
||||||
cos: -YELLOW.cos
|
|
||||||
},
|
|
||||||
high: {
|
|
||||||
color: "yellow",
|
|
||||||
...YELLOW
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DISTRESS: {
|
|
||||||
low: {
|
|
||||||
color: "orange",
|
|
||||||
sin: -ORANGE.sin,
|
|
||||||
cos: -ORANGE.cos
|
|
||||||
},
|
|
||||||
high: {
|
|
||||||
color: "orange",
|
|
||||||
...ORANGE
|
|
||||||
}
|
|
||||||
},
|
|
||||||
CRITICAL: {
|
|
||||||
low: {
|
|
||||||
color: "red",
|
|
||||||
sin: -RED.sin,
|
|
||||||
cos: -RED.cos
|
|
||||||
},
|
|
||||||
high: {
|
|
||||||
color: "red",
|
|
||||||
...RED
|
|
||||||
}
|
|
||||||
},
|
|
||||||
SEVERE: {
|
|
||||||
low: {
|
|
||||||
color: "purple",
|
|
||||||
sin: -PURPLE.sin,
|
|
||||||
cos: -PURPLE.cos
|
|
||||||
},
|
|
||||||
high: {
|
|
||||||
color: "purple",
|
|
||||||
...PURPLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return SinewaveLimitProvider;
|
return SinewaveLimitProvider;
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -48,7 +48,7 @@ define([
|
|||||||
var interval = setInterval(function () {
|
var interval = setInterval(function () {
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
var datum = pointForTimestamp(now, duration, domainObject.name);
|
var datum = pointForTimestamp(now, duration, domainObject.name);
|
||||||
datum.value = String(datum.value);
|
datum.value += "";
|
||||||
callback(datum);
|
callback(datum);
|
||||||
}, duration);
|
}, duration);
|
||||||
|
|
||||||
@ -57,24 +57,23 @@ define([
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
StateGeneratorProvider.prototype.supportsRequest = function (domainObject, options) {
|
StateGeneratorProvider.prototype.supportsRequest = function (domainObject, options) {
|
||||||
return domainObject.type === 'example.state-generator';
|
return domainObject.type === 'example.state-generator';
|
||||||
};
|
};
|
||||||
|
|
||||||
StateGeneratorProvider.prototype.request = function (domainObject, options) {
|
StateGeneratorProvider.prototype.request = function (domainObject, options) {
|
||||||
var start = options.start;
|
var start = options.start;
|
||||||
var end = Math.min(Date.now(), options.end); // no future values
|
var end = options.end;
|
||||||
var duration = domainObject.telemetry.duration * 1000;
|
var duration = domainObject.telemetry.duration * 1000;
|
||||||
if (options.strategy === 'latest' || options.size === 1) {
|
if (options.strategy === 'latest' || options.size === 1) {
|
||||||
start = end;
|
start = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = [];
|
var data = [];
|
||||||
while (start <= end && data.length < 5000) {
|
while (start <= end && data.length < 5000) {
|
||||||
data.push(pointForTimestamp(start, duration, domainObject.name));
|
data.push(pointForTimestamp(start, duration, domainObject.name));
|
||||||
start += duration;
|
start += duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(data);
|
return Promise.resolve(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -72,16 +72,13 @@ define([
|
|||||||
});
|
});
|
||||||
var messageId;
|
var messageId;
|
||||||
|
|
||||||
let self = this;
|
|
||||||
function callback(message) {
|
function callback(message) {
|
||||||
if (message.error) {
|
if (message.error) {
|
||||||
deferred.reject(message.error);
|
deferred.reject(message.error);
|
||||||
} else {
|
} else {
|
||||||
deferred.resolve(message.data);
|
deferred.resolve(message.data);
|
||||||
}
|
}
|
||||||
|
delete this.callbacks[messageId];
|
||||||
delete self.callbacks[messageId];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
messageId = this.dispatch('request', request, callback.bind(this));
|
messageId = this.dispatch('request', request, callback.bind(this));
|
||||||
@ -92,7 +89,7 @@ define([
|
|||||||
WorkerInterface.prototype.subscribe = function (request, cb) {
|
WorkerInterface.prototype.subscribe = function (request, cb) {
|
||||||
function callback(message) {
|
function callback(message) {
|
||||||
cb(message.data);
|
cb(message.data);
|
||||||
}
|
};
|
||||||
|
|
||||||
var messageId = this.dispatch('subscribe', request, callback);
|
var messageId = this.dispatch('subscribe', request, callback);
|
||||||
|
|
||||||
@ -104,5 +101,8 @@ define([
|
|||||||
}.bind(this);
|
}.bind(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return WorkerInterface;
|
return WorkerInterface;
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -20,6 +20,8 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*global self*/
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
|
|
||||||
var FIFTEEN_MINUTES = 15 * 60 * 1000;
|
var FIFTEEN_MINUTES = 15 * 60 * 1000;
|
||||||
@ -54,38 +56,22 @@
|
|||||||
var start = Date.now();
|
var start = Date.now();
|
||||||
var step = 1000 / data.dataRateInHz;
|
var step = 1000 / data.dataRateInHz;
|
||||||
var nextStep = start - (start % step) + step;
|
var nextStep = start - (start % step) + step;
|
||||||
let work;
|
|
||||||
if (data.spectra) {
|
|
||||||
work = function (now) {
|
|
||||||
while (nextStep < now) {
|
|
||||||
const messageCopy = Object.create(message);
|
|
||||||
message.data.start = nextStep - (60 * 1000);
|
|
||||||
message.data.end = nextStep;
|
|
||||||
onRequest(messageCopy);
|
|
||||||
nextStep += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nextStep;
|
function work(now) {
|
||||||
};
|
while (nextStep < now) {
|
||||||
} else {
|
self.postMessage({
|
||||||
work = function (now) {
|
id: message.id,
|
||||||
while (nextStep < now) {
|
data: {
|
||||||
self.postMessage({
|
name: data.name,
|
||||||
id: message.id,
|
utc: nextStep,
|
||||||
data: {
|
yesterday: nextStep - 60*60*24*1000,
|
||||||
name: data.name,
|
sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase),
|
||||||
utc: nextStep,
|
cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase)
|
||||||
yesterday: nextStep - 60 * 60 * 24 * 1000,
|
}
|
||||||
sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness),
|
});
|
||||||
wavelength: wavelength(start, nextStep),
|
nextStep += step;
|
||||||
cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness)
|
}
|
||||||
}
|
return nextStep;
|
||||||
});
|
|
||||||
nextStep += step;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nextStep;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subscriptions[message.id] = work;
|
subscriptions[message.id] = work;
|
||||||
@ -98,11 +84,10 @@
|
|||||||
|
|
||||||
function onRequest(message) {
|
function onRequest(message) {
|
||||||
var request = message.data;
|
var request = message.data;
|
||||||
if (request.end === undefined) {
|
if (request.end == undefined) {
|
||||||
request.end = Date.now();
|
request.end = Date.now();
|
||||||
}
|
}
|
||||||
|
if (request.start == undefined){
|
||||||
if (request.start === undefined) {
|
|
||||||
request.start = request.end - FIFTEEN_MINUTES;
|
request.start = request.end - FIFTEEN_MINUTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +99,6 @@
|
|||||||
var offset = request.offset;
|
var offset = request.offset;
|
||||||
var dataRateInHz = request.dataRateInHz;
|
var dataRateInHz = request.dataRateInHz;
|
||||||
var phase = request.phase;
|
var phase = request.phase;
|
||||||
var randomness = request.randomness;
|
|
||||||
|
|
||||||
var step = 1000 / dataRateInHz;
|
var step = 1000 / dataRateInHz;
|
||||||
var nextStep = start - (start % step) + step;
|
var nextStep = start - (start % step) + step;
|
||||||
@ -123,39 +107,27 @@
|
|||||||
|
|
||||||
for (; nextStep < end && data.length < 5000; nextStep += step) {
|
for (; nextStep < end && data.length < 5000; nextStep += step) {
|
||||||
data.push({
|
data.push({
|
||||||
|
name: request.name,
|
||||||
utc: nextStep,
|
utc: nextStep,
|
||||||
yesterday: nextStep - 60 * 60 * 24 * 1000,
|
yesterday: nextStep - 60*60*24*1000,
|
||||||
sin: sin(nextStep, period, amplitude, offset, phase, randomness),
|
sin: sin(nextStep, period, amplitude, offset, phase),
|
||||||
wavelength: wavelength(start, nextStep),
|
cos: cos(nextStep, period, amplitude, offset, phase)
|
||||||
cos: cos(nextStep, period, amplitude, offset, phase, randomness)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
id: message.id,
|
id: message.id,
|
||||||
data: request.spectra ? {
|
data: data
|
||||||
wavelength: data.map((item) => {
|
|
||||||
return item.wavelength;
|
|
||||||
}),
|
|
||||||
cos: data.map((item) => {
|
|
||||||
return item.cos;
|
|
||||||
})
|
|
||||||
} : data
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function cos(timestamp, period, amplitude, offset, phase, randomness) {
|
function cos(timestamp, period, amplitude, offset, phase) {
|
||||||
return amplitude
|
return amplitude *
|
||||||
* Math.cos(phase + (timestamp / period / 1000 * Math.PI * 2)) + (amplitude * Math.random() * randomness) + offset;
|
Math.cos(phase + (timestamp / period / 1000 * Math.PI * 2)) + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sin(timestamp, period, amplitude, offset, phase, randomness) {
|
function sin(timestamp, period, amplitude, offset, phase) {
|
||||||
return amplitude
|
return amplitude *
|
||||||
* Math.sin(phase + (timestamp / period / 1000 * Math.PI * 2)) + (amplitude * Math.random() * randomness) + offset;
|
Math.sin(phase + (timestamp / period / 1000 * Math.PI * 2)) + offset;
|
||||||
}
|
|
||||||
|
|
||||||
function wavelength(start, nextStep) {
|
|
||||||
return (nextStep - start) / 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendError(error, message) {
|
function sendError(error, message) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -19,6 +19,7 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
"./GeneratorProvider",
|
"./GeneratorProvider",
|
||||||
@ -32,30 +33,31 @@ define([
|
|||||||
GeneratorMetadataProvider
|
GeneratorMetadataProvider
|
||||||
) {
|
) {
|
||||||
|
|
||||||
return function (openmct) {
|
return function(openmct){
|
||||||
|
|
||||||
openmct.types.addType("example.state-generator", {
|
openmct.types.addType("example.state-generator", {
|
||||||
name: "State Generator",
|
name: "State Generator",
|
||||||
description: "For development use. Generates test enumerated telemetry by cycling through a given set of states",
|
description: "For development use. Generates test enumerated telemetry by cycling through a given set of states",
|
||||||
cssClass: "icon-generator-telemetry",
|
cssClass: "icon-telemetry",
|
||||||
creatable: true,
|
creatable: true,
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
name: "State Duration (seconds)",
|
name: "State Duration (seconds)",
|
||||||
control: "numberfield",
|
control: "textfield",
|
||||||
cssClass: "l-input-sm l-numeric",
|
cssClass: "l-input-sm l-numeric",
|
||||||
key: "duration",
|
key: "duration",
|
||||||
required: true,
|
required: true,
|
||||||
property: [
|
property: [
|
||||||
"telemetry",
|
"telemetry",
|
||||||
"duration"
|
"duration"
|
||||||
]
|
],
|
||||||
|
pattern: "^\\d*(\\.\\d*)?$"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
initialize: function (object) {
|
initialize: function (object) {
|
||||||
object.telemetry = {
|
object.telemetry = {
|
||||||
duration: 5
|
duration: 5
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -64,7 +66,7 @@ define([
|
|||||||
openmct.types.addType("generator", {
|
openmct.types.addType("generator", {
|
||||||
name: "Sine Wave Generator",
|
name: "Sine Wave Generator",
|
||||||
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
|
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
|
||||||
cssClass: "icon-generator-telemetry",
|
cssClass: "icon-telemetry",
|
||||||
creatable: true,
|
creatable: true,
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
@ -121,17 +123,6 @@ define([
|
|||||||
"telemetry",
|
"telemetry",
|
||||||
"phase"
|
"phase"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Randomness",
|
|
||||||
control: "numberfield",
|
|
||||||
cssClass: "l-input-sm l-numeric",
|
|
||||||
key: "randomness",
|
|
||||||
required: true,
|
|
||||||
property: [
|
|
||||||
"telemetry",
|
|
||||||
"randomness"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
initialize: function (object) {
|
initialize: function (object) {
|
||||||
@ -140,8 +131,7 @@ define([
|
|||||||
amplitude: 1,
|
amplitude: 1,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
dataRateInHz: 1,
|
dataRateInHz: 1,
|
||||||
phase: 0,
|
phase: 0
|
||||||
randomness: 0
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
48
example/identity/bundle.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define([
|
||||||
|
"./src/ExampleIdentityService",
|
||||||
|
'legacyRegistry'
|
||||||
|
], function (
|
||||||
|
ExampleIdentityService,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
legacyRegistry.register("example/identity", {
|
||||||
|
"extensions": {
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"implementation": ExampleIdentityService,
|
||||||
|
"provides": "identityService",
|
||||||
|
"type": "provider",
|
||||||
|
"depends": [
|
||||||
|
"dialogService",
|
||||||
|
"$q"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
91
example/identity/src/ExampleIdentityService.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var DEFAULT_IDENTITY = { key: "user", name: "Example User" },
|
||||||
|
DIALOG_STRUCTURE = {
|
||||||
|
name: "Identify Yourself",
|
||||||
|
sections: [{ rows: [
|
||||||
|
{
|
||||||
|
name: "User ID",
|
||||||
|
control: "textfield",
|
||||||
|
key: "key",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Human name",
|
||||||
|
control: "textfield",
|
||||||
|
key: "name",
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
]}]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example implementation of an identity service. This prompts the
|
||||||
|
* user to enter a name and user ID; in a more realistic
|
||||||
|
* implementation, this would be read from a server, possibly
|
||||||
|
* prompting for a user name and password (or similar) as
|
||||||
|
* appropriate.
|
||||||
|
*
|
||||||
|
* @implements {IdentityService}
|
||||||
|
* @memberof platform/identity
|
||||||
|
*/
|
||||||
|
function ExampleIdentityProvider(dialogService, $q) {
|
||||||
|
this.dialogService = dialogService;
|
||||||
|
this.$q = $q;
|
||||||
|
|
||||||
|
this.returnUser = this.returnUser.bind(this);
|
||||||
|
this.returnUndefined = this.returnUndefined.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExampleIdentityProvider.prototype.getUser = function () {
|
||||||
|
if (this.user) {
|
||||||
|
return this.$q.when(this.user);
|
||||||
|
} else {
|
||||||
|
return this.dialogService.getUserInput(DIALOG_STRUCTURE, DEFAULT_IDENTITY)
|
||||||
|
.then(this.returnUser, this.returnUndefined);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ExampleIdentityProvider.prototype.returnUser = function (user) {
|
||||||
|
return this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ExampleIdentityProvider.prototype.returnUndefined = function () {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExampleIdentityProvider;
|
||||||
|
}
|
||||||
|
);
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -20,219 +20,126 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
const DEFAULT_IMAGE_SAMPLES = [
|
define([
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18731.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18732.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18733.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18734.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18735.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18736.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18737.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18738.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18739.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18740.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18741.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18742.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18743.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18744.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18745.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18746.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18747.jpg",
|
|
||||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18748.jpg"
|
|
||||||
];
|
|
||||||
const DEFAULT_IMAGE_LOAD_DELAY_IN_MILISECONDS = 20000;
|
|
||||||
const MIN_IMAGE_LOAD_DELAY_IN_MILISECONDS = 5000;
|
|
||||||
|
|
||||||
let openmctInstance;
|
], function(
|
||||||
|
|
||||||
export default function () {
|
) {
|
||||||
return function install(openmct) {
|
function ImageryPlugin() {
|
||||||
openmctInstance = openmct;
|
|
||||||
openmct.types.addType('example.imagery', {
|
|
||||||
key: 'example.imagery',
|
|
||||||
name: 'Example Imagery',
|
|
||||||
cssClass: 'icon-image',
|
|
||||||
description: 'For development use. Creates example imagery '
|
|
||||||
+ 'data that mimics a live imagery stream.',
|
|
||||||
creatable: true,
|
|
||||||
initialize: (object) => {
|
|
||||||
object.configuration = {
|
|
||||||
imageLocation: '',
|
|
||||||
imageLoadDelayInMilliSeconds: DEFAULT_IMAGE_LOAD_DELAY_IN_MILISECONDS,
|
|
||||||
imageSamples: []
|
|
||||||
};
|
|
||||||
|
|
||||||
object.telemetry = {
|
var IMAGE_SAMPLES = [
|
||||||
values: [
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18731.jpg",
|
||||||
{
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18732.jpg",
|
||||||
name: 'Name',
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18733.jpg",
|
||||||
key: 'name'
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18734.jpg",
|
||||||
},
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18735.jpg",
|
||||||
{
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18736.jpg",
|
||||||
name: 'Time',
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18737.jpg",
|
||||||
key: 'utc',
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18738.jpg",
|
||||||
format: 'utc',
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18739.jpg",
|
||||||
hints: {
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18740.jpg",
|
||||||
domain: 2
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18741.jpg",
|
||||||
}
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18742.jpg",
|
||||||
},
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18743.jpg",
|
||||||
{
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18744.jpg",
|
||||||
name: 'Local Time',
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18745.jpg",
|
||||||
key: 'local',
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18746.jpg",
|
||||||
format: 'local-format',
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18747.jpg",
|
||||||
hints: {
|
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18748.jpg"
|
||||||
domain: 1
|
];
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Image',
|
|
||||||
key: 'url',
|
|
||||||
format: 'image',
|
|
||||||
hints: {
|
|
||||||
image: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Image Download Name',
|
|
||||||
key: 'imageDownloadName',
|
|
||||||
format: 'imageDownloadName',
|
|
||||||
hints: {
|
|
||||||
imageDownloadName: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
form: [
|
|
||||||
{
|
|
||||||
key: 'imageLocation',
|
|
||||||
name: 'Images url list (comma separated)',
|
|
||||||
control: 'textarea',
|
|
||||||
cssClass: 'l-inline',
|
|
||||||
property: [
|
|
||||||
"configuration",
|
|
||||||
"imageLocation"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'imageLoadDelayInMilliSeconds',
|
|
||||||
name: 'Image load delay (milliseconds)',
|
|
||||||
control: 'numberfield',
|
|
||||||
required: true,
|
|
||||||
cssClass: 'l-inline',
|
|
||||||
property: [
|
|
||||||
"configuration",
|
|
||||||
"imageLoadDelayInMilliSeconds"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
openmct.telemetry.addProvider(getRealtimeProvider());
|
function pointForTimestamp(timestamp, name) {
|
||||||
openmct.telemetry.addProvider(getHistoricalProvider());
|
return {
|
||||||
openmct.telemetry.addProvider(getLadProvider());
|
name: name,
|
||||||
};
|
utc: Math.floor(timestamp / 5000) * 5000,
|
||||||
}
|
url: IMAGE_SAMPLES[Math.floor(timestamp / 5000) % IMAGE_SAMPLES.length]
|
||||||
|
|
||||||
function getCompassValues(min, max) {
|
|
||||||
return min + Math.random() * (max - min);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getImageSamples(configuration) {
|
|
||||||
let imageSamples = DEFAULT_IMAGE_SAMPLES;
|
|
||||||
|
|
||||||
if (configuration.imageLocation && configuration.imageLocation.length) {
|
|
||||||
imageSamples = getImageUrlListFromConfig(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
return imageSamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getImageUrlListFromConfig(configuration) {
|
|
||||||
return configuration.imageLocation.split(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
function getImageLoadDelay(domainObject) {
|
|
||||||
const imageLoadDelay = domainObject.configuration.imageLoadDelayInMilliSeconds;
|
|
||||||
if (!imageLoadDelay) {
|
|
||||||
openmctInstance.objects.mutate(domainObject, 'configuration.imageLoadDelayInMilliSeconds', DEFAULT_IMAGE_LOAD_DELAY_IN_MILISECONDS);
|
|
||||||
|
|
||||||
return DEFAULT_IMAGE_LOAD_DELAY_IN_MILISECONDS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imageLoadDelay < MIN_IMAGE_LOAD_DELAY_IN_MILISECONDS) {
|
|
||||||
openmctInstance.objects.mutate(domainObject, 'configuration.imageLoadDelayInMilliSeconds', MIN_IMAGE_LOAD_DELAY_IN_MILISECONDS);
|
|
||||||
|
|
||||||
return MIN_IMAGE_LOAD_DELAY_IN_MILISECONDS;
|
|
||||||
}
|
|
||||||
|
|
||||||
return imageLoadDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRealtimeProvider() {
|
|
||||||
return {
|
|
||||||
supportsSubscribe: domainObject => domainObject.type === 'example.imagery',
|
|
||||||
subscribe: (domainObject, callback) => {
|
|
||||||
const delay = getImageLoadDelay(domainObject);
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
callback(pointForTimestamp(Date.now(), domainObject.name, getImageSamples(domainObject.configuration), delay));
|
|
||||||
}, delay);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
clearInterval(interval);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHistoricalProvider() {
|
var realtimeProvider = {
|
||||||
return {
|
supportsSubscribe: function (domainObject) {
|
||||||
supportsRequest: (domainObject, options) => {
|
return domainObject.type === 'example.imagery';
|
||||||
return domainObject.type === 'example.imagery'
|
},
|
||||||
&& options.strategy !== 'latest';
|
subscribe: function (domainObject, callback) {
|
||||||
},
|
var interval = setInterval(function () {
|
||||||
request: (domainObject, options) => {
|
callback(pointForTimestamp(Date.now(), domainObject.name));
|
||||||
const delay = getImageLoadDelay(domainObject);
|
}, 5000);
|
||||||
let start = options.start;
|
|
||||||
const end = Math.min(options.end, Date.now());
|
return function (interval) {
|
||||||
const data = [];
|
clearInterval(interval);
|
||||||
while (start <= end && data.length < delay) {
|
};
|
||||||
data.push(pointForTimestamp(start, domainObject.name, getImageSamples(domainObject.configuration), delay));
|
|
||||||
start += delay;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return Promise.resolve(data);
|
var historicalProvider = {
|
||||||
}
|
supportsRequest: function (domainObject, options) {
|
||||||
};
|
return domainObject.type === 'example.imagery'
|
||||||
}
|
&& options.strategy !== 'latest';
|
||||||
|
},
|
||||||
|
request: function (domainObject, options) {
|
||||||
|
var start = options.start;
|
||||||
|
var end = options.end;
|
||||||
|
var data = [];
|
||||||
|
while (start <= end && data.length < 5000) {
|
||||||
|
data.push(pointForTimestamp(start, domainObject.name));
|
||||||
|
start += 5000;
|
||||||
|
}
|
||||||
|
return Promise.resolve(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function getLadProvider() {
|
var ladProvider = {
|
||||||
return {
|
supportsRequest: function (domainObject, options) {
|
||||||
supportsRequest: (domainObject, options) => {
|
return domainObject.type === 'example.imagery' &&
|
||||||
return domainObject.type === 'example.imagery'
|
options.strategy === 'latest';
|
||||||
&& options.strategy === 'latest';
|
},
|
||||||
},
|
request: function (domainObject, options) {
|
||||||
request: (domainObject, options) => {
|
return Promise.resolve([pointForTimestamp(Date.now(), domainObject.name)]);
|
||||||
const delay = getImageLoadDelay(domainObject);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return Promise.resolve([pointForTimestamp(Date.now(), domainObject.name, delay)]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function pointForTimestamp(timestamp, name, imageSamples, delay) {
|
return function install(openmct) {
|
||||||
const url = imageSamples[Math.floor(timestamp / delay) % imageSamples.length];
|
openmct.types.addType('example.imagery', {
|
||||||
const urlItems = url.split('/');
|
key: 'example.imagery',
|
||||||
const imageDownloadName = `example.imagery.${urlItems[urlItems.length - 1]}`;
|
name: 'Example Imagery',
|
||||||
|
cssClass: 'icon-image',
|
||||||
|
description: 'For development use. Creates example imagery ' +
|
||||||
|
'data that mimics a live imagery stream.',
|
||||||
|
creatable: true,
|
||||||
|
initialize: function (object) {
|
||||||
|
object.telemetry = {
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
name: 'Name',
|
||||||
|
key: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Time',
|
||||||
|
key: 'utc',
|
||||||
|
format: 'utc',
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Image',
|
||||||
|
key: 'url',
|
||||||
|
format: 'image',
|
||||||
|
hints: {
|
||||||
|
image: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
openmct.telemetry.addProvider(realtimeProvider);
|
||||||
name,
|
openmct.telemetry.addProvider(historicalProvider);
|
||||||
utc: Math.floor(timestamp / delay) * delay,
|
openmct.telemetry.addProvider(ladProvider);
|
||||||
local: Math.floor(timestamp / delay) * delay,
|
};
|
||||||
url,
|
}
|
||||||
sunOrientation: getCompassValues(0, 360),
|
|
||||||
cameraPan: getCompassValues(0, 360),
|
return ImageryPlugin;
|
||||||
heading: getCompassValues(0, 360),
|
});
|
||||||
imageDownloadName
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -19,26 +19,27 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'./TelemetryTableColumn.js'
|
|
||||||
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
TelemetryTableColumn
|
|
||||||
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
class TelemetryTableNameColumn extends TelemetryTableColumn {
|
"use strict";
|
||||||
constructor(openmct, telemetryObject, metadatum) {
|
|
||||||
super(openmct, metadatum);
|
|
||||||
|
|
||||||
this.telemetryObject = telemetryObject;
|
legacyRegistry.register("example/mobile", {
|
||||||
|
"name": "Mobile",
|
||||||
|
"description": "Allows elements with pertinence to mobile usage and development",
|
||||||
|
"extensions": {
|
||||||
|
"stylesheets": [
|
||||||
|
{
|
||||||
|
"stylesheetUrl": "css/mobile-example.css",
|
||||||
|
"priority": "mandatory"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
});
|
||||||
getRawValue() {
|
|
||||||
return this.telemetryObject.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFormattedValue() {
|
|
||||||
return this.telemetryObject.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TelemetryTableNameColumn;
|
|
||||||
});
|
});
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -19,16 +19,13 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
@import "../../../../platform/commonUI/general/res/sass/constants";
|
||||||
|
@import "../../../../platform/commonUI/general/res/sass/mobile/constants";
|
||||||
|
@import "../../../../platform/commonUI/general/res/sass/mobile/mixins";
|
||||||
|
|
||||||
import {saveAs} from 'saveAs';
|
@include phoneandtablet {
|
||||||
|
// Show the Create button
|
||||||
class JSONExporter {
|
.create-button-holder {
|
||||||
export(obj, options) {
|
display: block !important;
|
||||||
let filename = (options && options.filename) || "test-export.json";
|
|
||||||
let jsonText = JSON.stringify(obj);
|
|
||||||
let blob = new Blob([jsonText], {type: "application/json"});
|
|
||||||
saveAs(blob, filename);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default JSONExporter;
|
|
20
example/msl/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
To use this bundle, add the following paths to /main.js -
|
||||||
|
'./platform/features/conductor/bundle',
|
||||||
|
'./example/msl/bundle',
|
||||||
|
|
||||||
|
An example plugin that integrates with public data from the Curiosity rover.
|
||||||
|
The data shown used by this plugin is published by the Centro de
|
||||||
|
Astrobiología (CSIC-INTA) at http://cab.inta-csic.es/rems/
|
||||||
|
|
||||||
|
Fetching data from this source requires a cross-origin request which will
|
||||||
|
fail on most modern browsers due to restrictions on such requests. As such,
|
||||||
|
it is proxied through a local proxy defined in app.js. In order to use this
|
||||||
|
example you will need to run app.js locally.
|
||||||
|
|
||||||
|
This example shows integration with an historical telemetry source, as
|
||||||
|
opposed to a real-time data source that is streaming back current information
|
||||||
|
about the state of a system. This example is atypical of a historical data
|
||||||
|
source in that it fetches all data in one request. The server infrastructure
|
||||||
|
of an historical telemetry source should ideally allow queries bounded by
|
||||||
|
time and other data attributes.
|
||||||
|
|
115
example/msl/bundle.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define([
|
||||||
|
"./src/RemsTelemetryServerAdapter",
|
||||||
|
"./src/RemsTelemetryModelProvider",
|
||||||
|
"./src/RemsTelemetryProvider",
|
||||||
|
'legacyRegistry',
|
||||||
|
"module"
|
||||||
|
], function (
|
||||||
|
RemsTelemetryServerAdapter,
|
||||||
|
RemsTelemetryModelProvider,
|
||||||
|
RemsTelemetryProvider,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
"use strict";
|
||||||
|
legacyRegistry.register("example/msl", {
|
||||||
|
"name" : "Mars Science Laboratory Data Adapter",
|
||||||
|
"extensions" : {
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"name":"Mars Science Laboratory",
|
||||||
|
"key": "msl.curiosity",
|
||||||
|
"cssClass": "icon-object"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Instrument",
|
||||||
|
"key": "msl.instrument",
|
||||||
|
"cssClass": "icon-object",
|
||||||
|
"model": {"composition": []}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Measurement",
|
||||||
|
"key": "msl.measurement",
|
||||||
|
"cssClass": "icon-telemetry",
|
||||||
|
"model": {"telemetry": {}},
|
||||||
|
"telemetry": {
|
||||||
|
"source": "rems.source",
|
||||||
|
"domains": [
|
||||||
|
{
|
||||||
|
"name": "Time",
|
||||||
|
"key": "utc",
|
||||||
|
"format": "utc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"constants": [
|
||||||
|
{
|
||||||
|
"key": "REMS_WS_URL",
|
||||||
|
"value": "/proxyUrl?url=http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"roots": [
|
||||||
|
{
|
||||||
|
"id": "msl:curiosity"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"models": [
|
||||||
|
{
|
||||||
|
"id": "msl:curiosity",
|
||||||
|
"priority": "preferred",
|
||||||
|
"model": {
|
||||||
|
"type": "msl.curiosity",
|
||||||
|
"name": "Mars Science Laboratory",
|
||||||
|
"composition": ["msl_tlm:rems"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"key":"rems.adapter",
|
||||||
|
"implementation": RemsTelemetryServerAdapter,
|
||||||
|
"depends": ["$http", "$log", "REMS_WS_URL"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"provides": "modelService",
|
||||||
|
"type": "provider",
|
||||||
|
"implementation": RemsTelemetryModelProvider,
|
||||||
|
"depends": ["rems.adapter"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"provides": "telemetryService",
|
||||||
|
"type": "provider",
|
||||||
|
"implementation": RemsTelemetryProvider,
|
||||||
|
"depends": ["rems.adapter", "$q"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
1
example/msl/data/rems.json
Normal file
79
example/msl/src/MSLDataDictionary.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
/**
|
||||||
|
* A data dictionary describes the telemetry available from a data
|
||||||
|
* source and its data types. The data dictionary will be parsed by a custom
|
||||||
|
* server provider for this data source (in this case
|
||||||
|
* {@link RemsTelemetryServerAdapter}).
|
||||||
|
*
|
||||||
|
* Typically a data dictionary would be made available alongside the
|
||||||
|
* telemetry data source itself.
|
||||||
|
*/
|
||||||
|
function () {
|
||||||
|
return {
|
||||||
|
"name": "Mars Science Laboratory",
|
||||||
|
"identifier": "msl",
|
||||||
|
"instruments": [
|
||||||
|
{
|
||||||
|
"name":"rems",
|
||||||
|
"identifier": "rems",
|
||||||
|
"measurements": [
|
||||||
|
{
|
||||||
|
"name": "Min. Air Temperature",
|
||||||
|
"identifier": "min_temp",
|
||||||
|
"units": "Degrees (C)",
|
||||||
|
"type": "float"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Max. Air Temperature",
|
||||||
|
"identifier": "max_temp",
|
||||||
|
"units": "Degrees (C)",
|
||||||
|
"type": "float"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Atmospheric Pressure",
|
||||||
|
"identifier": "pressure",
|
||||||
|
"units": "Millibars",
|
||||||
|
"type": "float"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Min. Ground Temperature",
|
||||||
|
"identifier": "min_gts_temp",
|
||||||
|
"units": "Degrees (C)",
|
||||||
|
"type": "float"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Max. Ground Temperature",
|
||||||
|
"identifier": "max_gts_temp",
|
||||||
|
"units": "Degrees (C)",
|
||||||
|
"type": "float"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|