Compare commits

..

14 Commits

Author SHA1 Message Date
Andrew Henry
e83d20da3a Merge branch 'master' into reorder-indicators 2022-09-07 14:57:11 -07:00
dependabot[bot]
47fb81ff1c Bump uuid from 8.3.2 to 9.0.0 (#5732) 2022-09-06 10:42:36 -07:00
dependabot[bot]
0efc6987a5 Bump jasmine-core from 4.3.0 to 4.4.0 (#5733) 2022-09-06 10:29:26 -07:00
Khalid Adil
79d1df39b7 Add check to hide any old popup items when showing a new one (#5680)
* Add check to hide any old popup items when showing a new one

* Use more deterministic selector

* Hover first to "slow down" e2e actions while in headless mode

* Add notebook tests

* Combine the section tests

* Set focused image when timestamp prop is passed in

* Unused var

* Create timestrip with imagery child

* Add equality check for hovered image and view large image url

* Cleanup

* add annotation and checks

* [e2e] Minor locator improvements

* Update button title

* skipping with context

Co-authored-by: John Hill <john.c.hill@nasa.gov>
Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
2022-08-31 17:11:09 +00:00
Scott Bell
0c9ea26888 Swallow abort errors in search (#5650)
* Imagery thumbnail regression fixes - 5327 (#5591)

* Add an active class to thumbnail to indicate current focused image

* Differentiate bg color between real-time and fixed

* scrollIntoView inline: center

* Added watcher for bounds change to trigger thumbnail scroll

* Resolve merge conflict with requestHistory change to telemetry collection

* Split thumbnail into sub component

* Monitor isFixed value to unpause playback status

Co-authored-by: Khalid Adil <khalidadil29@gmail.com>

* [e2e] Improve appActions (#5592)

* update selectors to use aria labels

* Update appActions

- Create new function `getHashUrlToDomainObject` to get the browse url to a given object given its uuid

- Create new function `getFocusedObjectUuid`... self explanatory :)

- Update `createDomainObjectWIthDefaults` to make use of the new url generation

- Update `createDomainObject...`'s arguments to be more organized, and accept a parent object

- Update some docs, still need to clarify some

* Update appActions e2e tests

- Refactor for organization

- Test our new appActions in one go

* Update existing usages of `createDomainObject...` to match the new API

* fix accidental renamed export

* Fix jsdoc return types

* refactor telemetryTable test to use appActions

* Improve selectors

* Refactor test

* improve selector

* add clock mode appActions

* lint

* Fix jsdoc

* Code review comments

* mark failing visual tests as fixme temporarily

* Update package.json (#5601)

* Fix menu style in Snow theme (#5557)

* Include the plan source map when generating the time list/plan hybrid object (#5604)

* Search should indicate in progress and no results states, filter orphaned results (#5599)

* no matching result implemented

* now filtering annotations that are orphaned

* filter object results without valid paths

* add progress bar

* added e2e tests

* removed extraneous click

* fix typos

* fix unit tests

* lint

* address pr comments

* fix tests

* fix tests, centralize logic to object api, check for root instead

* remove debug statement

* lint

* fix documentation

* lint

* fix doc

* made some optimizations after talking with akhenry

* fix test

* update docs

* fix docs

* Have in-memory search indexer use composition API (#5578)

* need to remove tags and objects on composition removal
* had to separate out emits from load as it was causing memory indexer to loop upon itself

* Add parsing for areIdsEqual util to consistently remove folders (#5589)

* Add parsing util to identifier for ID comparison

* Moved firstIdentifier to top of function

* Lint fix

Co-authored-by: Andrew Henry <akhenry@gmail.com>

* Revert "Have in-memory search indexer use composition API (#5578)" (#5609)

This reverts commit 7cf11e177c.

* [e2e] Tests for Display Layout and LAD Tables and telemetry (#5607)

* Check for circular references in originalPath - 5615 (#5619)

* check for circular references

* add test

* fix test

* address PR comments by making comments better

* fix docs...again

* Update version number

* Prevent cyclic references in link & move actions (#5635)

* do not create circular refs

* add negative validation test

* move to plugin

* add link test too

* fix docs

* refactored per john request

* fix path

* use appAction lib

Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com>

* swallow abort errors in search

* [Fault Management] New Example Provider, Unit and e2e tests (#5579)

* added unit tests for fault management plugin

* modified the example fault provider to work out of the box

* updating for new e2e folder structure

* part of the e2e tests

* WIP

* Imagery thumbnail regression fixes - 5327 (#5569)

* Add an active class to thumbnail to indicate current focused image

* Differentiate bg color between real-time and fixed

* scrollIntoView inline: center

* Added watcher for bounds change to trigger thumbnail scroll

* Resolve merge conflict with requestHistory change to telemetry collection

* Split thumbnail into sub component

* Monitor isFixed value to unpause playback status

* updated search to include name, namespace and description added some more e2e tests

* added rest of e2e tests

* fixed my init script, had to disable lint for no-force because it was not working without it, saw online this may be a pw bug

* fix: removing maelstrom theme from application (#5600)

* added some tests for no faults

* visual tests

* added visual tests for fault management

* created utils file for shared functionality between function and visual tests

* updating to 2.0.8

* tryin to remove imagery changes from master

* trying to trigger a refresh

* tryin to refresh

* updated search to include name, namespace and description added some more e2e tests

* added rest of e2e tests

* fix: removing maelstrom theme from application (#5600)

* fixed my init script, had to disable lint for no-force because it was not working without it, saw online this may be a pw bug

* added some tests for no faults

* visual tests

* added visual tests for fault management

* created utils file for shared functionality between function and visual tests

* updating to 2.0.8

* no clue

* still no clue

* removing imports and chaning to requires

* updating utils file to work with require

* fixing paths

* fixing a test I had messed up when adding static exmaple faults

* ONE LAST PATH FIX... hopefully

* typo in files fix

* fix folder typo

* thought I got this one, but apparently not, well I did now! who is laughing now!?

Co-authored-by: Michael Rogers <contact@mhrogers.com>
Co-authored-by: Vitor Henckel <vitor@henckel.com.br>

* Sort tree items locally on rename (#5643)

* fix typo

* Sort the tree items locally on object rename

* Use the navigationPath as a key

- This ensures that objects AND linked objects will be sorted

* add 'tree' and 'treeitem' roles to mct-tree

* WIP tree item reordering test

* Select the first object that matches

* Test that all object links are also reordered

* Get the final uuid before queryParams as notebook sections have uuids

* Make `openObjectTreeContextMenu` more deterministic and update usage

* Add `expandPathToTreeItem` and `expandTreeItemByName` appActions

* add `#tree-pane` id for the tree view

* Add tree visual component test suite and bump percy-cli

* Remove tree appActions

* Better variable name

Co-authored-by: Scott Bell <scott@traclabs.com>

* Mct5549 fix indexer composition error (#5610)

* [Display Layout] Composition and configuration sync (#5669)

LGTM

* [e2e] Stabilize notebook tag tests (#5681)

* Use more deterministic selector

* Hover first to "slow down" e2e actions while in headless mode

* flush hash in case other requests are awaiting debounce

* flush hash in case other requests are awaiting debounce

* the debounce will cause this resolve function to never fire, so force a flush

* lint

* remove debug statements

* add a comment

* Moves condition set fix into 2.0.8 (#5673)

* Set Focused Image index after a imagery is selected from a timestrip - 5632 (#5664)

* Set focused image when timestamp prop is passed in

* Unused var

* Create timestrip with imagery child

* Add equality check for hovered image and view large image url

* Cleanup

* Time List 5534 for release/2.0.8 (#5678)

* Changes to Time List view. Closes #5534.
- Compacted table row spacing.
- Set all timeframes to display by default when creating a new Time List.
- Removed 'Upload plan' file button from properties.

* Changes to Time List view. Closes #5534.
- Better hint text for editing Timeframe Inspector section.

Co-authored-by: Andrew Henry <akhenry@gmail.com>

* [CI] Enable couchdb e2e testing in open source (#5655)

* Handle couch db not found errors so that interceptors are still invoked. (#5654)

* Fix tests for interceptors
* [e2e] Add test for 'mine' folder initialization
* [e2e] don't fail on expected console errors

Co-authored-by: Andrew Henry <akhenry@gmail.com>
Co-authored-by: Scott Bell <scott@traclabs.com>
Co-authored-by: John Hill <john.c.hill@nasa.gov>
Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>

* [Docs] Update CouchDB local install documentation (#5692)

* Update local CouchDB install docs to include docker workflow

* reformat to source configuration scripts where possible

* correct couchdb case

Co-authored-by: John Hill <john.c.hill@nasa.gov>

* [Time Conductor] History not working correctly (#5687)

* the check for fixed time vs realtime was not updating, have fixed this

* merging in related changes from master pr #4414

* lint fixes

* Update src/plugins/timeConductor/ConductorHistory.vue

Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com>

* setting time mode directly on load

* fixing issue where realtime history was being wiped on reloads while viewing fixed time

* formatting

* stubbed in some tests

Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com>

* Only index if provider does not support search - mct5690 (#5693)

* only index if provider does not support search

* add some tests

* fix tests

* [e2e] Add search couchdb test for duplicates

* [e2e] Modify existing search test instead

* lint

Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>

* fixed flakey test maybe?

* fixed flakey test maybe?

* fail on console errors

* turn on console errors for search

* revert karma code cov change

* couchdb scripting artifacts gitignore

* keep couchdb tests separate

* remove console true as this is the default

* cleanup tests

* [e2e][couchdb] fix docker-compose command

* [e2e][couchdb] ensure script is run using bash

* [e2e][couchdb] try to debug curl in gha

* [e2e][couchdb] try 0.0.0.0

* [e2e][couchdb] add debug step

* [e2e][couchdb] try -L option

* [e2e][couchdb] try 127.0.0.1

* [e2e][couchdb] add http

* [e2e][couchdb] provide initial config

* [e2e][couchdb] bind to 0.0.0.0

* [e2e][couchdb] debug

* [e2e][couchdb] wait for couchdb to start, remove failed hacks

* fix typo

Co-authored-by: Michael Rogers <contact@mhrogers.com>
Co-authored-by: Khalid Adil <khalidadil29@gmail.com>
Co-authored-by: Jesse Mazzella <ozyx@users.noreply.github.com>
Co-authored-by: John Hill <john.c.hill@nasa.gov>
Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
Co-authored-by: Alize Nguyen <alizenguyen@gmail.com>
Co-authored-by: Shefali <simplyrender@gmail.com>
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: Vitor Henckel <vitor@henckel.com.br>
Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov>
2022-08-31 10:25:00 +02:00
dependabot[bot]
153538b6bf Bump eslint from 8.22.0 to 8.23.0 (#5720)
Bumps [eslint](https://github.com/eslint/eslint) from 8.22.0 to 8.23.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.22.0...v8.23.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-29 13:46:16 -07:00
dependabot[bot]
798e2d4337 Bump moment-timezone from 0.5.34 to 0.5.37 (#5714) 2022-08-25 14:38:27 -07:00
Jesse Mazzella
e3770dc701 [e2e] Enable CORS for CouchDB in CI (#5702) 2022-08-25 12:19:37 -07:00
John Hill
0f12aa1eae Update getting started readme (#5712)
Co-authored-by: John <jchill2@gmail.com>
2022-08-24 14:19:15 -07:00
David Tsay
b786fbb799 Merge branch 'master' into reorder-indicators 2022-08-15 09:51:31 -07:00
David Tsay
2bbfd7fd33 improve add indicator test 2022-08-05 12:19:56 -07:00
David Tsay
f36b2ba3f7 remove debugging statement 2022-07-25 22:13:47 -07:00
David Tsay
c6e147a563 add warning for duplicate key
unit tests
2022-07-25 22:09:09 -07:00
David Tsay
a890b3d9b0 allow priority to be changed 2022-07-25 15:51:30 -07:00
18 changed files with 212 additions and 76 deletions

View File

@@ -17,8 +17,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run : docker-compose up -d -f src/plugins/persistence/couch/couchdb-compose.yaml
- run : sh src/plugins/persistence/couch/setup-couchdb.sh
- run : docker-compose -f src/plugins/persistence/couch/couchdb-compose.yaml up --detach
- run : sleep 3 # wait until CouchDB has started (TODO: there must be a better way)
- run : bash src/plugins/persistence/couch/setup-couchdb.sh
- uses: actions/setup-node@v3
with:
node-version: '16'

4
.gitignore vendored
View File

@@ -36,6 +36,10 @@ report.*.json
test-results
html-test-results
# couchdb scripting artifacts
src/plugins/persistence/couch/.env.local
index.html.bak
# codecov artifacts
.nyc_output
coverage

View File

@@ -23,21 +23,23 @@ If this is your first time ever using the Playwright framework, we recommend goi
Once you've got an understanding of Playwright, you'll need a baseline understanding of Open MCT:
1. Follow the steps [Building and Running Open MCT Locally](../README.md#building-and-running-open-mct-locally)
2. Once you're serving Open MCT locally, create an Example Telemetry Object (e.g.: 'Sine Wave Generator')
2. Once you're serving Open MCT locally, create a 'Display Layout' object. Save it.
3. Create a 'Plot' Object (e.g.: 'Stacked Plot')
4. Expand the Tree on the left-hand nav and drag and drop the Example Telemetry Object into the Plot Object
5. Create a 'Display Layout' object
6. From the Tree, Drag the Plot object into the Display Layout
4. Create an Example Telemetry Object (e.g.: 'Sine Wave Generator')
5. Expand the Tree and note the hierarchy of objects which were created.
6. Navigate to the Demo Display Layout Object to edit and modify the embedded plot.
7. Modify the embedded plot with Telemetry Data.
What you've created is a display which mimics the display that a mission control operator might use to understand and model telemetry data.
Recreate the steps above with Playwright's codegen tool:
1. `npm run start` in a terminal window
2. Open another terminal window and start the Playwright codegen application `npx playwright codegen`
3. Navigate the browser to `http://localhost:8080`
4. Click the Create button and notice how your actions in the browser are being recorded in the Playwright Inspector
5. Continue through the steps 2-6 above
1. `npm run start` in a terminal window to serve Open MCT locally
2. `npx @playwright/test install` to install playwright and dependencies
3. Open another terminal window and start the Playwright codegen application `npx playwright codegen`
4. Navigate the browser to `http://localhost:8080`
5. Click the Create button and notice how your actions in the browser are being recorded in the Playwright Inspector
6. Continue through the steps 2-6 above
What you've created is an automated test which mimics the creation of a mission control display.

View File

@@ -27,6 +27,7 @@ This test suite is dedicated to tests which verify the basic operations surround
// FIXME: Remove this eslint exception once tests are implemented
// eslint-disable-next-line no-unused-vars
const { test, expect } = require('../../../../baseFixtures');
const { createDomainObjectWithDefaults } = require('../../../../appActions');
test.describe('Notebook CRUD Operations', () => {
test.fixme('Can create a Notebook Object', async ({ page }) => {
@@ -67,10 +68,32 @@ test.describe('Default Notebook', () => {
test.describe('Notebook section tests', () => {
//The following test cases are associated with Notebook Sections
test.fixme('New sections are automatically named Unnamed Section with Unnamed Page', async ({ page }) => {
//Create new notebook A
//Add section
//Verify new section and new page details
test.beforeEach(async ({ page }) => {
//Navigate to baseURL
await page.goto('./', { waitUntil: 'networkidle' });
// Create Notebook
await createDomainObjectWithDefaults(page, {
type: 'Notebook',
name: "Test Notebook"
});
});
test('Default and new sections are automatically named Unnamed Section with Unnamed Page', async ({ page }) => {
// Check that the default section and page are created and the name matches the defaults
const defaultSectionName = await page.locator('.c-notebook__sections .c-list__item__name').textContent();
expect(defaultSectionName).toBe('Unnamed Section');
const defaultPageName = await page.locator('.c-notebook__pages .c-list__item__name').textContent();
expect(defaultPageName).toBe('Unnamed Page');
// Expand sidebar and add a section
await page.locator('.c-notebook__toggle-nav-button').click();
await page.locator('.js-sidebar-sections .c-icon-button.icon-plus').click();
// Check that new section and page within the new section match the defaults
const newSectionName = await page.locator('.c-notebook__sections .c-list__item__name').nth(1).textContent();
expect(newSectionName).toBe('Unnamed Section');
const newPageName = await page.locator('.c-notebook__pages .c-list__item__name').textContent();
expect(newPageName).toBe('Unnamed Page');
});
test.fixme('Section selection operations and associated behavior', async ({ page }) => {
//Create new notebook A
@@ -107,6 +130,38 @@ test.describe('Notebook section tests', () => {
test.describe('Notebook page tests', () => {
//The following test cases are associated with Notebook Pages
test.beforeEach(async ({ page }) => {
//Navigate to baseURL
await page.goto('./', { waitUntil: 'networkidle' });
// Create Notebook
await createDomainObjectWithDefaults(page, {
type: 'Notebook',
name: "Test Notebook"
});
});
//Test will need to be implemented after a refactor in #5713
// eslint-disable-next-line playwright/no-skipped-test
test.skip('Delete page popup is removed properly on clicking dropdown again', async ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/nasa/openmct/issues/5713'
});
// Expand sidebar and add a second page
await page.locator('.c-notebook__toggle-nav-button').click();
await page.locator('text=Page Add >> button').click();
// Click on the 2nd page dropdown button and expect the Delete Page option to appear
await page.locator('button[title="Open context menu"]').nth(2).click();
await expect(page.locator('text=Delete Page')).toBeEnabled();
// Clicking on the same page a second time causes the same Delete Page option to recreate
await page.locator('button[title="Open context menu"]').nth(2).click();
await expect(page.locator('text=Delete Page')).toBeEnabled();
// Clicking on the first page causes the first delete button to detach and recreate on the first page
await page.locator('button[title="Open context menu"]').nth(1).click();
const numOfDeletePagePopups = await page.locator('li[title="Delete Page"]').count();
expect(numOfDeletePagePopups).toBe(1);
});
test.fixme('Page selection operations and associated behavior', async ({ page }) => {
//Create new notebook A
//Delete existing Page

View File

@@ -23,7 +23,7 @@
"d3-axis": "3.0.0",
"d3-scale": "3.3.0",
"d3-selection": "3.0.0",
"eslint": "8.22.0",
"eslint": "8.23.0",
"eslint-plugin-compat": "4.0.2",
"eslint-plugin-playwright": "0.11.1",
"eslint-plugin-vue": "9.3.0",
@@ -34,7 +34,7 @@
"git-rev-sync": "3.0.2",
"html2canvas": "1.4.1",
"imports-loader": "4.0.1",
"jasmine-core": "4.3.0",
"jasmine-core": "4.4.0",
"karma": "6.3.20",
"karma-chrome-launcher": "3.1.1",
"karma-cli": "2.0.0",
@@ -50,7 +50,7 @@
"mini-css-extract-plugin": "2.6.1",
"moment": "2.29.4",
"moment-duration-format": "2.3.2",
"moment-timezone": "0.5.34",
"moment-timezone": "0.5.37",
"nyc":"15.1.0",
"painterro": "1.2.78",
"plotly.js-basic-dist": "2.14.0",
@@ -62,7 +62,7 @@
"sass-loader": "13.0.2",
"sinon": "14.0.0",
"style-loader": "^1.0.1",
"uuid": "8.3.2",
"uuid": "9.0.0",
"vue": "2.6.14",
"vue-eslint-parser": "9.0.2",
"vue-loader": "15.9.8",
@@ -93,7 +93,7 @@
"test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome",
"test:e2e:updatesnapshots": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome --grep @snapshot --update-snapshots",
"test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js --grep-invert @unstable",
"test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js",
"test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js --grep-invert @couchdb",
"test:perf": "npx playwright test --config=e2e/playwright-performance.config.js",
"test:watch": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --no-single-run",
"update-about-dialog-copyright": "perl -pi -e 's/20\\d\\d\\-202\\d/2014\\-2022/gm' ./src/ui/layout/AboutDialog.vue",

View File

@@ -37,8 +37,8 @@ class IndicatorAPI extends EventEmitter {
return sortedIndicators;
}
simpleIndicator() {
return new SimpleIndicator(this.openmct);
simpleIndicator(key) {
return new SimpleIndicator(this.openmct, key);
}
/**
@@ -63,6 +63,13 @@ class IndicatorAPI extends EventEmitter {
*
*/
add(indicator) {
const keyExists = indicator.key !== undefined
&& this.indicatorObjects.some(installedIndicator => indicator.key === installedIndicator.key);
if (keyExists) {
console.warn(`An Indicator with key { ${indicator.key} } has already been installed.`);
}
if (!indicator.priority) {
indicator.priority = this.openmct.priority.DEFAULT;
}
@@ -72,6 +79,22 @@ class IndicatorAPI extends EventEmitter {
this.emit('addIndicator', indicator);
}
/**
* @param {string} key the key of the indicator
* @param {number} priority the priority to set
*/
setPriority(key, priority) {
const indicatorToPrioritize = this.indicatorObjects
.find(indicator => indicator.key === key);
if (indicatorToPrioritize !== undefined) {
indicatorToPrioritize.priority = priority;
this.emit('setPriority', indicatorToPrioritize);
} else {
console.warn(`Could not find an installed indicator: ${key}`);
}
}
}
export default IndicatorAPI;

View File

@@ -22,6 +22,8 @@
import { createOpenMct, resetApplicationState } from '../../utils/testing';
import SimpleIndicator from './SimpleIndicator';
const NOTIFICATIONS_INDICATOR_KEY = 'notifications-indicator';
describe("The Indicator API", () => {
let openmct;
@@ -39,6 +41,7 @@ describe("The Indicator API", () => {
const textNode = document.createTextNode(label);
element.appendChild(textNode);
const testIndicator = {
key: className,
element,
priority
};
@@ -46,12 +49,22 @@ describe("The Indicator API", () => {
return testIndicator;
}
it("installs the notifications indicator by default", () => {
let indicators = openmct.indicators.getIndicatorObjectsByPriority();
const notificationIndicator = indicators.find(indicator => indicator.key === NOTIFICATIONS_INDICATOR_KEY);
expect(notificationIndicator.key).toEqual(NOTIFICATIONS_INDICATOR_KEY);
});
it("can register an indicator", () => {
let indicators = openmct.indicators.getIndicatorObjectsByPriority();
const defaultIndicatorsLength = indicators.length;
const testIndicator = generateIndicator('test-indicator', 'This is a test indicator', 2);
openmct.indicators.add(testIndicator);
expect(openmct.indicators.indicatorObjects).toBeDefined();
// notifier indicator is installed by default
expect(openmct.indicators.indicatorObjects.length).toBe(2);
indicators = openmct.indicators.getIndicatorObjectsByPriority();
expect(indicators.length).toBe(defaultIndicatorsLength + 1);
});
it("can order indicators based on priority", () => {
@@ -67,10 +80,32 @@ describe("The Indicator API", () => {
const testIndicator4 = generateIndicator('test-indicator-4', 'This is yet another test indicator', openmct.priority.HIGH);
openmct.indicators.add(testIndicator4);
expect(openmct.indicators.indicatorObjects.length).toBe(5);
const indicatorObjectsByPriority = openmct.indicators.getIndicatorObjectsByPriority();
expect(indicatorObjectsByPriority.length).toBe(5);
expect(indicatorObjectsByPriority[2].priority).toBe(openmct.priority.DEFAULT);
let indicators = openmct.indicators.getIndicatorObjectsByPriority();
expect(indicators.length).toBe(5);
expect(indicators[2].priority).toBe(openmct.priority.DEFAULT);
});
it("can change priority of an installed indicator", () => {
const testIndicator1 = generateIndicator('test-indicator-1', 'This is a test indicator', openmct.priority.LOW);
openmct.indicators.add(testIndicator1);
const testIndicator2 = generateIndicator('test-indicator-2', 'This is another test indicator', openmct.priority.DEFAULT);
openmct.indicators.add(testIndicator2);
const testIndicator3 = generateIndicator('test-indicator-3', 'This is yet another test indicator', openmct.priority.LOW);
openmct.indicators.add(testIndicator3);
const testIndicator4 = generateIndicator('test-indicator-4', 'This is yet another test indicator', openmct.priority.HIGH);
openmct.indicators.add(testIndicator4);
let indicators = openmct.indicators.getIndicatorObjectsByPriority();
expect(indicators[0].key).toEqual('test-indicator-4');
openmct.indicators.setPriority('test-indicator-2', openmct.priority.HIGH + 1);
indicators = openmct.indicators.getIndicatorObjectsByPriority();
expect(indicators[0].key).toEqual('test-indicator-2');
});
it("the simple indicator can be added", () => {

View File

@@ -27,10 +27,11 @@ import { convertTemplateToHTML } from '@/utils/template/templateHelpers';
const DEFAULT_ICON_CLASS = 'icon-info';
class SimpleIndicator extends EventEmitter {
constructor(openmct) {
constructor(openmct, key) {
super();
this.openmct = openmct;
this.key = key;
this.element = convertTemplateToHTML(indicatorTemplate)[0];
this.priority = openmct.priority.DEFAULT;

View File

@@ -23,7 +23,7 @@ define(['./URLIndicator'],
function URLIndicatorPlugin(URLIndicator) {
return function (opts) {
return function install(openmct) {
const simpleIndicator = openmct.indicators.simpleIndicator();
const simpleIndicator = openmct.indicators.simpleIndicator('url-indicator');
const urlIndicator = new URLIndicator(opts, simpleIndicator);
openmct.indicators.add(simpleIndicator);

View File

@@ -56,85 +56,76 @@ describe("The URLTimeSettingsSynchronizer", () => {
it("initial clock is set to fixed is reflected in URL", (done) => {
resolveFunction = () => {
oldHash = window.location.hash;
expect(window.location.hash.includes('tc.mode=fixed')).toBe(true);
expect(window.location.hash).toContain('tc.mode=fixed');
openmct.router.removeListener('change:hash', resolveFunction);
done();
};
// We have a debounce set to 300ms on setHash, so if we don't flush,
// the above resolve function sometimes doesn't fire due to a race condition.
openmct.router.setHash.flush();
openmct.router.on('change:hash', resolveFunction);
});
it("when the clock is set via the time API, it is reflected in the URL", (done) => {
let success;
resolveFunction = () => {
openmct.time.clock('local', {
start: -2000,
end: 200
});
const hasStartDelta = window.location.hash.includes('tc.startDelta=2000');
const hasEndDelta = window.location.hash.includes('tc.endDelta=200');
const hasLocalClock = window.location.hash.includes('tc.mode=local');
success = hasStartDelta && hasEndDelta && hasLocalClock;
if (success) {
expect(success).toBe(true);
openmct.router.removeListener('change:hash', resolveFunction);
done();
}
openmct.router.setHash.flush();
const urlHash = window.location.hash;
expect(urlHash).toContain('tc.startDelta=2000');
expect(urlHash).toContain('tc.endDelta=200');
expect(urlHash).toContain('tc.mode=local');
openmct.router.removeListener('change:hash', resolveFunction);
done();
};
// We have a debounce set to 300ms on setHash, so if we don't flush,
// the above resolve function sometimes doesn't fire due to a race condition.
openmct.router.setHash.flush();
openmct.router.on('change:hash', resolveFunction);
});
it("when the clock mode is set to local, it is reflected in the URL", (done) => {
let success;
resolveFunction = () => {
let hash = window.location.hash;
hash = hash.replace('tc.mode=fixed', 'tc.mode=local');
window.location.hash = hash;
success = window.location.hash.includes('tc.mode=local');
if (success) {
expect(success).toBe(true);
done();
}
expect(window.location.hash).toContain('tc.mode=local');
done();
};
// We have a debounce set to 300ms on setHash, so if we don't flush,
// the above resolve function sometimes doesn't fire due to a race condition.
openmct.router.setHash.flush();
openmct.router.on('change:hash', resolveFunction);
});
it("when the clock mode is set to local, it is reflected in the URL", (done) => {
let success;
resolveFunction = () => {
let hash = window.location.hash;
hash = hash.replace('tc.mode=fixed', 'tc.mode=local');
window.location.hash = hash;
success = window.location.hash.includes('tc.mode=local');
if (success) {
expect(success).toBe(true);
done();
}
expect(window.location.hash).toContain('tc.mode=local');
done();
};
// We have a debounce set to 300ms on setHash, so if we don't flush,
// the above resolve function sometimes doesn't fire due to a race condition.
openmct.router.setHash.flush();
openmct.router.on('change:hash', resolveFunction);
});
it("reset hash", (done) => {
let success;
window.location.hash = oldHash;
resolveFunction = () => {
success = window.location.hash === oldHash;
if (success) {
expect(success).toBe(true);
done();
}
expect(window.location.hash).toBe(oldHash);
done();
};
openmct.router.on('change:hash', resolveFunction);

View File

@@ -1,7 +1,7 @@
<template>
<button
class="c-popup-menu-button c-disclosure-button"
title="popup menu"
title="Open context menu"
@click="showMenuItems"
>
</button>
@@ -65,6 +65,10 @@ export default {
return;
},
showMenuItems($event) {
if (this.menuItems) {
this.hideMenuItems();
}
const menuItems = new Vue({
components: {
MenuItems

View File

@@ -49,7 +49,7 @@ export default class OperatorStatusIndicator extends AbstractStatusIndicator {
}
createIndicator() {
const operatorIndicator = this.openmct.indicators.simpleIndicator();
const operatorIndicator = this.openmct.indicators.simpleIndicator('operator-indicator');
operatorIndicator.text("My Operator Status");
operatorIndicator.description("Set my operator status");

View File

@@ -49,7 +49,7 @@ export default class PollQuestionIndicator extends AbstractStatusIndicator {
}
createIndicator() {
const pollQuestionIndicator = this.openmct.indicators.simpleIndicator();
const pollQuestionIndicator = this.openmct.indicators.simpleIndicator('poll-question-indicator');
pollQuestionIndicator.text("Poll Question");
pollQuestionIndicator.description("Set the current poll question");

View File

@@ -23,7 +23,7 @@ export default function PerformanceIndicator() {
return function install(openmct) {
let frames = 0;
let lastCalculated = performance.now();
const indicator = openmct.indicators.simpleIndicator();
const indicator = openmct.indicators.simpleIndicator('performance-indicator');
indicator.text('~ fps');
indicator.statusClass('s-status-info');

View File

@@ -30,7 +30,7 @@ const COUCH_SEARCH_ONLY_NAMESPACE = `COUCH_SEARCH_${Date.now()}`;
export default function CouchPlugin(options) {
return function install(openmct) {
const simpleIndicator = openmct.indicators.simpleIndicator();
const simpleIndicator = openmct.indicators.simpleIndicator('couch-indicator');
openmct.indicators.add(simpleIndicator);
const couchStatusIndicator = new CouchStatusIndicator(simpleIndicator);
install.couchProvider = new CouchObjectProvider(openmct, options, NAMESPACE, couchStatusIndicator);

15
src/plugins/persistence/couch/setup-couchdb.sh Normal file → Executable file
View File

@@ -83,9 +83,13 @@ create_admin_user () {
curl -X PUT $COUCH_BASE_LOCAL/_node/$COUCH_NODE_NAME/_config/admins/$COUCH_ADMIN_USER -d \'"$COUCH_ADMIN_PASSWORD"\'
}
is_cors_enabled() {
resource_exists $COUCH_BASE_LOCAL/_node/$COUCH_NODE_NAME/_config/httpd/enable_cors
}
enable_cors () {
curl -su "${CURL_USERPASS_ARG}" -o /dev/null -X PUT $COUCH_BASE_LOCAL/_node/$COUCH_NODE_NAME/_config/httpd/enable_cors -d '"true"'
curl -su "${CURL_USERPASS_ARG}" -o /dev/null -X PUT $COUCH_BASE_LOCAL/_node/$COUCH_NODE_NAME/_config/cors/origins -d '"http://localhost:8080"'
curl -su "${CURL_USERPASS_ARG}" -o /dev/null -X PUT $COUCH_BASE_LOCAL/_node/$COUCH_NODE_NAME/_config/cors/origins -d '"*"'
curl -su "${CURL_USERPASS_ARG}" -o /dev/null -X PUT $COUCH_BASE_LOCAL/_node/$COUCH_NODE_NAME/_config/cors/credentials -d '"true"'
curl -su "${CURL_USERPASS_ARG}" -o /dev/null -X PUT $COUCH_BASE_LOCAL/_node/$COUCH_NODE_NAME/_config/cors/methods -d '"GET, PUT, POST, HEAD, DELETE"'
curl -su "${CURL_USERPASS_ARG}" -o /dev/null -X PUT $COUCH_BASE_LOCAL/_node/$COUCH_NODE_NAME/_config/cors/headers -d '"accept, authorization, content-type, origin, referer, x-csrf-token"'
@@ -132,6 +136,9 @@ else
echo "Database permissions not updated"
fi
echo "Enabling CORS"
enable_cors
echo "CORS successfully enabled"
if [ "FALSE" == $(is_cors_enabled) ]; then
echo "Enabling CORS"
enable_cors
else
echo "CORS enabled, nothing to do"
fi

View File

@@ -95,6 +95,11 @@ export default {
},
getPathsForObjects(objectsNeedingPaths) {
return Promise.all(objectsNeedingPaths.map(async (domainObject) => {
if (!domainObject) {
// user interrupted search, return back
return null;
}
const keyStringForObject = this.openmct.objects.makeKeyString(domainObject.identifier);
const originalPathObjects = await this.openmct.objects.getOriginalPath(keyStringForObject);
@@ -127,12 +132,17 @@ export default {
this.searchLoading = false;
this.showSearchResults();
} catch (error) {
console.error(`😞 Error searching`, error);
this.searchLoading = false;
if (this.abortSearchController) {
delete this.abortSearchController;
}
// Is this coming from the AbortController?
// If so, we can swallow the error. If not, 🤮 it to console
if (error.name !== 'AbortError') {
console.error(`😞 Error searching`, error);
}
}
},
showSearchResults() {

View File

@@ -28,6 +28,9 @@ describe('Application router utility functions', () => {
};
openmct.router.on('change:hash', resolveFunction);
// We have a debounce set to 300ms on setHash, so if we don't flush,
// the above resolve function sometimes doesn't fire due to a race condition.
openmct.router.setHash.flush();
openmct.router.setLocationFromUrl();
});