diff --git a/src/MCT.js b/src/MCT.js index 352d103e63..6d341ada6f 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -253,6 +253,8 @@ define([ this.status = new api.StatusAPI(this); + this.priority = api.PriorityAPI; + this.router = new ApplicationRouter(this); this.branding = BrandingAPI.default; diff --git a/src/api/api.js b/src/api/api.js index f3f7db28cd..b2734125ca 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -31,7 +31,8 @@ define([ './Editor', './menu/MenuAPI', './actions/ActionsAPI', - './status/StatusAPI' + './status/StatusAPI', + './priority/PriorityAPI' ], function ( TimeAPI, ObjectAPI, @@ -43,7 +44,8 @@ define([ EditorAPI, MenuAPI, ActionsAPI, - StatusAPI + StatusAPI, + PriorityAPI ) { return { TimeAPI: TimeAPI.default, @@ -56,6 +58,7 @@ define([ EditorAPI: EditorAPI, MenuAPI: MenuAPI.default, ActionsAPI: ActionsAPI.default, - StatusAPI: StatusAPI.default + StatusAPI: StatusAPI.default, + PriorityAPI: PriorityAPI.default }; }); diff --git a/src/api/indicators/IndicatorAPI.js b/src/api/indicators/IndicatorAPI.js index c89b8cc5ed..67779dd2b4 100644 --- a/src/api/indicators/IndicatorAPI.js +++ b/src/api/indicators/IndicatorAPI.js @@ -31,14 +31,22 @@ define([ this.indicatorObjects = []; } + IndicatorAPI.prototype.getIndicatorObjectsByPriority = function () { + const sortedIndicators = this.indicatorObjects.sort((a, b) => b.priority - a.priority); + + return sortedIndicators; + }; + IndicatorAPI.prototype.simpleIndicator = function () { return new SimpleIndicator(this.openmct); }; /** * Accepts an indicator object, which is a simple object - * with a single attribute, 'element' which has an HTMLElement - * as its value. + * with a two attributes: 'element' which has an HTMLElement + * as its value, and 'priority' with an integer that specifies its order in the layout. + * The lower the priority, the further to the right the element is placed. + * If undefined, the priority will be assigned -1. * * We provide .simpleIndicator() as a convenience function * which will create a default Open MCT indicator that can @@ -47,7 +55,7 @@ define([ * and dynamic behavior. * * Eg. - * var myIndicator = openmct.indicators.simpleIndicator(); + * const myIndicator = openmct.indicators.simpleIndicator(); * openmct.indicators.add(myIndicator); * * myIndicator.text("Hello World!"); @@ -55,6 +63,10 @@ define([ * */ IndicatorAPI.prototype.add = function (indicator) { + if (!indicator.priority) { + indicator.priority = this.openmct.priority.DEFAULT; + } + this.indicatorObjects.push(indicator); }; diff --git a/src/api/indicators/IndicatorAPISpec.js b/src/api/indicators/IndicatorAPISpec.js index 6b05bc55b9..42a8a49e3c 100644 --- a/src/api/indicators/IndicatorAPISpec.js +++ b/src/api/indicators/IndicatorAPISpec.js @@ -19,97 +19,64 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ +import { createOpenMct, resetApplicationState } from '../../utils/testing'; +import SimpleIndicator from './SimpleIndicator'; -define( - [ - "../../MCT", - "../../../platform/commonUI/general/src/directives/MCTIndicators" - ], - function ( - MCT, - MCTIndicators - ) { - xdescribe("The Indicator API", function () { - let openmct; - let directive; - let holderElement; +describe("The Indicator API", () => { + let openmct; - beforeEach(function () { - openmct = new MCT(); - directive = new MCTIndicators(openmct); - holderElement = document.createElement('div'); - }); - - describe("The simple indicator", function () { - let simpleIndicator; - - beforeEach(function () { - simpleIndicator = openmct.indicators.simpleIndicator(); - openmct.indicators.add(simpleIndicator); - renderIndicators(); - }); - - it("applies the set icon class", function () { - simpleIndicator.iconClass('testIconClass'); - - expect(getIconElement().classList.contains('testIconClass')).toBe(true); - - simpleIndicator.iconClass('anotherIconClass'); - expect(getIconElement().classList.contains('testIconClass')).toBe(false); - expect(getIconElement().classList.contains('anotherIconClass')).toBe(true); - }); - - it("applies the set status class", function () { - simpleIndicator.statusClass('testStatusClass'); - - expect(getIconElement().classList.contains('testStatusClass')).toBe(true); - simpleIndicator.statusClass('anotherStatusClass'); - expect(getIconElement().classList.contains('testStatusClass')).toBe(false); - expect(getIconElement().classList.contains('anotherStatusClass')).toBe(true); - }); - - it("displays the set text", function () { - simpleIndicator.text('some test text'); - expect(getTextElement().textContent.trim()).toEqual('some test text'); - }); - - it("sets the indicator's title", function () { - simpleIndicator.description('a test description'); - expect(getIndicatorElement().getAttribute('title')).toEqual('a test description'); - }); - - it("Hides indicator icon if no text is set", function () { - simpleIndicator.text(''); - expect(getIndicatorElement().classList.contains('hidden')).toBe(true); - }); - - function getIconElement() { - return holderElement.querySelector('.ls-indicator'); - } - - function getIndicatorElement() { - return holderElement.querySelector('.ls-indicator'); - } - - function getTextElement() { - return holderElement.querySelector('.indicator-text'); - } - }); - - it("Supports registration of a completely custom indicator", function () { - const customIndicator = document.createElement('div'); - customIndicator.classList.add('customIndicator'); - customIndicator.textContent = 'A custom indicator'; - - openmct.indicators.add({element: customIndicator}); - renderIndicators(); - - expect(holderElement.querySelector('.customIndicator').textContent.trim()).toEqual('A custom indicator'); - }); - - function renderIndicators() { - directive.link({}, holderElement); - } - - }); + beforeEach(() => { + openmct = createOpenMct(); }); + + afterEach(() => { + return resetApplicationState(openmct); + }); + + function generateIndicator(className, label, priority) { + const element = document.createElement('div'); + element.classList.add(className); + const textNode = document.createTextNode(label); + element.appendChild(textNode); + const testIndicator = { + element, + priority + }; + + return testIndicator; + } + + it("can register an indicator", () => { + 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); + }); + + it("can order indicators based on priority", () => { + 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); + + 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); + }); + + it("the simple indicator can be added", () => { + const simpleIndicator = new SimpleIndicator(openmct); + openmct.indicators.add(simpleIndicator); + + expect(openmct.indicators.indicatorObjects.length).toBe(2); + }); +}); diff --git a/src/api/indicators/SimpleIndicator.js b/src/api/indicators/SimpleIndicator.js index 5256f1b94e..b610e7d096 100644 --- a/src/api/indicators/SimpleIndicator.js +++ b/src/api/indicators/SimpleIndicator.js @@ -27,6 +27,7 @@ define(['zepto', './res/indicator-template.html'], function SimpleIndicator(openmct) { this.openmct = openmct; this.element = $(indicatorTemplate)[0]; + this.priority = openmct.priority.DEFAULT; this.textElement = this.element.querySelector('.js-indicator-text'); diff --git a/src/api/priority/PriorityAPI.js b/src/api/priority/PriorityAPI.js new file mode 100644 index 0000000000..d0401a11ae --- /dev/null +++ b/src/api/priority/PriorityAPI.js @@ -0,0 +1,28 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, 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. + *****************************************************************************/ + +const PRIORITIES = Object.freeze({ + HIGH: 1000, + DEFAULT: 0, + LOW: -1000 +}); +export default PRIORITIES; diff --git a/src/plugins/clearData/plugin.js b/src/plugins/clearData/plugin.js index 34b31c7018..65279b0801 100644 --- a/src/plugins/clearData/plugin.js +++ b/src/plugins/clearData/plugin.js @@ -47,7 +47,9 @@ define([ }); let indicator = { - element: component.$mount().$el + element: component.$mount().$el, + key: 'clear-data-indicator', + priority: openmct.priority.DEFAULT }; openmct.indicators.add(indicator); diff --git a/src/plugins/clearData/test/ClearDataActionSpec.js b/src/plugins/clearData/test/ClearDataActionSpec.js index ce68f69507..022d37d942 100644 --- a/src/plugins/clearData/test/ClearDataActionSpec.js +++ b/src/plugins/clearData/test/ClearDataActionSpec.js @@ -41,6 +41,9 @@ describe('When the Clear Data Plugin is installed,', () => { const openmct = { objectViews: mockObjectViews, indicators: mockIndicatorProvider, + priority: { + DEFAULT: 0 + }, actions: mockActionsProvider, install: function (plugin) { plugin(this); @@ -69,13 +72,13 @@ describe('When the Clear Data Plugin is installed,', () => { ]; it('Global Clear Indicator is installed', () => { - openmct.install(ClearDataActionPlugin([])); + openmct.install(ClearDataActionPlugin(openmct, {indicator: true})); expect(mockIndicatorProvider.add).toHaveBeenCalled(); }); it('Clear Data context menu action is installed', () => { - openmct.install(ClearDataActionPlugin([])); + openmct.install(ClearDataActionPlugin(openmct, [])); expect(mockActionsProvider.register).toHaveBeenCalled(); }); diff --git a/src/plugins/clock/plugin.js b/src/plugins/clock/plugin.js index 31d122d5d0..15424bb1c8 100644 --- a/src/plugins/clock/plugin.js +++ b/src/plugins/clock/plugin.js @@ -116,7 +116,8 @@ export default function ClockPlugin(options) { }); const indicator = { element: clockIndicator.$mount().$el, - key: 'clock-indicator' + key: 'clock-indicator', + priority: openmct.priority.LOW }; openmct.indicators.add(indicator); diff --git a/src/plugins/notebook/plugin.js b/src/plugins/notebook/plugin.js index 3ec561a1c1..56a61b8d34 100644 --- a/src/plugins/notebook/plugin.js +++ b/src/plugins/notebook/plugin.js @@ -114,7 +114,8 @@ export default function NotebookPlugin() { }); const indicator = { element: notebookSnapshotIndicator.$mount().$el, - key: 'notebook-snapshot-indicator' + key: 'notebook-snapshot-indicator', + priority: openmct.priority.DEFAULT }; openmct.indicators.add(indicator); diff --git a/src/plugins/notificationIndicator/plugin.js b/src/plugins/notificationIndicator/plugin.js index 0bace12140..629fcc4348 100644 --- a/src/plugins/notificationIndicator/plugin.js +++ b/src/plugins/notificationIndicator/plugin.js @@ -36,7 +36,8 @@ export default function plugin() { let indicator = { key: 'notifications-indicator', - element: component.$mount().$el + element: component.$mount().$el, + priority: openmct.priority.DEFAULT }; openmct.indicators.add(indicator); diff --git a/src/ui/layout/layout.scss b/src/ui/layout/layout.scss index 19980a95b3..d4c28ce15e 100644 --- a/src/ui/layout/layout.scss +++ b/src/ui/layout/layout.scss @@ -224,7 +224,6 @@ flex: 1 1 auto; flex-wrap: wrap; justify-content: flex-end; - [class*='indicator-clock'] { order: 90; } .c-indicator .label { font-size: 0.9em; diff --git a/src/ui/layout/status-bar/Indicators.vue b/src/ui/layout/status-bar/Indicators.vue index c37d7c5e7c..bbdd3f1520 100644 --- a/src/ui/layout/status-bar/Indicators.vue +++ b/src/ui/layout/status-bar/Indicators.vue @@ -25,7 +25,7 @@ export default { inject: ['openmct'], mounted() { - this.openmct.indicators.indicatorObjects.forEach((indicator) => { + this.openmct.indicators.getIndicatorObjectsByPriority().forEach((indicator) => { this.$el.appendChild(indicator.element); }); }