Mct4170 - Give indicators priorities (#4322)

* added priority api with an enum for sane priority defaults
openmct.priority.LOW: -1000. Should always run last.
openmct.priority.DEFAULT: 0. This is the default unless you specify something else.
openmct.priority.HIGH: 1000. Should always run first.

* allow indicators to be sorted by priority
This commit is contained in:
Scott Bell 2021-10-25 23:24:03 +02:00 committed by GitHub
parent c0bda64927
commit a908eb1d65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 125 additions and 105 deletions

View File

@ -253,6 +253,8 @@ define([
this.status = new api.StatusAPI(this);
this.priority = api.PriorityAPI;
this.router = new ApplicationRouter(this);
this.branding = BrandingAPI.default;

View File

@ -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
};
});

View File

@ -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);
};

View File

@ -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 () {
describe("The Indicator API", () => {
let openmct;
let directive;
let holderElement;
beforeEach(function () {
openmct = new MCT();
directive = new MCTIndicators(openmct);
holderElement = document.createElement('div');
beforeEach(() => {
openmct = createOpenMct();
});
describe("The simple indicator", function () {
let simpleIndicator;
afterEach(() => {
return resetApplicationState(openmct);
});
beforeEach(function () {
simpleIndicator = openmct.indicators.simpleIndicator();
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);
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);
}
});
expect(openmct.indicators.indicatorObjects.length).toBe(2);
});
});

View File

@ -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');

View File

@ -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;

View File

@ -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);

View File

@ -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();
});

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);
});
}