Compare commits
1 Commits
non-editab
...
save-as-pn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ae61720da |
@@ -182,7 +182,7 @@ The following guidelines are provided for anyone contributing source code to the
|
||||
1. Avoid the use of "magic" values.
|
||||
eg.
|
||||
```JavaScript
|
||||
const UNAUTHORIZED = 401;
|
||||
Const UNAUTHORIZED = 401
|
||||
if (responseCode === UNAUTHORIZED)
|
||||
```
|
||||
is preferable to
|
||||
|
||||
@@ -131,10 +131,10 @@
|
||||
}
|
||||
],
|
||||
// maximum recent bounds to retain in conductor history
|
||||
records: 10
|
||||
records: 10,
|
||||
// maximum duration between start and end bounds
|
||||
// for utc-based time systems this is in milliseconds
|
||||
// limit: ONE_DAY
|
||||
limit: ONE_DAY
|
||||
},
|
||||
{
|
||||
name: "Realtime",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openmct",
|
||||
"version": "1.5.0-SNAPSHOT",
|
||||
"version": "1.4.1-SNAPSHOT",
|
||||
"description": "The Open MCT core platform",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, 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 ActionCollection from './ActionCollection';
|
||||
import { createOpenMct, resetApplicationState } from '../../utils/testing';
|
||||
|
||||
describe('The ActionCollection', () => {
|
||||
let openmct;
|
||||
let actionCollection;
|
||||
let mockApplicableActions;
|
||||
let mockObjectPath;
|
||||
let mockView;
|
||||
|
||||
beforeEach(() => {
|
||||
openmct = createOpenMct();
|
||||
mockObjectPath = [
|
||||
{
|
||||
name: 'mock folder',
|
||||
type: 'fake-folder',
|
||||
identifier: {
|
||||
key: 'mock-folder',
|
||||
namespace: ''
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'mock parent folder',
|
||||
type: 'fake-folder',
|
||||
identifier: {
|
||||
key: 'mock-parent-folder',
|
||||
namespace: ''
|
||||
}
|
||||
}
|
||||
];
|
||||
mockView = {
|
||||
getViewContext: () => {
|
||||
return {
|
||||
onlyAppliesToTestCase: true
|
||||
};
|
||||
}
|
||||
};
|
||||
mockApplicableActions = {
|
||||
'test-action-object-path': {
|
||||
name: 'Test Action Object Path',
|
||||
key: 'test-action-object-path',
|
||||
cssClass: 'test-action-object-path',
|
||||
description: 'This is a test action for object path',
|
||||
group: 'action',
|
||||
priority: 9,
|
||||
appliesTo: (objectPath) => {
|
||||
if (objectPath.length) {
|
||||
return objectPath[0].type === 'fake-folder';
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
invoke: () => {
|
||||
}
|
||||
},
|
||||
'test-action-view': {
|
||||
name: 'Test Action View',
|
||||
key: 'test-action-view',
|
||||
cssClass: 'test-action-view',
|
||||
description: 'This is a test action for view',
|
||||
group: 'action',
|
||||
priority: 9,
|
||||
showInStatusBar: true,
|
||||
appliesTo: (objectPath, view = {}) => {
|
||||
if (view.getViewContext) {
|
||||
let viewContext = view.getViewContext();
|
||||
|
||||
return viewContext.onlyAppliesToTestCase;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
invoke: () => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
actionCollection = new ActionCollection(mockApplicableActions, mockObjectPath, mockView, openmct);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
actionCollection.destroy();
|
||||
resetApplicationState(openmct);
|
||||
});
|
||||
|
||||
describe("disable method invoked with action keys", () => {
|
||||
it("marks those actions as isDisabled", () => {
|
||||
let actionKey = 'test-action-object-path';
|
||||
let actionsObject = actionCollection.getActionsObject();
|
||||
let action = actionsObject[actionKey];
|
||||
|
||||
expect(action.isDisabled).toBeFalsy();
|
||||
|
||||
actionCollection.disable([actionKey]);
|
||||
actionsObject = actionCollection.getActionsObject();
|
||||
action = actionsObject[actionKey];
|
||||
|
||||
expect(action.isDisabled).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe("enable method invoked with action keys", () => {
|
||||
it("marks the isDisabled property as false", () => {
|
||||
let actionKey = 'test-action-object-path';
|
||||
|
||||
actionCollection.disable([actionKey]);
|
||||
|
||||
let actionsObject = actionCollection.getActionsObject();
|
||||
let action = actionsObject[actionKey];
|
||||
|
||||
expect(action.isDisabled).toBeTrue();
|
||||
|
||||
actionCollection.enable([actionKey]);
|
||||
actionsObject = actionCollection.getActionsObject();
|
||||
action = actionsObject[actionKey];
|
||||
|
||||
expect(action.isDisabled).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe("hide method invoked with action keys", () => {
|
||||
it("marks those actions as isHidden", () => {
|
||||
let actionKey = 'test-action-object-path';
|
||||
let actionsObject = actionCollection.getActionsObject();
|
||||
let action = actionsObject[actionKey];
|
||||
|
||||
expect(action.isHidden).toBeFalsy();
|
||||
|
||||
actionCollection.hide([actionKey]);
|
||||
actionsObject = actionCollection.getActionsObject();
|
||||
action = actionsObject[actionKey];
|
||||
|
||||
expect(action.isHidden).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe("show method invoked with action keys", () => {
|
||||
it("marks the isHidden property as false", () => {
|
||||
let actionKey = 'test-action-object-path';
|
||||
|
||||
actionCollection.hide([actionKey]);
|
||||
|
||||
let actionsObject = actionCollection.getActionsObject();
|
||||
let action = actionsObject[actionKey];
|
||||
|
||||
expect(action.isHidden).toBeTrue();
|
||||
|
||||
actionCollection.show([actionKey]);
|
||||
actionsObject = actionCollection.getActionsObject();
|
||||
action = actionsObject[actionKey];
|
||||
|
||||
expect(action.isHidden).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getVisibleActions method", () => {
|
||||
it("returns an array of non hidden actions", () => {
|
||||
let action1Key = 'test-action-object-path';
|
||||
let action2Key = 'test-action-view';
|
||||
|
||||
actionCollection.hide([action1Key]);
|
||||
|
||||
let visibleActions = actionCollection.getVisibleActions();
|
||||
|
||||
expect(Array.isArray(visibleActions)).toBeTrue();
|
||||
expect(visibleActions.length).toEqual(1);
|
||||
expect(visibleActions[0].key).toEqual(action2Key);
|
||||
|
||||
actionCollection.show([action1Key]);
|
||||
visibleActions = actionCollection.getVisibleActions();
|
||||
|
||||
expect(visibleActions.length).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getStatusBarActions method", () => {
|
||||
it("returns an array of non disabled, non hidden statusBar actions", () => {
|
||||
let action2Key = 'test-action-view';
|
||||
|
||||
let statusBarActions = actionCollection.getStatusBarActions();
|
||||
|
||||
expect(Array.isArray(statusBarActions)).toBeTrue();
|
||||
expect(statusBarActions.length).toEqual(1);
|
||||
expect(statusBarActions[0].key).toEqual(action2Key);
|
||||
|
||||
actionCollection.disable([action2Key]);
|
||||
statusBarActions = actionCollection.getStatusBarActions();
|
||||
|
||||
expect(statusBarActions.length).toEqual(0);
|
||||
|
||||
actionCollection.enable([action2Key]);
|
||||
statusBarActions = actionCollection.getStatusBarActions();
|
||||
|
||||
expect(statusBarActions.length).toEqual(1);
|
||||
expect(statusBarActions[0].key).toEqual(action2Key);
|
||||
|
||||
actionCollection.hide([action2Key]);
|
||||
statusBarActions = actionCollection.getStatusBarActions();
|
||||
|
||||
expect(statusBarActions.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -22,41 +22,22 @@
|
||||
|
||||
import ActionsAPI from './ActionsAPI';
|
||||
import { createOpenMct, resetApplicationState } from '../../utils/testing';
|
||||
import ActionCollection from './ActionCollection';
|
||||
|
||||
describe('The Actions API', () => {
|
||||
let openmct;
|
||||
let actionsAPI;
|
||||
let mockAction;
|
||||
let mockObjectPath;
|
||||
let mockObjectPathAction;
|
||||
let mockViewContext1;
|
||||
|
||||
beforeEach(() => {
|
||||
openmct = createOpenMct();
|
||||
actionsAPI = new ActionsAPI(openmct);
|
||||
mockObjectPathAction = {
|
||||
name: 'Test Action Object Path',
|
||||
key: 'test-action-object-path',
|
||||
cssClass: 'test-action-object-path',
|
||||
description: 'This is a test action for object path',
|
||||
group: 'action',
|
||||
priority: 9,
|
||||
appliesTo: (objectPath) => {
|
||||
if (objectPath.length) {
|
||||
return objectPath[0].type === 'fake-folder';
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
invoke: () => {
|
||||
}
|
||||
};
|
||||
mockAction = {
|
||||
name: 'Test Action View',
|
||||
key: 'test-action-view',
|
||||
cssClass: 'test-action-view',
|
||||
description: 'This is a test action for view',
|
||||
name: 'Test Action',
|
||||
key: 'test-action',
|
||||
cssClass: 'test-action',
|
||||
description: 'This is a test action',
|
||||
group: 'action',
|
||||
priority: 9,
|
||||
appliesTo: (objectPath, view = {}) => {
|
||||
@@ -64,6 +45,8 @@ describe('The Actions API', () => {
|
||||
let viewContext = view.getViewContext();
|
||||
|
||||
return viewContext.onlyAppliesToTestCase;
|
||||
} else if (objectPath.length) {
|
||||
return objectPath[0].type === 'fake-folder';
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -117,32 +100,9 @@ describe('The Actions API', () => {
|
||||
describe("get method", () => {
|
||||
beforeEach(() => {
|
||||
actionsAPI.register(mockAction);
|
||||
actionsAPI.register(mockObjectPathAction);
|
||||
});
|
||||
|
||||
it("returns an ActionCollection when invoked with an objectPath only", () => {
|
||||
let actionCollection = actionsAPI.get(mockObjectPath);
|
||||
let instanceOfActionCollection = actionCollection instanceof ActionCollection;
|
||||
|
||||
expect(instanceOfActionCollection).toBeTrue();
|
||||
});
|
||||
|
||||
it("returns an ActionCollection when invoked with an objectPath and view", () => {
|
||||
let actionCollection = actionsAPI.get(mockObjectPath, mockViewContext1);
|
||||
let instanceOfActionCollection = actionCollection instanceof ActionCollection;
|
||||
|
||||
expect(instanceOfActionCollection).toBeTrue();
|
||||
});
|
||||
|
||||
it("returns relevant actions when invoked with objectPath only", () => {
|
||||
let actionCollection = actionsAPI.get(mockObjectPath);
|
||||
let action = actionCollection.getActionsObject()[mockObjectPathAction.key];
|
||||
|
||||
expect(action.key).toEqual(mockObjectPathAction.key);
|
||||
expect(action.name).toEqual(mockObjectPathAction.name);
|
||||
});
|
||||
|
||||
it("returns relevant actions when invoked with objectPath and view", () => {
|
||||
it("returns an object with relevant actions when invoked with objectPath only", () => {
|
||||
let actionCollection = actionsAPI.get(mockObjectPath, mockViewContext1);
|
||||
let action = actionCollection.getActionsObject()[mockAction.key];
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
import { createOpenMct, resetApplicationState } from "utils/testing";
|
||||
import ConditionPlugin from "./plugin";
|
||||
import stylesManager from '@/ui/inspector/styles/StylesManager';
|
||||
import StylesView from "./components/inspector/StylesView.vue";
|
||||
import Vue from 'vue';
|
||||
import {getApplicableStylesForItem} from "./utils/styleUtils";
|
||||
@@ -403,8 +402,7 @@ describe('the plugin', function () {
|
||||
component = new Vue({
|
||||
provide: {
|
||||
openmct: openmct,
|
||||
selection: selection,
|
||||
stylesManager
|
||||
selection: selection
|
||||
},
|
||||
el: viewContainer,
|
||||
components: {
|
||||
|
||||
@@ -233,9 +233,8 @@ export default {
|
||||
formattedValueForCopy() {
|
||||
const timeFormatterKey = this.openmct.time.timeSystem().key;
|
||||
const timeFormatter = this.formats[timeFormatterKey];
|
||||
const unit = this.unit ? ` ${this.unit}` : '';
|
||||
|
||||
return `At ${timeFormatter.format(this.datum)} ${this.domainObject.name} had a value of ${this.telemetryValue}${unit}`;
|
||||
return `At ${timeFormatter.format(this.datum)} ${this.domainObject.name} had a value of ${this.telemetryValue} ${this.unit}`;
|
||||
},
|
||||
requestHistoricalData() {
|
||||
let bounds = this.openmct.time.bounds();
|
||||
|
||||
@@ -89,7 +89,7 @@ export default class DuplicateAction {
|
||||
{
|
||||
key: "name",
|
||||
control: "textfield",
|
||||
name: "Name",
|
||||
name: "Folder Name",
|
||||
pattern: "\\S+",
|
||||
required: true,
|
||||
cssClass: "l-input-lg"
|
||||
|
||||
@@ -48,14 +48,13 @@ export default class DuplicateTask {
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the duplicate/copy task with the objects provided.
|
||||
* Execute the duplicate/copy task with the objects provided in the constructor.
|
||||
* @returns {promise} Which will resolve with a clone of the object
|
||||
* once complete.
|
||||
*/
|
||||
async duplicate(domainObject, parent, filter) {
|
||||
this.domainObject = domainObject;
|
||||
this.parent = parent;
|
||||
this.namespace = parent.identifier.namespace;
|
||||
this.filter = filter || this.isCreatable;
|
||||
|
||||
await this.buildDuplicationPlan();
|
||||
@@ -79,9 +78,8 @@ export default class DuplicateTask {
|
||||
*/
|
||||
async buildDuplicationPlan() {
|
||||
let domainObjectClone = await this.duplicateObject(this.domainObject);
|
||||
|
||||
if (domainObjectClone !== this.domainObject) {
|
||||
domainObjectClone.location = this.getKeyString(this.parent);
|
||||
domainObjectClone.location = this.getId(this.parent);
|
||||
}
|
||||
|
||||
this.firstClone = domainObjectClone;
|
||||
@@ -98,14 +96,13 @@ export default class DuplicateTask {
|
||||
let initialCount = this.clones.length;
|
||||
let dialog = this.openmct.overlays.progressDialog({
|
||||
progressPerc: 0,
|
||||
message: `Duplicating ${initialCount} objects.`,
|
||||
message: `Duplicating ${initialCount} files.`,
|
||||
iconClass: 'info',
|
||||
title: 'Duplicating'
|
||||
});
|
||||
|
||||
let clonesDone = Promise.all(this.clones.map((clone) => {
|
||||
let clonesDone = Promise.all(this.clones.map(clone => {
|
||||
let percentPersisted = Math.ceil(100 * (++this.persisted / initialCount));
|
||||
let message = `Duplicating ${initialCount - this.persisted} objects.`;
|
||||
let message = `Duplicating ${initialCount - this.persisted} files.`;
|
||||
|
||||
dialog.updateProgress(percentPersisted, message);
|
||||
|
||||
@@ -113,7 +110,6 @@ export default class DuplicateTask {
|
||||
}));
|
||||
|
||||
await clonesDone;
|
||||
|
||||
dialog.dismiss();
|
||||
this.openmct.notifications.info(`Duplicated ${this.persisted} objects.`);
|
||||
|
||||
@@ -145,7 +141,10 @@ export default class DuplicateTask {
|
||||
async duplicateObject(originalObject) {
|
||||
// Check if the creatable (or other passed in filter).
|
||||
if (this.filter(originalObject)) {
|
||||
// Clone original object
|
||||
let clone = this.cloneObjectModel(originalObject);
|
||||
|
||||
// Get children, if any
|
||||
let composeesCollection = this.openmct.composition.get(originalObject);
|
||||
let composees;
|
||||
|
||||
@@ -153,6 +152,7 @@ export default class DuplicateTask {
|
||||
composees = await composeesCollection.load();
|
||||
}
|
||||
|
||||
// Recursively duplicate children
|
||||
return this.duplicateComposees(clone, composees);
|
||||
}
|
||||
|
||||
@@ -160,6 +160,36 @@ export default class DuplicateTask {
|
||||
return originalObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update identifiers in a cloned object model (or part of
|
||||
* a cloned object model) to reflect new identifiers after
|
||||
* duplicating.
|
||||
* @private
|
||||
*/
|
||||
rewriteIdentifiers(obj, idMap) {
|
||||
function lookupValue(value) {
|
||||
return (typeof value === 'string' && idMap[value]) || value;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
obj.forEach((value, index) => {
|
||||
obj[index] = lookupValue(value);
|
||||
this.rewriteIdentifiers(obj[index], idMap);
|
||||
});
|
||||
} else if (obj && typeof obj === 'object') {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
let value = obj[key];
|
||||
obj[key] = lookupValue(value);
|
||||
if (idMap[key]) {
|
||||
delete obj[key];
|
||||
obj[idMap[key]] = value;
|
||||
}
|
||||
|
||||
this.rewriteIdentifiers(value, idMap);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of objects composed by a parent, clone them, then
|
||||
* add them to the parent.
|
||||
@@ -167,67 +197,34 @@ export default class DuplicateTask {
|
||||
* @returns {*}
|
||||
*/
|
||||
async duplicateComposees(clonedParent, composees = []) {
|
||||
let idMappings = [];
|
||||
let idMap = {};
|
||||
|
||||
let allComposeesDuplicated = composees.reduce(async (previousPromise, nextComposee) => {
|
||||
await previousPromise;
|
||||
|
||||
let clonedComposee = await this.duplicateObject(nextComposee);
|
||||
|
||||
if (clonedComposee) {
|
||||
idMappings.push({
|
||||
newId: clonedComposee.identifier,
|
||||
oldId: nextComposee.identifier
|
||||
});
|
||||
this.composeChild(clonedComposee, clonedParent, clonedComposee !== nextComposee);
|
||||
}
|
||||
idMap[this.getId(nextComposee)] = this.getId(clonedComposee);
|
||||
await this.composeChild(clonedComposee, clonedParent, clonedComposee !== nextComposee);
|
||||
|
||||
return;
|
||||
}, Promise.resolve());
|
||||
|
||||
await allComposeesDuplicated;
|
||||
|
||||
clonedParent = this.rewriteIdentifiers(clonedParent, idMappings);
|
||||
this.rewriteIdentifiers(clonedParent, idMap);
|
||||
this.clones.push(clonedParent);
|
||||
|
||||
return clonedParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update identifiers in a cloned object model (or part of
|
||||
* a cloned object model) to reflect new identifiers after
|
||||
* duplicating.
|
||||
* @private
|
||||
*/
|
||||
rewriteIdentifiers(clonedParent, childIdMappings) {
|
||||
for (let { newId, oldId } of childIdMappings) {
|
||||
let newIdKeyString = this.openmct.objects.makeKeyString(newId);
|
||||
let oldIdKeyString = this.openmct.objects.makeKeyString(oldId);
|
||||
|
||||
// regex replace keystrings
|
||||
clonedParent = JSON.stringify(clonedParent).replace(new RegExp(oldIdKeyString, 'g'), newIdKeyString);
|
||||
|
||||
// parse reviver to replace identifiers
|
||||
clonedParent = JSON.parse(clonedParent, (key, value) => {
|
||||
if (Object.prototype.hasOwnProperty.call(value, 'key')
|
||||
&& Object.prototype.hasOwnProperty.call(value, 'namespace')
|
||||
&& value.key === oldId.key
|
||||
&& value.namespace === oldId.namespace) {
|
||||
return newId;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return clonedParent;
|
||||
}
|
||||
|
||||
composeChild(child, parent, setLocation) {
|
||||
parent.composition.push(child.identifier);
|
||||
async composeChild(child, parent, setLocation) {
|
||||
const PERSIST_BOOL = false;
|
||||
let parentComposition = this.openmct.composition.get(parent);
|
||||
await parentComposition.load();
|
||||
parentComposition.add(child, PERSIST_BOOL);
|
||||
|
||||
//If a location is not specified, set it.
|
||||
if (setLocation && child.location === undefined) {
|
||||
let parentKeyString = this.getKeyString(parent);
|
||||
let parentKeyString = this.getId(parent);
|
||||
child.location = parentKeyString;
|
||||
}
|
||||
}
|
||||
@@ -242,7 +239,7 @@ export default class DuplicateTask {
|
||||
let clone = JSON.parse(JSON.stringify(domainObject));
|
||||
let identifier = {
|
||||
key: uuid(),
|
||||
namespace: this.namespace // set to NEW parent's namespace
|
||||
namespace: domainObject.identifier.namespace
|
||||
};
|
||||
|
||||
if (clone.modified || clone.persisted || clone.location) {
|
||||
@@ -263,7 +260,7 @@ export default class DuplicateTask {
|
||||
return clone;
|
||||
}
|
||||
|
||||
getKeyString(domainObject) {
|
||||
getId(domainObject) {
|
||||
return this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<div class="c-imagery__main-image__bg"
|
||||
:class="{'paused unnsynced': isPaused,'stale':false }"
|
||||
>
|
||||
<div class="c-imagery__main-image__image js-imageryView-image"
|
||||
<div class="c-imagery__main-image__image"
|
||||
:style="{
|
||||
'background-image': imageUrl ? `url(${imageUrl})` : 'none',
|
||||
'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)`
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, 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 ImageryPlugin from './plugin.js';
|
||||
import Vue from 'vue';
|
||||
import {
|
||||
createOpenMct,
|
||||
resetApplicationState,
|
||||
simulateKeyEvent
|
||||
} from 'utils/testing';
|
||||
|
||||
const ONE_MINUTE = 1000 * 60;
|
||||
const TEN_MINUTES = ONE_MINUTE * 10;
|
||||
const MAIN_IMAGE_CLASS = '.js-imageryView-image';
|
||||
const NEW_IMAGE_CLASS = '.c-imagery__age.c-imagery--new';
|
||||
const REFRESH_CSS_MS = 500;
|
||||
|
||||
function getImageInfo(doc) {
|
||||
let imageElement = doc.querySelectorAll(MAIN_IMAGE_CLASS)[0];
|
||||
let timestamp = imageElement.dataset.openmctImageTimestamp;
|
||||
let identifier = imageElement.dataset.openmctObjectKeystring;
|
||||
let url = imageElement.style.backgroundImage;
|
||||
|
||||
return {
|
||||
timestamp,
|
||||
identifier,
|
||||
url
|
||||
};
|
||||
}
|
||||
|
||||
function isNew(doc) {
|
||||
let newIcon = doc.querySelectorAll(NEW_IMAGE_CLASS);
|
||||
|
||||
return newIcon.length !== 0;
|
||||
}
|
||||
|
||||
function generateTelemetry(start, count) {
|
||||
let telemetry = [];
|
||||
|
||||
for (let i = 1, l = count + 1; i < l; i++) {
|
||||
let stringRep = i + 'minute';
|
||||
let logo = 'images/logo-openmct.svg';
|
||||
|
||||
telemetry.push({
|
||||
"name": stringRep + " Imagery",
|
||||
"utc": start + (i * ONE_MINUTE),
|
||||
"url": location.host + '/' + logo + '?time=' + stringRep,
|
||||
"timeId": stringRep
|
||||
});
|
||||
}
|
||||
|
||||
return telemetry;
|
||||
}
|
||||
|
||||
describe("The Imagery View Layout", () => {
|
||||
const imageryKey = 'example.imagery';
|
||||
const START = Date.now();
|
||||
const COUNT = 10;
|
||||
|
||||
let openmct;
|
||||
let imageryPlugin;
|
||||
let parent;
|
||||
let child;
|
||||
let timeFormat = 'utc';
|
||||
let bounds = {
|
||||
start: START - TEN_MINUTES,
|
||||
end: START
|
||||
};
|
||||
let imageTelemetry = generateTelemetry(START - TEN_MINUTES, COUNT);
|
||||
let imageryObject = {
|
||||
identifier: {
|
||||
namespace: "",
|
||||
key: "imageryId"
|
||||
},
|
||||
name: "Example Imagery",
|
||||
type: "example.imagery",
|
||||
location: "parentId",
|
||||
modified: 0,
|
||||
persisted: 0,
|
||||
telemetry: {
|
||||
values: [
|
||||
{
|
||||
"name": "Image",
|
||||
"key": "url",
|
||||
"format": "image",
|
||||
"hints": {
|
||||
"image": 1,
|
||||
"priority": 3
|
||||
},
|
||||
"source": "url"
|
||||
},
|
||||
{
|
||||
"name": "Name",
|
||||
"key": "name",
|
||||
"source": "name",
|
||||
"hints": {
|
||||
"priority": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Time",
|
||||
"key": "utc",
|
||||
"format": "utc",
|
||||
"hints": {
|
||||
"domain": 2,
|
||||
"priority": 1
|
||||
},
|
||||
"source": "utc"
|
||||
},
|
||||
{
|
||||
"name": "Local Time",
|
||||
"key": "local",
|
||||
"format": "local-format",
|
||||
"hints": {
|
||||
"domain": 1,
|
||||
"priority": 2
|
||||
},
|
||||
"source": "local"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// this setups up the app
|
||||
beforeEach((done) => {
|
||||
const appHolder = document.createElement('div');
|
||||
appHolder.style.width = '640px';
|
||||
appHolder.style.height = '480px';
|
||||
|
||||
openmct = createOpenMct();
|
||||
|
||||
parent = document.createElement('div');
|
||||
child = document.createElement('div');
|
||||
parent.appendChild(child);
|
||||
|
||||
spyOn(openmct.telemetry, 'request').and.returnValue(Promise.resolve([]));
|
||||
|
||||
imageryPlugin = new ImageryPlugin();
|
||||
openmct.install(imageryPlugin);
|
||||
|
||||
spyOn(openmct.objects, 'get').and.returnValue(Promise.resolve({}));
|
||||
|
||||
openmct.time.timeSystem(timeFormat, {
|
||||
start: 0,
|
||||
end: 4
|
||||
});
|
||||
|
||||
openmct.on('start', done);
|
||||
openmct.startHeadless(appHolder);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
return resetApplicationState(openmct);
|
||||
});
|
||||
|
||||
it("should provide an imagery view only for imagery producing objects", () => {
|
||||
let applicableViews = openmct.objectViews.get(imageryObject);
|
||||
let imageryView = applicableViews.find(
|
||||
viewProvider => viewProvider.key === imageryKey
|
||||
);
|
||||
|
||||
expect(imageryView).toBeDefined();
|
||||
});
|
||||
|
||||
describe("imagery view", () => {
|
||||
let applicableViews;
|
||||
let imageryViewProvider;
|
||||
let imageryView;
|
||||
|
||||
beforeEach(async (done) => {
|
||||
let telemetryRequestResolve;
|
||||
let telemetryRequestPromise = new Promise((resolve) => {
|
||||
telemetryRequestResolve = resolve;
|
||||
});
|
||||
|
||||
openmct.telemetry.request.and.callFake(() => {
|
||||
telemetryRequestResolve(imageTelemetry);
|
||||
|
||||
return telemetryRequestPromise;
|
||||
});
|
||||
|
||||
openmct.time.clock('local', {
|
||||
start: bounds.start,
|
||||
end: bounds.end + 100
|
||||
});
|
||||
|
||||
applicableViews = openmct.objectViews.get(imageryObject);
|
||||
imageryViewProvider = applicableViews.find(viewProvider => viewProvider.key === imageryKey);
|
||||
imageryView = imageryViewProvider.view(imageryObject);
|
||||
imageryView.show(child);
|
||||
|
||||
await telemetryRequestPromise;
|
||||
await Vue.nextTick();
|
||||
|
||||
return done();
|
||||
});
|
||||
|
||||
it("on mount should show the the most recent image", () => {
|
||||
const imageInfo = getImageInfo(parent);
|
||||
|
||||
expect(imageInfo.url.indexOf(imageTelemetry[COUNT - 1].timeId)).not.toEqual(-1);
|
||||
});
|
||||
|
||||
it("should show the clicked thumbnail as the main image", async () => {
|
||||
const target = imageTelemetry[5].url;
|
||||
parent.querySelectorAll(`img[src='${target}']`)[0].click();
|
||||
await Vue.nextTick();
|
||||
const imageInfo = getImageInfo(parent);
|
||||
|
||||
expect(imageInfo.url.indexOf(imageTelemetry[5].timeId)).not.toEqual(-1);
|
||||
});
|
||||
|
||||
it("should show that an image is new", async (done) => {
|
||||
await Vue.nextTick();
|
||||
|
||||
// used in code, need to wait to the 500ms here too
|
||||
setTimeout(() => {
|
||||
const imageIsNew = isNew(parent);
|
||||
|
||||
expect(imageIsNew).toBeTrue();
|
||||
done();
|
||||
}, REFRESH_CSS_MS);
|
||||
});
|
||||
|
||||
it("should show that an image is not new", async (done) => {
|
||||
const target = imageTelemetry[2].url;
|
||||
parent.querySelectorAll(`img[src='${target}']`)[0].click();
|
||||
|
||||
await Vue.nextTick();
|
||||
|
||||
// used in code, need to wait to the 500ms here too
|
||||
setTimeout(() => {
|
||||
const imageIsNew = isNew(parent);
|
||||
|
||||
expect(imageIsNew).toBeFalse();
|
||||
done();
|
||||
}, REFRESH_CSS_MS);
|
||||
});
|
||||
|
||||
it("should navigate via arrow keys", async () => {
|
||||
let keyOpts = {
|
||||
element: parent.querySelector('.c-imagery'),
|
||||
key: 'ArrowLeft',
|
||||
keyCode: 37,
|
||||
type: 'keyup'
|
||||
};
|
||||
|
||||
simulateKeyEvent(keyOpts);
|
||||
|
||||
await Vue.nextTick();
|
||||
|
||||
const imageInfo = getImageInfo(parent);
|
||||
|
||||
expect(imageInfo.url.indexOf(imageTelemetry[COUNT - 2].timeId)).not.toEqual(-1);
|
||||
});
|
||||
|
||||
it("should navigate via numerous arrow keys", async () => {
|
||||
let element = parent.querySelector('.c-imagery');
|
||||
let type = 'keyup';
|
||||
let leftKeyOpts = {
|
||||
element,
|
||||
type,
|
||||
key: 'ArrowLeft',
|
||||
keyCode: 37
|
||||
};
|
||||
let rightKeyOpts = {
|
||||
element,
|
||||
type,
|
||||
key: 'ArrowRight',
|
||||
keyCode: 39
|
||||
};
|
||||
|
||||
// left thrice
|
||||
simulateKeyEvent(leftKeyOpts);
|
||||
simulateKeyEvent(leftKeyOpts);
|
||||
simulateKeyEvent(leftKeyOpts);
|
||||
// right once
|
||||
simulateKeyEvent(rightKeyOpts);
|
||||
|
||||
await Vue.nextTick();
|
||||
|
||||
const imageInfo = getImageInfo(parent);
|
||||
|
||||
expect(imageInfo.url.indexOf(imageTelemetry[COUNT - 3].timeId)).not.toEqual(-1);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1,114 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, 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 {
|
||||
createOpenMct,
|
||||
resetApplicationState
|
||||
} from 'utils/testing';
|
||||
|
||||
describe("The local time", () => {
|
||||
const LOCAL_FORMAT_KEY = 'local-format';
|
||||
const LOCAL_SYSTEM_KEY = 'local';
|
||||
const JUNK = "junk";
|
||||
const TIMESTAMP = -14256000000;
|
||||
const DATESTRING = '1969-07-20 12:00:00.000 am';
|
||||
let openmct;
|
||||
|
||||
beforeEach((done) => {
|
||||
|
||||
openmct = createOpenMct();
|
||||
|
||||
openmct.install(openmct.plugins.LocalTimeSystem());
|
||||
|
||||
openmct.on('start', done);
|
||||
openmct.startHeadless();
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
return resetApplicationState(openmct);
|
||||
});
|
||||
|
||||
describe("system", function () {
|
||||
|
||||
let localTimeSystem;
|
||||
|
||||
beforeEach(() => {
|
||||
localTimeSystem = openmct.time.timeSystem(LOCAL_SYSTEM_KEY, {
|
||||
start: 0,
|
||||
end: 4
|
||||
});
|
||||
});
|
||||
|
||||
it("is installed", () => {
|
||||
let timeSystems = openmct.time.getAllTimeSystems();
|
||||
let local = timeSystems.find(ts => ts.key === LOCAL_SYSTEM_KEY);
|
||||
|
||||
expect(local).not.toEqual(-1);
|
||||
});
|
||||
|
||||
it("can be set to be the main time system", () => {
|
||||
expect(openmct.time.timeSystem().key).toBe(LOCAL_SYSTEM_KEY);
|
||||
});
|
||||
|
||||
it("uses the local-format time format", () => {
|
||||
expect(localTimeSystem.timeFormat).toBe(LOCAL_FORMAT_KEY);
|
||||
});
|
||||
|
||||
it("is UTC based", () => {
|
||||
expect(localTimeSystem.isUTCBased).toBe(true);
|
||||
});
|
||||
|
||||
it("defines expected metadata", () => {
|
||||
expect(localTimeSystem.key).toBe(LOCAL_SYSTEM_KEY);
|
||||
expect(localTimeSystem.name).toBeDefined();
|
||||
expect(localTimeSystem.cssClass).toBeDefined();
|
||||
expect(localTimeSystem.durationFormat).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatter can be obtained from the telemetry API and", () => {
|
||||
|
||||
let localTimeFormatter;
|
||||
let dateString;
|
||||
let timeStamp;
|
||||
|
||||
beforeEach(() => {
|
||||
localTimeFormatter = openmct.telemetry.getFormatter(LOCAL_FORMAT_KEY);
|
||||
dateString = localTimeFormatter.format(TIMESTAMP);
|
||||
timeStamp = localTimeFormatter.parse(DATESTRING);
|
||||
});
|
||||
|
||||
it("will format a timestamp in local time format", () => {
|
||||
expect(localTimeFormatter.format(TIMESTAMP)).toBe(dateString);
|
||||
});
|
||||
|
||||
it("will parse an local time Date String into milliseconds", () => {
|
||||
expect(localTimeFormatter.parse(DATESTRING)).toBe(timeStamp);
|
||||
});
|
||||
|
||||
it("will validate correctly", () => {
|
||||
expect(localTimeFormatter.validate(DATESTRING)).toBe(true);
|
||||
expect(localTimeFormatter.validate(JUNK)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -143,9 +143,9 @@ export default {
|
||||
this.openmct.notifications.alert(message);
|
||||
}
|
||||
|
||||
const relativeHash = hash.slice(hash.indexOf('#'));
|
||||
const url = new URL(relativeHash, `${location.protocol}//${location.host}${location.pathname}`);
|
||||
window.location.hash = url.hash;
|
||||
const link = `${location.host}${location.pathname}${hash}`;
|
||||
const url = new URL(link);
|
||||
window.location.href = url.hash;
|
||||
},
|
||||
formatTime(unixTime, timeFormat) {
|
||||
return Moment.utc(unixTime).format(timeFormat);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
import { createOpenMct, createMouseEvent, resetApplicationState } from 'utils/testing';
|
||||
import { createOpenMct, resetApplicationState } from 'utils/testing';
|
||||
import NotebookPlugin from './plugin';
|
||||
import Vue from 'vue';
|
||||
|
||||
@@ -133,89 +133,4 @@ describe("Notebook plugin:", () => {
|
||||
expect(hasMajorElements).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Notebook Snapshots view:", () => {
|
||||
let snapshotIndicator;
|
||||
let drawerElement;
|
||||
|
||||
function clickSnapshotIndicator() {
|
||||
const indicator = element.querySelector('.icon-camera');
|
||||
const button = indicator.querySelector('button');
|
||||
const clickEvent = createMouseEvent('click');
|
||||
|
||||
button.dispatchEvent(clickEvent);
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
snapshotIndicator = openmct.indicators.indicatorObjects
|
||||
.find(indicator => indicator.key === 'notebook-snapshot-indicator').element;
|
||||
|
||||
element.append(snapshotIndicator);
|
||||
|
||||
return Vue.nextTick();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
snapshotIndicator.remove();
|
||||
snapshotIndicator = undefined;
|
||||
|
||||
if (drawerElement) {
|
||||
drawerElement.remove();
|
||||
drawerElement = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
drawerElement = document.querySelector('.l-shell__drawer');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (drawerElement) {
|
||||
drawerElement.classList.remove('is-expanded');
|
||||
}
|
||||
});
|
||||
|
||||
it("has Snapshots indicator", () => {
|
||||
const hasSnapshotIndicator = snapshotIndicator !== null && snapshotIndicator !== undefined;
|
||||
expect(hasSnapshotIndicator).toBe(true);
|
||||
});
|
||||
|
||||
it("snapshots container has class isExpanded", () => {
|
||||
let classes = drawerElement.classList;
|
||||
const isExpandedBefore = classes.contains('is-expanded');
|
||||
|
||||
clickSnapshotIndicator();
|
||||
classes = drawerElement.classList;
|
||||
const isExpandedAfterFirstClick = classes.contains('is-expanded');
|
||||
|
||||
expect(isExpandedBefore).toBeFalse();
|
||||
expect(isExpandedAfterFirstClick).toBeTrue();
|
||||
});
|
||||
|
||||
it("snapshots container does not have class isExpanded", () => {
|
||||
let classes = drawerElement.classList;
|
||||
const isExpandedBefore = classes.contains('is-expanded');
|
||||
|
||||
clickSnapshotIndicator();
|
||||
classes = drawerElement.classList;
|
||||
const isExpandedAfterFirstClick = classes.contains('is-expanded');
|
||||
|
||||
clickSnapshotIndicator();
|
||||
classes = drawerElement.classList;
|
||||
const isExpandedAfterSecondClick = classes.contains('is-expanded');
|
||||
|
||||
expect(isExpandedBefore).toBeFalse();
|
||||
expect(isExpandedAfterFirstClick).toBeTrue();
|
||||
expect(isExpandedAfterSecondClick).toBeFalse();
|
||||
});
|
||||
|
||||
it("show notebook snapshots container text", () => {
|
||||
clickSnapshotIndicator();
|
||||
|
||||
const notebookSnapshots = drawerElement.querySelector('.l-browse-bar__object-name');
|
||||
const snapshotsText = notebookSnapshots.textContent.trim();
|
||||
|
||||
expect(snapshotsText).toBe('Notebook Snapshots');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,14 +7,15 @@ export default class Snapshot {
|
||||
constructor(openmct) {
|
||||
this.openmct = openmct;
|
||||
this.snapshotContainer = new SnapshotContainer(openmct);
|
||||
this.exportImageService = openmct.$injector.get('exportImageService');
|
||||
this.dialogService = openmct.$injector.get('dialogService');
|
||||
|
||||
this.capture = this.capture.bind(this);
|
||||
this._saveSnapShot = this._saveSnapShot.bind(this);
|
||||
}
|
||||
|
||||
capture(snapshotMeta, notebookType, domElement) {
|
||||
const exportImageService = this.openmct.$injector.get('exportImageService');
|
||||
exportImageService.exportPNGtoSRC(domElement, 's-status-taking-snapshot')
|
||||
this.exportImageService.exportPNGtoSRC(domElement, 's-status-taking-snapshot')
|
||||
.then(function (blob) {
|
||||
const reader = new window.FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
|
||||
@@ -39,11 +39,10 @@ define([], function () {
|
||||
const thisRequest = {
|
||||
pending: 0
|
||||
};
|
||||
const telemetryObjects = $scope.telemetryObjects = [];
|
||||
const thisTickWidthMap = {};
|
||||
|
||||
currentRequest = thisRequest;
|
||||
$scope.currentRequest = thisRequest;
|
||||
const telemetryObjects = $scope.telemetryObjects = [];
|
||||
const thisTickWidthMap = {};
|
||||
tickWidthMap = thisTickWidthMap;
|
||||
|
||||
if (unlisten) {
|
||||
@@ -53,10 +52,14 @@ define([], function () {
|
||||
|
||||
function addChild(child) {
|
||||
const id = openmct.objects.makeKeyString(child.identifier);
|
||||
const legacyObject = openmct.legacyObject(child);
|
||||
|
||||
thisTickWidthMap[id] = 0;
|
||||
telemetryObjects.push(legacyObject);
|
||||
thisRequest.pending += 1;
|
||||
objectService.getObjects([id])
|
||||
.then(function (objects) {
|
||||
thisRequest.pending -= 1;
|
||||
const childObj = objects[id];
|
||||
telemetryObjects.push(childObj);
|
||||
});
|
||||
}
|
||||
|
||||
function removeChild(childIdentifier) {
|
||||
@@ -81,7 +84,6 @@ define([], function () {
|
||||
}
|
||||
|
||||
thisRequest.pending += 1;
|
||||
|
||||
openmct.objects.get(domainObject.getId())
|
||||
.then(function (obj) {
|
||||
thisRequest.pending -= 1;
|
||||
|
||||
@@ -98,10 +98,6 @@ describe('the plugin', function () {
|
||||
|
||||
beforeEach((done) => {
|
||||
planDomainObject = {
|
||||
identifier: {
|
||||
key: 'test-object',
|
||||
namespace: ''
|
||||
},
|
||||
type: 'plan',
|
||||
id: "test-object",
|
||||
selectFile: {
|
||||
|
||||
@@ -70,8 +70,11 @@ define(
|
||||
if (multiSelect) {
|
||||
this.handleMultiSelect(selectable);
|
||||
} else {
|
||||
this.handleSingleSelect(selectable);
|
||||
this.setSelectionStyles(selectable);
|
||||
this.selected = [selectable];
|
||||
}
|
||||
|
||||
this.emit('change', this.selected);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -84,20 +87,6 @@ define(
|
||||
this.addSelectionAttributes(selectable);
|
||||
this.selected.push(selectable);
|
||||
}
|
||||
|
||||
this.emit('change', this.selected);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Selection.prototype.handleSingleSelect = function (selectable) {
|
||||
if (!_.isEqual([selectable], this.selected)) {
|
||||
this.setSelectionStyles(selectable);
|
||||
this.selected = [selectable];
|
||||
|
||||
this.emit('change', this.selected);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -482,7 +482,7 @@ select {
|
||||
transition: $transIn;
|
||||
white-space: nowrap;
|
||||
|
||||
@include hover {
|
||||
&:hover {
|
||||
background: $colorMenuHovBg;
|
||||
color: $colorMenuHovFg;
|
||||
&:before {
|
||||
@@ -500,10 +500,6 @@ select {
|
||||
&:not([class*='icon']):before {
|
||||
content: ''; // Enable :before so that menu items without an icon still indent properly
|
||||
}
|
||||
|
||||
.menus-no-icon & {
|
||||
&:before { display: none; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,6 +731,7 @@ select {
|
||||
.c-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
> * {
|
||||
// First level items
|
||||
|
||||
@@ -47,7 +47,6 @@ mct-plot {
|
||||
.c-plot,
|
||||
.gl-plot {
|
||||
overflow: hidden;
|
||||
min-height: 100px;
|
||||
|
||||
.s-status-taking-snapshot & {
|
||||
.c-control-bar {
|
||||
@@ -80,8 +79,7 @@ mct-plot {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&--stacked {
|
||||
|
||||
@@ -552,8 +552,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
&[class*='--menus-left'],
|
||||
&[class*='menus-to-left'] {
|
||||
&[class*='--menus-left'] {
|
||||
.c-menu {
|
||||
left: auto; right: 0;
|
||||
}
|
||||
|
||||
@@ -162,5 +162,5 @@
|
||||
// This element is the recipient for object styling; cannot be display: contents
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
display: contents;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
<toolbar-select-menu
|
||||
:options="fontSizeMenuOptions"
|
||||
@change="setFontSize"
|
||||
class="menus-to-left menus-no-icon"
|
||||
/>
|
||||
<div class="c-toolbar__separator"></div>
|
||||
<toolbar-select-menu
|
||||
:options="fontMenuOptions"
|
||||
@change="setFont"
|
||||
class="menus-to-left menus-no-icon"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
<span
|
||||
class="l-browse-bar__object-name c-object-label__name c-input-inline"
|
||||
:contenteditable="type.creatable"
|
||||
contenteditable
|
||||
@blur="updateName"
|
||||
@keydown.enter.prevent
|
||||
@keyup.enter.prevent="updateNameOnEnterKeyPress"
|
||||
|
||||
@@ -279,12 +279,10 @@
|
||||
}
|
||||
|
||||
&__toolbar {
|
||||
// Toolbar in the main shell, used by Display Layouts
|
||||
$p: $interiorMargin;
|
||||
background: $editUIBaseColor;
|
||||
border-radius: $basicCr;
|
||||
height: $p + 24px; // Need to standardize the height
|
||||
justify-content: space-between;
|
||||
padding: $p;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,28 +90,6 @@ export function resetApplicationState(openmct) {
|
||||
return promise;
|
||||
}
|
||||
|
||||
// required: key
|
||||
// optional: element, keyCode, type
|
||||
export function simulateKeyEvent(opts) {
|
||||
|
||||
if (!opts.key) {
|
||||
console.warn('simulateKeyEvent needs a key');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const el = opts.element || document;
|
||||
const key = opts.key;
|
||||
const keyCode = opts.keyCode || key;
|
||||
const type = opts.type || 'keydown';
|
||||
const event = new Event(type);
|
||||
|
||||
event.keyCode = keyCode;
|
||||
event.key = key;
|
||||
|
||||
el.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function clearBuiltinSpy(funcDefinition) {
|
||||
funcDefinition.object[funcDefinition.functionName] = funcDefinition.nativeFunction;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user