Compare commits
44 Commits
alphanumer
...
select-tab
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b74507bd1b | ||
|
|
7fe4a77c43 | ||
|
|
1461a209d9 | ||
|
|
bfb89c7ece | ||
|
|
f45e1623a1 | ||
|
|
09c4ee48b2 | ||
|
|
e8997917b2 | ||
|
|
8578d78c51 | ||
|
|
362e565a09 | ||
|
|
faa1d01499 | ||
|
|
a9c245a7db | ||
|
|
85dd5ce00c | ||
|
|
ec86ebd692 | ||
|
|
6c69694dca | ||
|
|
0b8bf682a4 | ||
|
|
9517c1f2cd | ||
|
|
e72ba5e8bf | ||
|
|
3caba5efac | ||
|
|
efdd80bd57 | ||
|
|
262d35804d | ||
|
|
e0587bf0e7 | ||
|
|
f1494fd285 | ||
|
|
832c4d9816 | ||
|
|
3a5024d38d | ||
|
|
dcd6334036 | ||
|
|
728b39164e | ||
|
|
884aec8ea0 | ||
|
|
216f447578 | ||
|
|
c38d810658 | ||
|
|
f5c48b7bf6 | ||
|
|
d0e08f1d9a | ||
|
|
72ea7b80fd | ||
|
|
35d0c02bc5 | ||
|
|
abd7506b45 | ||
|
|
526b4aa07e | ||
|
|
b5e23963d4 | ||
|
|
2c11eb90d4 | ||
|
|
90e9c79e19 | ||
|
|
1b83631e43 | ||
|
|
547d4e82db | ||
|
|
3377ad5e0d | ||
|
|
1c0df60f05 | ||
|
|
138067dca9 | ||
|
|
844280eaa5 |
@@ -99,10 +99,10 @@ define([
|
||||
|
||||
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
|
||||
return _.extend(
|
||||
{},
|
||||
domainObject.telemetry,
|
||||
METADATA_BY_TYPE[domainObject.type]
|
||||
);
|
||||
{},
|
||||
domainObject.telemetry,
|
||||
METADATA_BY_TYPE[domainObject.type]
|
||||
);
|
||||
};
|
||||
|
||||
return GeneratorMetadataProvider;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<span class="h-indicator" ng-controller="DialogLaunchController">
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<div class="ls-indicator icon-box-with-arrow s-status-available"><span class="label">
|
||||
<a ng-click="launchProgress(true)">Known</a>
|
||||
<a ng-click="launchProgress(false)">Unknown</a>
|
||||
<a ng-click="launchError()">Error</a>
|
||||
<a ng-click="launchInfo()">Info</a>
|
||||
<div class="c-indicator c-indicator--clickable icon-box-with-arrow s-status-available"><span class="label c-indicator__label">
|
||||
<button ng-click="launchProgress(true)">Known</button>
|
||||
<button ng-click="launchProgress(false)">Unknown</button>
|
||||
<button ng-click="launchError()">Error</button>
|
||||
<button ng-click="launchInfo()">Info</button>
|
||||
</span></div>
|
||||
</span>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<span class="h-indicator" ng-controller="NotificationLaunchController">
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<div class="ls-indicator icon-bell s-status-available"><span class="label">
|
||||
<a ng-click="newInfo()">Success</a>
|
||||
<a ng-click="newError()">Error</a>
|
||||
<a ng-click="newAlert()">Alert</a>
|
||||
<a ng-click="newProgress()">Progress</a>
|
||||
<div class="c-indicator c-indicator--clickable icon-bell s-status-available"><span class="label c-indicator__label">
|
||||
<button ng-click="newInfo()">Success</button>
|
||||
<button ng-click="newError()">Error</button>
|
||||
<button ng-click="newAlert()">Alert</button>
|
||||
<button ng-click="newProgress()">Progress</button>
|
||||
</span></div>
|
||||
</span>
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
openmct.install(openmct.plugins.Generator());
|
||||
openmct.install(openmct.plugins.ExampleImagery());
|
||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||
openmct.install(openmct.plugins.ImportExport());
|
||||
openmct.install(openmct.plugins.AutoflowView({
|
||||
type: "telemetry.panel"
|
||||
}));
|
||||
@@ -80,12 +79,9 @@
|
||||
}));
|
||||
openmct.install(openmct.plugins.SummaryWidget());
|
||||
openmct.install(openmct.plugins.Notebook());
|
||||
openmct.install(openmct.plugins.FolderView());
|
||||
openmct.install(openmct.plugins.Tabs());
|
||||
openmct.install(openmct.plugins.FlexibleLayout());
|
||||
openmct.install(openmct.plugins.LADTable());
|
||||
openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay']));
|
||||
openmct.install(openmct.plugins.ObjectMigration());
|
||||
openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked']));
|
||||
openmct.start();
|
||||
</script>
|
||||
</html>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"description": "The Open MCT core platform",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"acorn": "6.2.0",
|
||||
"angular": "1.4.14",
|
||||
"angular-route": "1.4.14",
|
||||
"babel-eslint": "8.2.6",
|
||||
@@ -55,7 +56,7 @@
|
||||
"node-bourbon": "^4.2.3",
|
||||
"node-sass": "^4.9.2",
|
||||
"painterro": "^0.2.65",
|
||||
"printj": "^1.1.0",
|
||||
"printj": "^1.2.1",
|
||||
"raw-loader": "^0.5.1",
|
||||
"request": "^2.69.0",
|
||||
"split": "^1.0.0",
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
ng-model="ngModel"
|
||||
ng-show="ngModel.progressPerc !== undefined"></mct-include>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<button ng-repeat="dialogOption in ngModel.options"
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<button ng-repeat="dialogOption in ngModel.options"
|
||||
class="c-button"
|
||||
ng-click="dialogOption.callback()">
|
||||
{{dialogOption.label}}
|
||||
</button>
|
||||
<button class="c-button c-button--major"
|
||||
{{dialogOption.label}}
|
||||
</button>
|
||||
<button class="c-button c-button--major"
|
||||
ng-if="ngModel.primaryOption"
|
||||
ng-click="ngModel.primaryOption.callback()">
|
||||
{{ngModel.primaryOption.label}}
|
||||
</button>
|
||||
</div>
|
||||
{{ngModel.primaryOption.label}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -64,7 +64,6 @@ define(
|
||||
* @returns boolean
|
||||
*/
|
||||
EditorCapability.prototype.inEditContext = function () {
|
||||
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
|
||||
return this.openmct.editor.isEditing();
|
||||
};
|
||||
|
||||
@@ -74,7 +73,6 @@ define(
|
||||
* @returns {*}
|
||||
*/
|
||||
EditorCapability.prototype.isEditContextRoot = function () {
|
||||
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
|
||||
return this.openmct.editor.isEditing();
|
||||
};
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<div class="ls-indicator {{ngModel.getCssClass()}}"
|
||||
<div class="c-indicator {{ngModel.getCssClass()}}"
|
||||
title="{{ngModel.getDescription()}}"
|
||||
ng-show="ngModel.getText().length > 0">
|
||||
<span class="label">{{ngModel.getText()}}</span>
|
||||
<span class="label c-indicator__label">{{ngModel.getText()}}</span>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<div ng-show="notifications.length > 0" class="ls-indicator s-status-{{highest.severity}} icon-bell"
|
||||
<div ng-show="notifications.length > 0" class="c-indicator c-indicator--clickable s-status-{{highest.severity}} icon-bell"
|
||||
ng-controller="NotificationIndicatorController">
|
||||
<span class="label">
|
||||
<a ng-click="showNotificationsList()">
|
||||
{{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></a>
|
||||
</span><span class="count">{{notifications.length}}</span>
|
||||
<span class="label c-indicator__label">
|
||||
<button ng-click="showNotificationsList()">
|
||||
{{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></button>
|
||||
</span><span class="c-indicator__count">{{notifications.length}}</span>
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,6 @@ define([
|
||||
"./src/actions/MoveAction",
|
||||
"./src/actions/CopyAction",
|
||||
"./src/actions/LinkAction",
|
||||
"./src/actions/GoToOriginalAction",
|
||||
"./src/actions/SetPrimaryLocationAction",
|
||||
"./src/services/LocatingCreationDecorator",
|
||||
"./src/services/LocatingObjectDecorator",
|
||||
@@ -41,7 +40,6 @@ define([
|
||||
MoveAction,
|
||||
CopyAction,
|
||||
LinkAction,
|
||||
GoToOriginalAction,
|
||||
SetPrimaryLocationAction,
|
||||
LocatingCreationDecorator,
|
||||
LocatingObjectDecorator,
|
||||
@@ -104,14 +102,6 @@ define([
|
||||
"linkService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "follow",
|
||||
"name": "Go To Original",
|
||||
"description": "Go to the original, un-linked instance of this object.",
|
||||
"cssClass": "",
|
||||
"category": "contextual",
|
||||
"implementation": GoToOriginalAction
|
||||
},
|
||||
{
|
||||
"key": "locate",
|
||||
"name": "Set Primary Location",
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Implements the "Go To Original" action, which follows a link back
|
||||
* to an original instance of an object.
|
||||
*
|
||||
* @implements {Action}
|
||||
* @constructor
|
||||
* @private
|
||||
* @memberof platform/entanglement
|
||||
* @param {ActionContext} context the context in which the action
|
||||
* will be performed
|
||||
*/
|
||||
function GoToOriginalAction(context) {
|
||||
this.domainObject = context.domainObject;
|
||||
}
|
||||
|
||||
GoToOriginalAction.prototype.perform = function () {
|
||||
return this.domainObject.getCapability("location").getOriginal()
|
||||
.then(function (originalObject) {
|
||||
var actionCapability =
|
||||
originalObject.getCapability("action");
|
||||
return actionCapability &&
|
||||
actionCapability.perform("navigate");
|
||||
});
|
||||
};
|
||||
|
||||
GoToOriginalAction.appliesTo = function (context) {
|
||||
var domainObject = context.domainObject;
|
||||
return domainObject && domainObject.hasCapability("location") &&
|
||||
domainObject.getCapability("location").isLink();
|
||||
};
|
||||
|
||||
return GoToOriginalAction;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
define(
|
||||
[
|
||||
'../../src/actions/GoToOriginalAction',
|
||||
'../DomainObjectFactory',
|
||||
'../ControlledPromise'
|
||||
],
|
||||
function (GoToOriginalAction, domainObjectFactory, ControlledPromise) {
|
||||
|
||||
describe("The 'go to original' action", function () {
|
||||
var testContext,
|
||||
originalDomainObject,
|
||||
mockLocationCapability,
|
||||
mockOriginalActionCapability,
|
||||
originalPromise,
|
||||
action;
|
||||
|
||||
beforeEach(function () {
|
||||
mockLocationCapability = jasmine.createSpyObj(
|
||||
'location',
|
||||
['isLink', 'isOriginal', 'getOriginal']
|
||||
);
|
||||
mockOriginalActionCapability = jasmine.createSpyObj(
|
||||
'action',
|
||||
['perform', 'getActions']
|
||||
);
|
||||
originalPromise = new ControlledPromise();
|
||||
mockLocationCapability.getOriginal.and.returnValue(originalPromise);
|
||||
mockLocationCapability.isLink.and.returnValue(true);
|
||||
mockLocationCapability.isOriginal.and.callFake(function () {
|
||||
return !mockLocationCapability.isLink();
|
||||
});
|
||||
testContext = {
|
||||
domainObject: domainObjectFactory({
|
||||
capabilities: {
|
||||
location: mockLocationCapability
|
||||
}
|
||||
})
|
||||
};
|
||||
originalDomainObject = domainObjectFactory({
|
||||
capabilities: {
|
||||
action: mockOriginalActionCapability
|
||||
}
|
||||
});
|
||||
|
||||
action = new GoToOriginalAction(testContext);
|
||||
});
|
||||
|
||||
it("is applicable to links", function () {
|
||||
expect(GoToOriginalAction.appliesTo(testContext))
|
||||
.toBeTruthy();
|
||||
});
|
||||
|
||||
it("is not applicable to originals", function () {
|
||||
mockLocationCapability.isLink.and.returnValue(false);
|
||||
expect(GoToOriginalAction.appliesTo(testContext))
|
||||
.toBeFalsy();
|
||||
});
|
||||
|
||||
it("navigates to original objects when performed", function () {
|
||||
expect(mockOriginalActionCapability.perform)
|
||||
.not.toHaveBeenCalled();
|
||||
action.perform();
|
||||
originalPromise.resolve(originalDomainObject);
|
||||
expect(mockOriginalActionCapability.perform)
|
||||
.toHaveBeenCalledWith('navigate');
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -49,7 +49,7 @@ define(
|
||||
};
|
||||
|
||||
ClockIndicator.prototype.getCssClass = function () {
|
||||
return "t-indicator-clock icon-clock no-collapse float-right";
|
||||
return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable";
|
||||
};
|
||||
|
||||
ClockIndicator.prototype.getText = function () {
|
||||
|
||||
@@ -64,12 +64,30 @@ define(['zepto'], function ($) {
|
||||
var tree = this.generateNewIdentifiers(objTree);
|
||||
var rootId = tree.rootId;
|
||||
var rootObj = this.instantiate(tree.openmct[rootId], rootId);
|
||||
var newStyleParent = parent.useCapability('adapter');
|
||||
var newStyleRootObj = rootObj.useCapability('adapter');
|
||||
|
||||
// Instantiate all objects in tree with their newly genereated ids,
|
||||
// adding each to its rightful parent's composition
|
||||
rootObj.getCapability("location").setPrimaryLocation(parent.getId());
|
||||
this.deepInstantiate(rootObj, tree.openmct, []);
|
||||
parent.getCapability("composition").add(rootObj);
|
||||
if (this.openmct.composition.checkPolicy(newStyleParent, newStyleRootObj)) {
|
||||
// Instantiate all objects in tree with their newly generated ids,
|
||||
// adding each to its rightful parent's composition
|
||||
rootObj.getCapability("location").setPrimaryLocation(parent.getId());
|
||||
this.deepInstantiate(rootObj, tree.openmct, []);
|
||||
parent.getCapability("composition").add(rootObj);
|
||||
} else {
|
||||
var dialog = this.openmct.overlays.dialog({
|
||||
iconClass: 'alert',
|
||||
message: "We're sorry, but you cannot import that object type into this object.",
|
||||
buttons: [
|
||||
{
|
||||
label: "Ok",
|
||||
emphasis: true,
|
||||
callback: function () {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) {
|
||||
@@ -80,15 +98,17 @@ define(['zepto'], function ($) {
|
||||
var newObj;
|
||||
|
||||
seen.push(parent.getId());
|
||||
parentModel.composition.forEach(function (childId, index) {
|
||||
if (!tree[childId] || seen.includes(childId)) {
|
||||
|
||||
parentModel.composition.forEach(function (childId) {
|
||||
let keystring = this.openmct.objects.makeKeyString(childId);
|
||||
|
||||
if (!tree[keystring] || seen.includes(keystring)) {
|
||||
return;
|
||||
}
|
||||
|
||||
newObj = this.instantiate(tree[childId], childId);
|
||||
parent.getCapability("composition").add(newObj);
|
||||
newObj = this.instantiate(tree[keystring], keystring);
|
||||
newObj.getCapability("location")
|
||||
.setPrimaryLocation(tree[childId].location);
|
||||
.setPrimaryLocation(tree[keystring].location);
|
||||
this.deepInstantiate(newObj, tree, seen);
|
||||
}, this);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ define(
|
||||
}
|
||||
|
||||
CouchIndicator.prototype.getCssClass = function () {
|
||||
return "icon-database " + this.state.statusClass;
|
||||
return "c-indicator--clickable icon-database " + this.state.statusClass;
|
||||
};
|
||||
|
||||
CouchIndicator.prototype.getGlyphClass = function () {
|
||||
|
||||
@@ -84,7 +84,7 @@ define(
|
||||
}
|
||||
|
||||
ElasticIndicator.prototype.getCssClass = function () {
|
||||
return "icon-database";
|
||||
return "c-indicator--clickable icon-database";
|
||||
};
|
||||
ElasticIndicator.prototype.getGlyphClass = function () {
|
||||
return this.state.glyphClass;
|
||||
|
||||
@@ -41,7 +41,7 @@ define(
|
||||
}
|
||||
|
||||
LocalStorageIndicator.prototype.getCssClass = function () {
|
||||
return "icon-database s-status-caution";
|
||||
return "c-indicator--clickable icon-database s-status-caution";
|
||||
};
|
||||
LocalStorageIndicator.prototype.getGlyphClass = function () {
|
||||
return 'caution';
|
||||
|
||||
@@ -246,12 +246,21 @@ define([
|
||||
this.branding = BrandingAPI.default;
|
||||
|
||||
this.legacyRegistry = defaultRegistry;
|
||||
|
||||
// Plugin's that are installed by default
|
||||
|
||||
this.install(this.plugins.Plot());
|
||||
this.install(this.plugins.TelemetryTable());
|
||||
this.install(PreviewPlugin.default());
|
||||
this.install(LegacyIndicatorsPlugin());
|
||||
this.install(LicensesPlugin.default());
|
||||
this.install(RemoveActionPlugin.default());
|
||||
this.install(this.plugins.ImportExport());
|
||||
this.install(this.plugins.FolderView());
|
||||
this.install(this.plugins.Tabs());
|
||||
this.install(this.plugins.FlexibleLayout());
|
||||
this.install(this.plugins.LADTable());
|
||||
this.install(this.plugins.GoToOriginalAction());
|
||||
|
||||
if (typeof BUILD_CONSTANTS !== 'undefined') {
|
||||
this.install(buildInfoPlugin(BUILD_CONSTANTS));
|
||||
|
||||
@@ -36,7 +36,7 @@ define([
|
||||
'./runs/RegisterLegacyTypes',
|
||||
'./services/LegacyObjectAPIInterceptor',
|
||||
'./views/installLegacyViews',
|
||||
'./policies/legacyCompositionPolicyAdapter',
|
||||
'./policies/LegacyCompositionPolicyAdapter',
|
||||
'./actions/LegacyActionAdapter'
|
||||
], function (
|
||||
legacyRegistry,
|
||||
|
||||
@@ -45,22 +45,27 @@ define([
|
||||
view: function (domainObject) {
|
||||
let $rootScope = openmct.$injector.get('$rootScope');
|
||||
let templateLinker = openmct.$injector.get('templateLinker');
|
||||
let scope = $rootScope.$new();
|
||||
let scope = $rootScope.$new(true);
|
||||
let legacyObject = convertToLegacyObject(domainObject);
|
||||
let isDestroyed = false;
|
||||
let unlistenToStatus;
|
||||
let element;
|
||||
scope.domainObject = legacyObject;
|
||||
scope.model = legacyObject.getModel();
|
||||
|
||||
let child;
|
||||
let parent;
|
||||
|
||||
return {
|
||||
show: function (container) {
|
||||
parent = container;
|
||||
child = document.createElement('div');
|
||||
parent.appendChild(child);
|
||||
let statusCapability = legacyObject.getCapability('status');
|
||||
unlistenToStatus = statusCapability.listen((newStatus) => {
|
||||
container.classList.remove('s-status-timeconductor-unsynced');
|
||||
child.classList.remove('s-status-timeconductor-unsynced');
|
||||
|
||||
if (newStatus.includes('timeconductor-unsynced')) {
|
||||
container.classList.add('s-status-timeconductor-unsynced');
|
||||
child.classList.add('s-status-timeconductor-unsynced');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -84,12 +89,13 @@ define([
|
||||
uses.forEach(function (key, i) {
|
||||
scope[key] = results[i];
|
||||
});
|
||||
element = openmct.$angular.element(child);
|
||||
templateLinker.link(
|
||||
scope,
|
||||
openmct.$angular.element(container),
|
||||
element,
|
||||
legacyView
|
||||
);
|
||||
container.classList.add('u-contents');
|
||||
child.classList.add('u-contents');
|
||||
}
|
||||
|
||||
if (promises.length) {
|
||||
@@ -102,8 +108,15 @@ define([
|
||||
link();
|
||||
}
|
||||
},
|
||||
onClearData() {
|
||||
scope.$broadcast('clearData');
|
||||
},
|
||||
destroy: function () {
|
||||
element.off();
|
||||
element.remove();
|
||||
scope.$destroy();
|
||||
element = null;
|
||||
scope = null;
|
||||
unlistenToStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ define([
|
||||
cssClass: representation.cssClass,
|
||||
description: representation.description,
|
||||
canView: function (selection) {
|
||||
if (selection.length === 0 || selection[0].length === 0) {
|
||||
if (selection.length !== 1 || selection[0].length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -41,15 +41,18 @@ define([
|
||||
let domainObject = selection[0][0].context.item;
|
||||
let $rootScope = openmct.$injector.get('$rootScope');
|
||||
let templateLinker = openmct.$injector.get('templateLinker');
|
||||
let scope = $rootScope.$new();
|
||||
let scope = $rootScope.$new(true);
|
||||
let legacyObject = convertToLegacyObject(domainObject);
|
||||
let isDestroyed = false;
|
||||
let element;
|
||||
scope.domainObject = legacyObject;
|
||||
scope.model = legacyObject.getModel();
|
||||
|
||||
|
||||
return {
|
||||
show: function (container) {
|
||||
let child = document.createElement('div');
|
||||
container.appendChild(child);
|
||||
// TODO: implement "gestures" support ?
|
||||
let uses = representation.uses || [];
|
||||
let promises = [];
|
||||
@@ -70,9 +73,10 @@ define([
|
||||
uses.forEach(function (key, i) {
|
||||
scope[key] = results[i];
|
||||
});
|
||||
element = openmct.$angular.element(child)
|
||||
templateLinker.link(
|
||||
scope,
|
||||
openmct.$angular.element(container),
|
||||
element,
|
||||
representation
|
||||
);
|
||||
container.style.height = '100%';
|
||||
@@ -89,7 +93,11 @@ define([
|
||||
}
|
||||
},
|
||||
destroy: function () {
|
||||
element.off();
|
||||
element.remove();
|
||||
scope.$destroy();
|
||||
element = null;
|
||||
scope = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,20 @@ define([
|
||||
publicAPI = {};
|
||||
publicAPI.objects = jasmine.createSpyObj('ObjectAPI', [
|
||||
'get',
|
||||
'mutate'
|
||||
'mutate',
|
||||
'observe',
|
||||
'areIdsEqual'
|
||||
]);
|
||||
|
||||
publicAPI.objects.areIdsEqual.and.callFake(function (id1, id2) {
|
||||
return id1.namespace === id2.namespace && id1.key === id2.key;
|
||||
});
|
||||
|
||||
publicAPI.composition = jasmine.createSpyObj('CompositionAPI', [
|
||||
'checkPolicy'
|
||||
]);
|
||||
publicAPI.composition.checkPolicy.and.returnValue(true);
|
||||
|
||||
publicAPI.objects.eventEmitter = jasmine.createSpyObj('eventemitter', [
|
||||
'on'
|
||||
]);
|
||||
@@ -91,7 +103,7 @@ define([
|
||||
beforeEach(function () {
|
||||
listener = jasmine.createSpy('reorderListener');
|
||||
composition.on('reorder', listener);
|
||||
|
||||
|
||||
return composition.load();
|
||||
});
|
||||
it('', function () {
|
||||
@@ -119,49 +131,16 @@ define([
|
||||
expect(newComposition[2].key).toEqual('a');
|
||||
})
|
||||
});
|
||||
|
||||
// TODO: Implement add/removal in new default provider.
|
||||
xit('synchronizes changes between instances', function () {
|
||||
var otherComposition = compositionAPI.get(domainObject);
|
||||
var addListener = jasmine.createSpy('addListener');
|
||||
var removeListener = jasmine.createSpy('removeListener');
|
||||
var otherAddListener = jasmine.createSpy('otherAddListener');
|
||||
var otherRemoveListener = jasmine.createSpy('otherRemoveListener');
|
||||
it('supports adding an object to composition', function () {
|
||||
let addListener = jasmine.createSpy('addListener');
|
||||
let mockChildObject = {
|
||||
identifier: {key: 'mock-key', namespace: ''}
|
||||
};
|
||||
composition.on('add', addListener);
|
||||
composition.on('remove', removeListener);
|
||||
otherComposition.on('add', otherAddListener);
|
||||
otherComposition.on('remove', otherRemoveListener);
|
||||
composition.add(mockChildObject);
|
||||
|
||||
return Promise.all([composition.load(), otherComposition.load()])
|
||||
.then(function () {
|
||||
expect(addListener).toHaveBeenCalled();
|
||||
expect(otherAddListener).toHaveBeenCalled();
|
||||
expect(removeListener).not.toHaveBeenCalled();
|
||||
expect(otherRemoveListener).not.toHaveBeenCalled();
|
||||
|
||||
var object = addListener.calls.mostRecent().args[0];
|
||||
composition.remove(object);
|
||||
expect(removeListener).toHaveBeenCalled();
|
||||
expect(otherRemoveListener).toHaveBeenCalled();
|
||||
|
||||
addListener.reset();
|
||||
otherAddListener.reset();
|
||||
composition.add(object);
|
||||
expect(addListener).toHaveBeenCalled();
|
||||
expect(otherAddListener).toHaveBeenCalled();
|
||||
|
||||
removeListener.reset();
|
||||
otherRemoveListener.reset();
|
||||
otherComposition.remove(object);
|
||||
expect(removeListener).toHaveBeenCalled();
|
||||
expect(otherRemoveListener).toHaveBeenCalled();
|
||||
|
||||
addListener.reset();
|
||||
otherAddListener.reset();
|
||||
otherComposition.add(object);
|
||||
expect(addListener).toHaveBeenCalled();
|
||||
expect(otherAddListener).toHaveBeenCalled();
|
||||
});
|
||||
expect(domainObject.composition.length).toBe(4);
|
||||
expect(domainObject.composition[3]).toEqual(mockChildObject.identifier);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -184,7 +163,9 @@ define([
|
||||
key: 'thing'
|
||||
}
|
||||
]);
|
||||
}
|
||||
},
|
||||
add: jasmine.createSpy('add'),
|
||||
remove: jasmine.createSpy('remove')
|
||||
};
|
||||
domainObject = {
|
||||
identifier: {
|
||||
@@ -214,6 +195,25 @@ define([
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Calling add or remove', function () {
|
||||
let mockChildObject;
|
||||
|
||||
beforeEach(function () {
|
||||
mockChildObject = {
|
||||
identifier: {key: 'mock-key', namespace: ''}
|
||||
};
|
||||
composition.add(mockChildObject);
|
||||
});
|
||||
|
||||
it('calls add on the provider', function () {
|
||||
expect(customProvider.add).toHaveBeenCalledWith(domainObject, mockChildObject.identifier);
|
||||
});
|
||||
|
||||
it('calls remove on the provider', function () {
|
||||
composition.remove(mockChildObject);
|
||||
expect(customProvider.remove).toHaveBeenCalledWith(domainObject, mockChildObject.identifier);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('dynamic custom composition', function () {
|
||||
|
||||
@@ -75,9 +75,7 @@ define([
|
||||
throw new Error('Event not supported by composition: ' + event);
|
||||
}
|
||||
if (!this.mutationListener) {
|
||||
this.mutationListener = this.publicAPI.objects.observe(this.domainObject, '*', (newDomainObject) => {
|
||||
this.domainObject = newDomainObject;
|
||||
})
|
||||
this._synchronize();
|
||||
}
|
||||
if (this.provider.on && this.provider.off) {
|
||||
if (event === 'add') {
|
||||
@@ -134,10 +132,8 @@ define([
|
||||
|
||||
this.listeners[event].splice(index, 1);
|
||||
if (this.listeners[event].length === 0) {
|
||||
if (this.mutationListener) {
|
||||
this.mutationListener();
|
||||
delete this.mutationListener;
|
||||
}
|
||||
this._destroy();
|
||||
|
||||
// Remove provider listener if this is the last callback to
|
||||
// be removed.
|
||||
if (this.provider.off && this.provider.on) {
|
||||
@@ -181,6 +177,9 @@ define([
|
||||
*/
|
||||
CompositionCollection.prototype.add = function (child, skipMutate) {
|
||||
if (!skipMutate) {
|
||||
if (!this.publicAPI.composition.checkPolicy(this.domainObject, child)) {
|
||||
throw `Object of type ${child.type} cannot be added to object of type ${this.domainObject.type}`;
|
||||
}
|
||||
this.provider.add(this.domainObject, child.identifier);
|
||||
} else {
|
||||
this.emit('add', child);
|
||||
@@ -272,6 +271,19 @@ define([
|
||||
this.remove(child, true);
|
||||
};
|
||||
|
||||
CompositionCollection.prototype._synchronize = function () {
|
||||
this.mutationListener = this.publicAPI.objects.observe(this.domainObject, '*', (newDomainObject) => {
|
||||
this.domainObject = JSON.parse(JSON.stringify(newDomainObject));
|
||||
});
|
||||
};
|
||||
|
||||
CompositionCollection.prototype._destroy = function () {
|
||||
if (this.mutationListener) {
|
||||
this.mutationListener();
|
||||
delete this.mutationListener;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Emit events.
|
||||
* @private
|
||||
|
||||
@@ -48,24 +48,11 @@ define([
|
||||
this.listeningTo = {};
|
||||
this.onMutation = this.onMutation.bind(this);
|
||||
|
||||
this.cannotContainDuplicates = this.cannotContainDuplicates.bind(this);
|
||||
this.cannotContainItself = this.cannotContainItself.bind(this);
|
||||
|
||||
compositionAPI.addPolicy(this.cannotContainDuplicates);
|
||||
compositionAPI.addPolicy(this.cannotContainItself);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
DefaultCompositionProvider.prototype.cannotContainDuplicates = function (parent, child) {
|
||||
return this.appliesTo(parent) &&
|
||||
parent.composition.findIndex((composeeId) => {
|
||||
return composeeId.namespace === child.identifier.namespace &&
|
||||
composeeId.key === child.identifier.key;
|
||||
}) === -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -199,9 +186,18 @@ define([
|
||||
* @memberof module:openmct.CompositionProvider#
|
||||
* @method add
|
||||
*/
|
||||
DefaultCompositionProvider.prototype.add = function (domainObject, child) {
|
||||
throw new Error('Default Provider does not implement adding.');
|
||||
// TODO: this needs to be synchronized via mutation
|
||||
DefaultCompositionProvider.prototype.add = function (parent, childId) {
|
||||
if (!this.includes(parent, childId)) {
|
||||
parent.composition.push(childId);
|
||||
this.publicAPI.objects.mutate(parent, 'composition', parent.composition);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
DefaultCompositionProvider.prototype.includes = function (parent, childId) {
|
||||
return parent.composition.findIndex(composee =>
|
||||
this.publicAPI.objects.areIdsEqual(composee, childId)) !== -1;
|
||||
};
|
||||
|
||||
DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) {
|
||||
|
||||
@@ -28,7 +28,7 @@ define(['zepto', './res/indicator-template.html'],
|
||||
this.openmct = openmct;
|
||||
this.element = $(indicatorTemplate)[0];
|
||||
|
||||
this.textElement = this.element.querySelector('.indicator-text');
|
||||
this.textElement = this.element.querySelector('.js-indicator-text');
|
||||
|
||||
//Set defaults
|
||||
this.text('New Indicator');
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<div class="ls-indicator" title="">
|
||||
<span class="label indicator-text"></span>
|
||||
<div class="c-indicator c-indicator--clickable c-indicator--simple" title="">
|
||||
<span class="label js-indicator-text c-indicator__label"></span>
|
||||
</div>
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
&.message-severity-error:before {
|
||||
@include legacyMessage();
|
||||
content: $glyph-icon-alert-triangle;
|
||||
color: $colorWarningLo;
|
||||
color: $colorWarningHi;
|
||||
}
|
||||
|
||||
// Messages in a list
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__top-bar {
|
||||
@@ -92,6 +93,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
height: 0; // Chrome 73 overflow bug fix
|
||||
overflow: auto;
|
||||
padding-right: $interiorMargin; // fend off scroll bar
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./components/LadTable.vue',
|
||||
'./components/LADTable.vue',
|
||||
'vue'
|
||||
], function (
|
||||
LadTableComponent,
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
<script>
|
||||
import lodash from 'lodash';
|
||||
import LadRow from './LadRow.vue';
|
||||
import LadRow from './LADRow.vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'domainObject'],
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
<script>
|
||||
import lodash from 'lodash';
|
||||
import LadRow from './LadRow.vue';
|
||||
import LadRow from './LADRow.vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'domainObject'],
|
||||
|
||||
39
src/plugins/clearData/clearDataAction.js
Normal file
39
src/plugins/clearData/clearDataAction.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
export default class ClearDataAction {
|
||||
constructor(openmct, appliesToObjects) {
|
||||
this.name = 'Clear Data';
|
||||
this.description = 'Clears current data for object, unsubscribes and resubscribes to data';
|
||||
|
||||
this._openmct = openmct;
|
||||
this._appliesToObjects = appliesToObjects;
|
||||
}
|
||||
invoke(objectPath) {
|
||||
this._openmct.objectViews.emit('clearData', objectPath[0]);
|
||||
}
|
||||
appliesTo(objectPath) {
|
||||
let contextualDomainObject = objectPath[0];
|
||||
|
||||
return this._appliesToObjects.filter(type => contextualDomainObject.type === type).length;
|
||||
}
|
||||
}
|
||||
18
src/plugins/clearData/components/globalClearIndicator.vue
Normal file
18
src/plugins/clearData/components/globalClearIndicator.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div class="c-indicator c-indicator--clickable icon-session">
|
||||
<span class="label c-indicator__label">
|
||||
<button @click="globalClearEmit">Clear All Data</button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
methods: {
|
||||
globalClearEmit() {
|
||||
this.openmct.objectViews.emit('clearData');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
54
src/plugins/clearData/plugin.js
Normal file
54
src/plugins/clearData/plugin.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2019, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./components/globalClearIndicator.vue',
|
||||
'./clearDataAction',
|
||||
'vue'
|
||||
], function (
|
||||
GlobaClearIndicator,
|
||||
ClearDataAction,
|
||||
Vue
|
||||
) {
|
||||
return function plugin(appliesToObjects) {
|
||||
appliesToObjects = appliesToObjects || [];
|
||||
|
||||
return function install(openmct) {
|
||||
let component = new Vue ({
|
||||
provide: {
|
||||
openmct
|
||||
},
|
||||
components: {
|
||||
GlobalClearIndicator: GlobaClearIndicator.default
|
||||
},
|
||||
template: '<GlobalClearIndicator></GlobalClearIndicator>'
|
||||
}),
|
||||
indicator = {
|
||||
element: component.$mount().$el
|
||||
};
|
||||
|
||||
openmct.indicators.add(indicator);
|
||||
|
||||
openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
|
||||
};
|
||||
};
|
||||
});
|
||||
62
src/plugins/clearData/test/clearDataActionSpec.js
Normal file
62
src/plugins/clearData/test/clearDataActionSpec.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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 ClearDataActionPlugin from '../plugin.js';
|
||||
import ClearDataAction from '../clearDataAction.js';
|
||||
|
||||
describe('When the Clear Data Plugin is installed,', function () {
|
||||
var mockObjectViews = jasmine.createSpyObj('objectViews', ['emit']),
|
||||
mockIndicatorProvider = jasmine.createSpyObj('indicators', ['add']),
|
||||
mockContextMenuProvider = jasmine.createSpyObj('contextMenu', ['registerAction']),
|
||||
openmct = {
|
||||
objectViews: mockObjectViews,
|
||||
indicators: mockIndicatorProvider,
|
||||
contextMenu: mockContextMenuProvider,
|
||||
install: function (plugin) {
|
||||
plugin(this);
|
||||
}
|
||||
},
|
||||
mockObjectPath = [
|
||||
{name: 'mockObject1'},
|
||||
{name: 'mockObject2'}
|
||||
];
|
||||
|
||||
it('Global Clear Indicator is installed', function () {
|
||||
openmct.install(ClearDataActionPlugin([]));
|
||||
|
||||
expect(mockIndicatorProvider.add).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Clear Data context menu action is installed', function () {
|
||||
openmct.install(ClearDataActionPlugin([]));
|
||||
|
||||
expect(mockContextMenuProvider.registerAction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('clear data action emits a clearData event when invoked', function () {
|
||||
let action = new ClearDataAction(openmct);
|
||||
|
||||
action.invoke(mockObjectPath);
|
||||
|
||||
expect(mockObjectViews.emit).toHaveBeenCalledWith('clearData', mockObjectPath[0]);
|
||||
});
|
||||
});
|
||||
77
src/plugins/displayLayout/AlphanumericFormatViewProvider.js
Normal file
77
src/plugins/displayLayout/AlphanumericFormatViewProvider.js
Normal file
@@ -0,0 +1,77 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./components/AlphanumericFormatView.vue',
|
||||
'vue'
|
||||
], function (AlphanumericFormatView, Vue) {
|
||||
|
||||
function AlphanumericFormatViewProvider(openmct, options) {
|
||||
function isTelemetryObject(selectionPath) {
|
||||
let selectedObject = selectionPath[0].context.item;
|
||||
let parentObject = selectionPath[1].context.item;
|
||||
return parentObject &&
|
||||
parentObject.type === 'layout' &&
|
||||
selectedObject &&
|
||||
openmct.telemetry.isTelemetryObject(selectedObject) &&
|
||||
!options.showAsView.includes(selectedObject.type)
|
||||
}
|
||||
|
||||
return {
|
||||
key: 'alphanumeric-format',
|
||||
name: 'Alphanumeric Format',
|
||||
canView: function (selection) {
|
||||
if (selection.length === 0 || selection[0].length === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return selection.every(isTelemetryObject);
|
||||
},
|
||||
view: function (selection) {
|
||||
let component;
|
||||
return {
|
||||
show: function (element) {
|
||||
component = new Vue({
|
||||
provide: {
|
||||
openmct
|
||||
},
|
||||
components: {
|
||||
AlphanumericFormatView: AlphanumericFormatView.default
|
||||
},
|
||||
template: '<alphanumeric-format-view></alphanumeric-format-view>',
|
||||
el: element
|
||||
});
|
||||
},
|
||||
destroy: function () {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
priority: function () {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AlphanumericFormatViewProvider;
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="c-properties" v-if="isEditing">
|
||||
<div class="c-properties__header">Alphanumeric Format</div>
|
||||
<ul class="c-properties__section">
|
||||
<li class="c-properties__row">
|
||||
<div class="c-properties__label" title="Printf formatting for the selected telemetry">
|
||||
<label for="telemetryPrintfFormat">Format</label>
|
||||
</div>
|
||||
<div class="c-properties__value">
|
||||
<input id="telemetryPrintfFormat"
|
||||
type="text"
|
||||
@change="formatTelemetry"
|
||||
:value="telemetryFormat"
|
||||
:placeholder="nonMixedFormat ? '' : 'Mixed'"
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
data() {
|
||||
let selectionPath = this.openmct.selection.get()[0];
|
||||
return {
|
||||
isEditing: this.openmct.editor.isEditing(),
|
||||
telemetryFormat: undefined,
|
||||
nonMixedFormat: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleEdit(isEditing) {
|
||||
this.isEditing = isEditing;
|
||||
},
|
||||
formatTelemetry(event) {
|
||||
let newFormat = event.currentTarget.value;
|
||||
this.openmct.selection.get().forEach(selectionPath => {
|
||||
selectionPath[0].context.updateTelemetryFormat(newFormat);
|
||||
});
|
||||
this.telemetryFormat = newFormat;
|
||||
},
|
||||
handleSelection(selection) {
|
||||
if (selection.length === 0 || selection[0].length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
let format = selection[0][0].context.layoutItem.format;
|
||||
this.nonMixedFormat = selection.every(selectionPath => {
|
||||
return selectionPath[0].context.layoutItem.format === format;
|
||||
});
|
||||
|
||||
this.telemetryFormat = this.nonMixedFormat ? format : '';
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.editor.on('isEditing', this.toggleEdit);
|
||||
this.openmct.selection.on('change', this.handleSelection);
|
||||
this.handleSelection(this.openmct.selection.get());
|
||||
},
|
||||
destroyed() {
|
||||
this.openmct.editor.off('isEditing', this.toggleEdit);
|
||||
this.openmct.selection.off('change', this.handleSelection);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -48,7 +48,8 @@
|
||||
:multiSelect="selectedLayoutItems.length > 1"
|
||||
@move="move"
|
||||
@endMove="endMove"
|
||||
@endLineResize='endLineResize'>
|
||||
@endLineResize='endLineResize'
|
||||
@formatChanged='updateTelemetryFormat'>
|
||||
</component>
|
||||
<edit-marquee v-if='showMarquee'
|
||||
:gridSize="gridSize"
|
||||
@@ -269,33 +270,63 @@
|
||||
_.cloneDeep(this.selectedLayoutItems).forEach(selectedItem => {
|
||||
if (selectedItem.type === 'line-view') {
|
||||
this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y, selectedItem.x2, selectedItem.y2];
|
||||
this.startingMinX2 = this.startingMinX2 !== undefined ? Math.min(this.startingMinX2, selectedItem.x2) : selectedItem.x2;
|
||||
this.startingMinY2 = this.startingMinY2 !== undefined ? Math.min(this.startingMinY2, selectedItem.y2) : selectedItem.y2;
|
||||
} else {
|
||||
this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y];
|
||||
}
|
||||
|
||||
this.startingMinX = this.startingMinX !== undefined ? Math.min(this.startingMinX, selectedItem.x) : selectedItem.x;
|
||||
this.startingMinY = this.startingMinY !== undefined ? Math.min(this.startingMinY, selectedItem.y) : selectedItem.y;
|
||||
});
|
||||
}
|
||||
|
||||
let layoutItems = this.layoutItems.map(item => {
|
||||
if (this.initialPositions[item.id]) {
|
||||
let startingPosition = this.initialPositions[item.id];
|
||||
let [startingX, startingY, startingX2, startingY2] = startingPosition;
|
||||
item.x = startingX + gridDelta[0];
|
||||
item.y = startingY + gridDelta[1];
|
||||
|
||||
if (item.x2) {
|
||||
item.x2 = startingX2 + gridDelta[0];
|
||||
}
|
||||
|
||||
if (item.y2) {
|
||||
item.y2 = startingY2 + gridDelta[1];
|
||||
}
|
||||
this.updateItemPosition(item, gridDelta);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
},
|
||||
updateItemPosition(item, gridDelta) {
|
||||
let startingPosition = this.initialPositions[item.id];
|
||||
let [startingX, startingY, startingX2, startingY2] = startingPosition;
|
||||
|
||||
if (this.startingMinX + gridDelta[0] >= 0) {
|
||||
if (item.x2 !== undefined) {
|
||||
if (this.startingMinX2 + gridDelta[0] >= 0) {
|
||||
item.x = startingX + gridDelta[0];
|
||||
}
|
||||
} else {
|
||||
item.x = startingX + gridDelta[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (this.startingMinY + gridDelta[1] >= 0) {
|
||||
if (item.y2 !== undefined) {
|
||||
if (this.startingMinY2 + gridDelta[1] >= 0) {
|
||||
item.y = startingY + gridDelta[1];
|
||||
}
|
||||
} else {
|
||||
item.y = startingY + gridDelta[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (item.x2 !== undefined && this.startingMinX2 + gridDelta[0] >= 0 && this.startingMinX + gridDelta[0] >= 0) {
|
||||
item.x2 = startingX2 + gridDelta[0];
|
||||
}
|
||||
|
||||
if (item.y2 !== undefined && this.startingMinY2 + gridDelta[1] >= 0 && this.startingMinY + gridDelta[1] >= 0) {
|
||||
item.y2 = startingY2 + gridDelta[1];
|
||||
}
|
||||
},
|
||||
endMove() {
|
||||
this.mutate('configuration.items', this.layoutItems);
|
||||
this.initialPositions = undefined;
|
||||
this.startingMinX = undefined;
|
||||
this.startingMinY = undefined;
|
||||
this.startingMinX2 = undefined;
|
||||
this.startingMinY2 = undefined;
|
||||
},
|
||||
mutate(path, value) {
|
||||
this.openmct.objects.mutate(this.internalDomainObject, path, value);
|
||||
@@ -527,6 +558,11 @@
|
||||
this.layoutItems.splice(itemIndex, 1);
|
||||
this.layoutItems.splice(newIndex, 0, items[itemIndex]);
|
||||
}
|
||||
},
|
||||
updateTelemetryFormat(item, format) {
|
||||
let index = _.findIndex(this.layoutItems, item);
|
||||
item.format = format;
|
||||
this.mutate(`configuration.items[${index}]`, item);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
let height = Number.NEGATIVE_INFINITY;
|
||||
|
||||
this.selectedLayoutItems.forEach(item => {
|
||||
if (item.x2) {
|
||||
if (item.x2 !== undefined) {
|
||||
let lineWidth = Math.abs(item.x - item.x2);
|
||||
let lineMinX = Math.min(item.x, item.x2);
|
||||
x = Math.min(lineMinX, x);
|
||||
@@ -126,7 +126,7 @@
|
||||
width = Math.max(item.width + item.x, width);
|
||||
}
|
||||
|
||||
if (item.y2) {
|
||||
if (item.y2 !== undefined) {
|
||||
let lineHeight = Math.abs(item.y - item.y2);
|
||||
let lineMinY = Math.min(item.y, item.y2);
|
||||
y = Math.min(lineMinY, y);
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
|
||||
<script>
|
||||
import LayoutFrame from './LayoutFrame.vue'
|
||||
import printj from 'printj'
|
||||
|
||||
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
|
||||
DEFAULT_POSITION = [1, 1];
|
||||
@@ -143,6 +144,10 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.item.format) {
|
||||
return printj.sprintf(this.item.format, this.datum[this.valueMetadata.key]);
|
||||
}
|
||||
|
||||
return this.valueFormatter && this.valueFormatter.format(this.datum);
|
||||
},
|
||||
telemetryClass() {
|
||||
@@ -168,6 +173,9 @@
|
||||
}
|
||||
|
||||
this.context.index = newIndex;
|
||||
},
|
||||
item(newItem) {
|
||||
this.context.layoutItem = newItem;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -219,10 +227,14 @@
|
||||
this.context = {
|
||||
item: domainObject,
|
||||
layoutItem: this.item,
|
||||
index: this.index
|
||||
index: this.index,
|
||||
updateTelemetryFormat: this.updateTelemetryFormat
|
||||
};
|
||||
this.removeSelectable = this.openmct.selection.selectable(
|
||||
this.$el, this.context, this.initSelect);
|
||||
},
|
||||
updateTelemetryFormat(format) {
|
||||
this.$emit('formatChanged', this.item, format);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -25,6 +25,8 @@ import Vue from 'vue'
|
||||
import objectUtils from '../../api/objects/object-utils.js'
|
||||
import DisplayLayoutType from './DisplayLayoutType.js'
|
||||
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js'
|
||||
import AlphaNumericFormatViewProvider from './AlphanumericFormatViewProvider.js'
|
||||
|
||||
export default function DisplayLayoutPlugin(options) {
|
||||
return function (openmct) {
|
||||
openmct.objectViews.addProvider({
|
||||
@@ -76,7 +78,8 @@ export default function DisplayLayoutPlugin(options) {
|
||||
}
|
||||
});
|
||||
openmct.types.addType('layout', DisplayLayoutType());
|
||||
openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct));
|
||||
openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct, options));
|
||||
openmct.inspectorViews.addProvider(new AlphaNumericFormatViewProvider(openmct, options));
|
||||
openmct.composition.addPolicy((parent, child) => {
|
||||
if (parent.type === 'layout' && child.type === 'folder') {
|
||||
return false;
|
||||
|
||||
@@ -63,7 +63,13 @@ export default {
|
||||
|
||||
if (filterValue && filterValue[comparator]) {
|
||||
if (value === false) {
|
||||
filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
|
||||
let filteredValueName = filterValue[comparator].filter(v => v !== valueName);
|
||||
|
||||
if (filteredValueName.length === 0) {
|
||||
delete this.updatedFilters[key];
|
||||
} else {
|
||||
filterValue[comparator] = filteredValueName;
|
||||
}
|
||||
} else {
|
||||
filterValue[comparator].push(valueName);
|
||||
}
|
||||
@@ -77,6 +83,14 @@ export default {
|
||||
this.$emit('updateFilters', this.keyString, this.updatedFilters);
|
||||
},
|
||||
updateTextFilter(key, comparator, value) {
|
||||
if (value.trim() === '') {
|
||||
if (this.updatedFilters[key]) {
|
||||
delete this.updatedFilters[key];
|
||||
this.$emit('updateFilters', this.keyString, this.updatedFilters);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.updatedFilters[key]) {
|
||||
this.$set(this.updatedFilters, key, {});
|
||||
this.$set(this.updatedFilters[key], comparator, '');
|
||||
|
||||
@@ -59,14 +59,18 @@ export default {
|
||||
removeChildren(identifier) {
|
||||
let keyString = this.openmct.objects.makeKeyString(identifier);
|
||||
this.$delete(this.children, keyString);
|
||||
this.persistFilters(keyString);
|
||||
delete this.persistedFilters[keyString];
|
||||
this.mutateConfigurationFilters();
|
||||
},
|
||||
persistFilters(keyString, userSelects) {
|
||||
this.persistedFilters[keyString] = userSelects;
|
||||
this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
|
||||
this.mutateConfigurationFilters();
|
||||
},
|
||||
updatePersistedFilters(filters) {
|
||||
this.persistedFilters = filters;
|
||||
},
|
||||
mutateConfigurationFilters() {
|
||||
this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
|
||||
53
src/plugins/goToOriginalAction/goToOriginalAction.js
Normal file
53
src/plugins/goToOriginalAction/goToOriginalAction.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
export default class GoToOriginalAction {
|
||||
constructor(openmct) {
|
||||
this.name = 'Go To Original';
|
||||
this.description = 'Go to the original unlinked instance of this object';
|
||||
|
||||
this._openmct = openmct;
|
||||
}
|
||||
invoke(objectPath) {
|
||||
this._openmct.objects.getOriginalPath(objectPath[0].identifier)
|
||||
.then((originalPath) => {
|
||||
let url = '#/browse/' + originalPath
|
||||
.map(function (o) {
|
||||
return o && this._openmct.objects.makeKeyString(o.identifier);
|
||||
}.bind(this))
|
||||
.reverse()
|
||||
.slice(1)
|
||||
.join('/');
|
||||
|
||||
window.location.href = url;
|
||||
});
|
||||
}
|
||||
appliesTo(objectPath) {
|
||||
let parentKeystring = objectPath[1] && this._openmct.objects.makeKeyString(objectPath[1].identifier);
|
||||
|
||||
if (!parentKeystring) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (parentKeystring !== objectPath[0].location);
|
||||
}
|
||||
}
|
||||
28
src/plugins/goToOriginalAction/plugin.js
Normal file
28
src/plugins/goToOriginalAction/plugin.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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 GoToOriginalAction from './goToOriginalAction';
|
||||
|
||||
export default function () {
|
||||
return function (openmct) {
|
||||
openmct.contextMenu.registerAction(new GoToOriginalAction(openmct));
|
||||
};
|
||||
}
|
||||
@@ -64,12 +64,41 @@ define([
|
||||
Object.keys(panels).forEach(key => {
|
||||
let panel = panels[key];
|
||||
let domainObject = childObjects[key];
|
||||
let identifier = undefined;
|
||||
|
||||
if (isTelemetry(domainObject)) {
|
||||
// If object is a telemetry point, convert it to a plot and
|
||||
// replace the object in migratedObject composition with the plot.
|
||||
identifier = {
|
||||
key: uuid(),
|
||||
namespace: migratedObject.identifier.namespace
|
||||
};
|
||||
let plotObject = {
|
||||
identifier: identifier,
|
||||
location: domainObject.location,
|
||||
name: domainObject.name,
|
||||
type: "telemetry.plot.overlay"
|
||||
};
|
||||
let plotType = openmct.types.get('telemetry.plot.overlay');
|
||||
plotType.definition.initialize(plotObject);
|
||||
plotObject.composition.push(domainObject.identifier);
|
||||
openmct.objects.mutate(plotObject, 'persisted', Date.now());
|
||||
|
||||
let keyString = openmct.objects.makeKeyString(domainObject.identifier);
|
||||
let clonedComposition = Object.assign([], migratedObject.composition);
|
||||
clonedComposition.forEach((identifier, index) => {
|
||||
if (openmct.objects.makeKeyString(identifier) === keyString) {
|
||||
migratedObject.composition[index] = plotObject.identifier;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
width: panel.dimensions[0],
|
||||
height: panel.dimensions[1],
|
||||
x: panel.position[0],
|
||||
y: panel.position[1],
|
||||
identifier: domainObject.identifier,
|
||||
identifier: identifier || domainObject.identifier,
|
||||
id: uuid(),
|
||||
type: 'subobject-view',
|
||||
hasFrame: panel.hasFrame
|
||||
@@ -148,7 +177,9 @@ define([
|
||||
return [
|
||||
{
|
||||
check(domainObject) {
|
||||
return domainObject.type === 'layout' && domainObject.configuration.layout;
|
||||
return domainObject.type === 'layout' &&
|
||||
domainObject.configuration &&
|
||||
domainObject.configuration.layout;
|
||||
},
|
||||
migrate(domainObject) {
|
||||
let childObjects = {};
|
||||
@@ -167,7 +198,9 @@ define([
|
||||
},
|
||||
{
|
||||
check(domainObject) {
|
||||
return domainObject.type === 'telemetry.fixed' && domainObject.configuration['fixed-display'];
|
||||
return domainObject.type === 'telemetry.fixed' &&
|
||||
domainObject.configuration &&
|
||||
domainObject.configuration['fixed-display'];
|
||||
},
|
||||
migrate(domainObject) {
|
||||
const DEFAULT_GRID_SIZE = [64, 16];
|
||||
@@ -205,6 +238,7 @@ define([
|
||||
{
|
||||
check(domainObject) {
|
||||
return domainObject.type === 'table' &&
|
||||
domainObject.configuration &&
|
||||
domainObject.configuration.table;
|
||||
},
|
||||
migrate(domainObject) {
|
||||
|
||||
@@ -115,11 +115,13 @@ define([
|
||||
|
||||
Collection.prototype.remove = function (model) {
|
||||
var index = this.indexOf(model);
|
||||
|
||||
if (index === -1) {
|
||||
throw new Error('model not found in collection.');
|
||||
}
|
||||
this.models.splice(index, 1);
|
||||
|
||||
this.emit('remove', model, index);
|
||||
this.models.splice(index, 1);
|
||||
};
|
||||
|
||||
Collection.prototype.destroy = function (model) {
|
||||
|
||||
@@ -377,6 +377,19 @@ define([
|
||||
delete this.unsubscribe;
|
||||
}
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the plot series, unsubscribes and resubscribes
|
||||
* @public
|
||||
*/
|
||||
refresh: function () {
|
||||
this.reset();
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
delete this.unsubscribe;
|
||||
}
|
||||
this.fetch();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -100,19 +100,33 @@ define([
|
||||
removeTelemetryObject: function (identifier) {
|
||||
var plotObject = this.plot.get('domainObject');
|
||||
if (plotObject.type === 'telemetry.plot.overlay') {
|
||||
var index = _.findIndex(plotObject.configuration.series, function (s) {
|
||||
|
||||
var persistedIndex = _.findIndex(plotObject.configuration.series, function (s) {
|
||||
return _.isEqual(identifier, s.identifier);
|
||||
});
|
||||
this.remove(this.at(index));
|
||||
// Because this is triggered by a composition change, we have
|
||||
// to defer mutation of our plot object, otherwise we might
|
||||
// mutate an outdated version of the plotObject.
|
||||
setTimeout(function () {
|
||||
var newPlotObject = this.plot.get('domainObject');
|
||||
var cSeries = newPlotObject.configuration.series.slice();
|
||||
cSeries.splice(index, 1);
|
||||
this.openmct.objects.mutate(newPlotObject, 'configuration.series', cSeries);
|
||||
}.bind(this));
|
||||
|
||||
var configIndex = _.findIndex(this.models, function (m) {
|
||||
return _.isEqual(m.domainObject.identifier, identifier);
|
||||
});
|
||||
|
||||
/*
|
||||
when cancelling out of edit mode, the config store and domain object are out of sync
|
||||
thus it is necesarry to check both and remove the models that are no longer in composition
|
||||
*/
|
||||
if (persistedIndex === -1) {
|
||||
this.remove(this.at(configIndex));
|
||||
} else {
|
||||
this.remove(this.at(persistedIndex));
|
||||
// Because this is triggered by a composition change, we have
|
||||
// to defer mutation of our plot object, otherwise we might
|
||||
// mutate an outdated version of the plotObject.
|
||||
setTimeout(function () {
|
||||
var newPlotObject = this.plot.get('domainObject');
|
||||
var cSeries = newPlotObject.configuration.series.slice();
|
||||
cSeries.splice(persistedIndex, 1);
|
||||
this.openmct.objects.mutate(newPlotObject, 'configuration.series', cSeries);
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
},
|
||||
onSeriesAdd: function (series) {
|
||||
|
||||
@@ -25,23 +25,11 @@ define([
|
||||
|
||||
function ConfigStore() {
|
||||
this.store = {};
|
||||
this.tracking = {};
|
||||
}
|
||||
|
||||
ConfigStore.prototype.track = function (id) {
|
||||
if (!this.tracking[id]) {
|
||||
this.tracking[id] = 0;
|
||||
}
|
||||
this.tracking[id] += 1;
|
||||
};
|
||||
|
||||
ConfigStore.prototype.untrack = function (id) {
|
||||
this.tracking[id] -= 1;
|
||||
if (this.tracking[id] <= 0) {
|
||||
delete this.tracking[id];
|
||||
this.store[id].destroy();
|
||||
delete this.store[id];
|
||||
}
|
||||
ConfigStore.prototype.deleteStore = function (id) {
|
||||
this.store[id].destroy();
|
||||
delete this.store[id];
|
||||
};
|
||||
|
||||
ConfigStore.prototype.add = function (id, config) {
|
||||
|
||||
@@ -49,7 +49,6 @@ define([
|
||||
};
|
||||
|
||||
PlotOptionsController.prototype.destroy = function () {
|
||||
configStore.untrack(this.configId);
|
||||
this.stopListening();
|
||||
this.unlisten();
|
||||
};
|
||||
@@ -60,7 +59,7 @@ define([
|
||||
this.$timeout(this.setUpScope.bind(this));
|
||||
return;
|
||||
}
|
||||
configStore.track(this.configId);
|
||||
|
||||
this.config = this.$scope.config = config;
|
||||
this.$scope.plotSeries = [];
|
||||
|
||||
|
||||
@@ -282,11 +282,19 @@ define([
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.zoom = function (zoomDirection, zoomFactor) {
|
||||
var currentXaxis = this.$scope.xAxis.get('displayRange'),
|
||||
currentYaxis = this.$scope.yAxis.get('displayRange');
|
||||
|
||||
// when there is no plot data, the ranges can be undefined
|
||||
// in which case we should not perform zoom
|
||||
if (!currentXaxis || !currentYaxis) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.freeze();
|
||||
this.trackHistory();
|
||||
var currentXaxis = this.$scope.xAxis.get('displayRange'),
|
||||
currentYaxis = this.$scope.yAxis.get('displayRange'),
|
||||
xAxisDist= (currentXaxis.max - currentXaxis.min) * zoomFactor,
|
||||
|
||||
var xAxisDist= (currentXaxis.max - currentXaxis.min) * zoomFactor,
|
||||
yAxisDist = (currentYaxis.max - currentYaxis.min) * zoomFactor;
|
||||
|
||||
if (zoomDirection === 'in') {
|
||||
@@ -322,12 +330,19 @@ define([
|
||||
return;
|
||||
}
|
||||
|
||||
let xDisplayRange = this.$scope.xAxis.get('displayRange'),
|
||||
yDisplayRange = this.$scope.yAxis.get('displayRange');
|
||||
|
||||
// when there is no plot data, the ranges can be undefined
|
||||
// in which case we should not perform zoom
|
||||
if (!xDisplayRange || !yDisplayRange) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.freeze();
|
||||
window.clearTimeout(this.stillZooming);
|
||||
|
||||
let xDisplayRange = this.$scope.xAxis.get('displayRange'),
|
||||
yDisplayRange = this.$scope.yAxis.get('displayRange'),
|
||||
xAxisDist = (xDisplayRange.max - xDisplayRange.min),
|
||||
let xAxisDist = (xDisplayRange.max - xDisplayRange.min),
|
||||
yAxisDist = (yDisplayRange.max - yDisplayRange.min),
|
||||
xDistMouseToMax = xDisplayRange.max - this.positionOverPlot.x,
|
||||
xDistMouseToMin = this.positionOverPlot.x - xDisplayRange.min,
|
||||
|
||||
@@ -63,8 +63,11 @@ define([
|
||||
|
||||
$scope.pending = 0;
|
||||
|
||||
this.clearData = this.clearData.bind(this);
|
||||
|
||||
this.listenTo($scope, 'user:viewport:change:end', this.onUserViewportChangeEnd, this);
|
||||
this.listenTo($scope, '$destroy', this.destroy, this);
|
||||
this.listenTo($scope, 'clearData', this.clearData);
|
||||
|
||||
this.config = this.getConfig(this.$scope.domainObject);
|
||||
this.listenTo(this.config.series, 'add', this.addSeries, this);
|
||||
@@ -74,6 +77,7 @@ define([
|
||||
this.followTimeConductor();
|
||||
|
||||
this.newStyleDomainObject = $scope.domainObject.useCapability('adapter');
|
||||
this.keyString = this.openmct.objects.makeKeyString(this.newStyleDomainObject.identifier);
|
||||
|
||||
this.filterObserver = this.openmct.objects.observe(
|
||||
this.newStyleDomainObject,
|
||||
@@ -148,7 +152,6 @@ define([
|
||||
});
|
||||
configStore.add(configId, config);
|
||||
}
|
||||
configStore.track(configId);
|
||||
return config;
|
||||
};
|
||||
|
||||
@@ -157,7 +160,8 @@ define([
|
||||
};
|
||||
|
||||
PlotController.prototype.destroy = function () {
|
||||
configStore.untrack(this.config.id);
|
||||
configStore.deleteStore(this.config.id);
|
||||
|
||||
this.stopListening();
|
||||
if (this.checkForSize) {
|
||||
clearInterval(this.checkForSize);
|
||||
@@ -263,6 +267,12 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
PlotController.prototype.clearData = function () {
|
||||
this.config.series.forEach(function (series) {
|
||||
series.refresh();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Export view as JPG.
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
define([
|
||||
'lodash',
|
||||
'./utcTimeSystem/plugin',
|
||||
'./localTimeSystem/plugin',
|
||||
'../../example/generator/plugin',
|
||||
'./autoflow/AutoflowTabularPlugin',
|
||||
'./timeConductor/plugin',
|
||||
@@ -41,10 +42,13 @@ define([
|
||||
'./tabs/plugin',
|
||||
'./LADTable/plugin',
|
||||
'./filters/plugin',
|
||||
'./objectMigration/plugin'
|
||||
'./objectMigration/plugin',
|
||||
'./goToOriginalAction/plugin',
|
||||
'./clearData/plugin'
|
||||
], function (
|
||||
_,
|
||||
UTCTimeSystem,
|
||||
LocalTimeSystem,
|
||||
GeneratorPlugin,
|
||||
AutoflowPlugin,
|
||||
TimeConductorPlugin,
|
||||
@@ -63,7 +67,9 @@ define([
|
||||
Tabs,
|
||||
LADTable,
|
||||
Filters,
|
||||
ObjectMigration
|
||||
ObjectMigration,
|
||||
GoToOriginalAction,
|
||||
ClearData
|
||||
) {
|
||||
var bundleMap = {
|
||||
LocalStorage: 'platform/persistence/local',
|
||||
@@ -79,6 +85,7 @@ define([
|
||||
});
|
||||
|
||||
plugins.UTCTimeSystem = UTCTimeSystem;
|
||||
plugins.LocalTimeSystem = LocalTimeSystem;
|
||||
|
||||
plugins.ImportExport = ImportExport;
|
||||
|
||||
@@ -160,6 +167,8 @@ define([
|
||||
plugins.LADTable = LADTable;
|
||||
plugins.Filters = Filters;
|
||||
plugins.ObjectMigration = ObjectMigration.default;
|
||||
plugins.GoToOriginalAction = GoToOriginalAction.default;
|
||||
plugins.ClearData = ClearData;
|
||||
|
||||
return plugins;
|
||||
});
|
||||
|
||||
@@ -70,16 +70,14 @@ define([
|
||||
*/
|
||||
function onValueInput(event) {
|
||||
var elem = event.target,
|
||||
value = (isNaN(elem.valueAsNumber) ? elem.value : elem.valueAsNumber),
|
||||
value = isNaN(Number(elem.value)) ? elem.value : Number(elem.value),
|
||||
inputIndex = self.valueInputs.indexOf(elem);
|
||||
|
||||
if (elem.tagName.toUpperCase() === 'INPUT') {
|
||||
self.eventEmitter.emit('change', {
|
||||
value: value,
|
||||
property: 'values[' + inputIndex + ']',
|
||||
index: self.index
|
||||
});
|
||||
}
|
||||
self.eventEmitter.emit('change', {
|
||||
value: value,
|
||||
property: 'values[' + inputIndex + ']',
|
||||
index: self.index
|
||||
});
|
||||
}
|
||||
|
||||
this.listenTo(this.deleteButton, 'click', this.remove, this);
|
||||
@@ -108,8 +106,7 @@ define([
|
||||
Object.values(this.selects).forEach(function (select) {
|
||||
$('.t-configuration', self.domElement).append(select.getDOM());
|
||||
});
|
||||
|
||||
this.listenTo($(this.domElement), 'input', onValueInput);
|
||||
this.listenTo($('.t-value-inputs', this.domElement), 'input', onValueInput);
|
||||
}
|
||||
|
||||
Condition.prototype.getDOM = function (container) {
|
||||
@@ -167,7 +164,9 @@ define([
|
||||
|
||||
/**
|
||||
* When an operation is selected, create the appropriate value inputs
|
||||
* and add them to the view
|
||||
* and add them to the view. If an operation is of type enum, create
|
||||
* a drop-down menu instead.
|
||||
*
|
||||
* @param {string} operation The key of currently selected operation
|
||||
*/
|
||||
Condition.prototype.generateValueInputs = function (operation) {
|
||||
@@ -176,25 +175,49 @@ define([
|
||||
inputCount,
|
||||
inputType,
|
||||
newInput,
|
||||
index = 0;
|
||||
index = 0,
|
||||
emitChange = false;
|
||||
|
||||
inputArea.html('');
|
||||
this.valueInputs = [];
|
||||
this.config.values = [];
|
||||
|
||||
if (evaluator.getInputCount(operation)) {
|
||||
inputCount = evaluator.getInputCount(operation);
|
||||
inputType = evaluator.getInputType(operation);
|
||||
|
||||
while (index < inputCount) {
|
||||
if (!this.config.values[index]) {
|
||||
this.config.values[index] = (inputType === 'number' ? 0 : '');
|
||||
if (inputType === 'select') {
|
||||
newInput = $('<select>' + this.generateSelectOptions() + '</select>');
|
||||
emitChange = true;
|
||||
} else {
|
||||
this.config.values[index] = inputType === 'number' ? 0 : '';
|
||||
newInput = $('<input type = "' + inputType + '" value = "' + this.config.values[index] + '"> </input>');
|
||||
}
|
||||
newInput = $('<input type = "' + inputType + '" value = "' + this.config.values[index] + '"> </input>');
|
||||
|
||||
this.valueInputs.push(newInput.get(0));
|
||||
inputArea.append(newInput);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
if (emitChange) {
|
||||
this.eventEmitter.emit('change', {
|
||||
value: Number(newInput[0].options[0].value),
|
||||
property: 'values[0]',
|
||||
index: this.index
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Condition.prototype.generateSelectOptions = function () {
|
||||
let telemetryMetadata = this.conditionManager.getTelemetryMetadata(this.config.object);
|
||||
let options = '';
|
||||
telemetryMetadata[this.config.key].enumerations.forEach(enumeration => {
|
||||
options += '<option value="' + enumeration.value + '">'+ enumeration.string + '</option>';
|
||||
});
|
||||
return options;
|
||||
};
|
||||
|
||||
return Condition;
|
||||
});
|
||||
|
||||
@@ -24,7 +24,8 @@ define([], function () {
|
||||
*/
|
||||
this.inputTypes = {
|
||||
number: 'number',
|
||||
string: 'text'
|
||||
string: 'text',
|
||||
enum: 'select'
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -34,7 +35,8 @@ define([], function () {
|
||||
*/
|
||||
this.inputValidators = {
|
||||
number: this.validateNumberInput,
|
||||
string: this.validateStringInput
|
||||
string: this.validateStringInput,
|
||||
enum: this.validateNumberInput
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -201,7 +203,7 @@ define([], function () {
|
||||
return typeof input[0] === 'undefined';
|
||||
},
|
||||
text: 'is undefined',
|
||||
appliesTo: ['string', 'number'],
|
||||
appliesTo: ['string', 'number', 'enum'],
|
||||
inputCount: 0,
|
||||
getDescription: function () {
|
||||
return ' is undefined';
|
||||
@@ -212,11 +214,33 @@ define([], function () {
|
||||
return typeof input[0] !== 'undefined';
|
||||
},
|
||||
text: 'is defined',
|
||||
appliesTo: ['string', 'number'],
|
||||
appliesTo: ['string', 'number', 'enum'],
|
||||
inputCount: 0,
|
||||
getDescription: function () {
|
||||
return ' is defined';
|
||||
}
|
||||
},
|
||||
enumValueIs: {
|
||||
operation: function (input) {
|
||||
return input[0] === input[1];
|
||||
},
|
||||
text: 'is',
|
||||
appliesTo: ['enum'],
|
||||
inputCount: 1,
|
||||
getDescription: function (values) {
|
||||
return ' == ' + values[0];
|
||||
}
|
||||
},
|
||||
enumValueIsNot: {
|
||||
operation: function (input) {
|
||||
return input[0] !== input[1];
|
||||
},
|
||||
text: 'is not',
|
||||
appliesTo: ['enum'],
|
||||
inputCount: 1,
|
||||
getDescription: function (values) {
|
||||
return ' != ' + values[0];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -310,13 +334,16 @@ define([], function () {
|
||||
validator;
|
||||
|
||||
if (cache[object] && typeof cache[object][key] !== 'undefined') {
|
||||
telemetryValue = [cache[object][key]];
|
||||
let value = cache[object][key];
|
||||
telemetryValue = [isNaN(Number(value)) ? value : Number(value)];
|
||||
}
|
||||
|
||||
op = this.operations[operation] && this.operations[operation].operation;
|
||||
input = telemetryValue && telemetryValue.concat(values);
|
||||
validator = op && this.inputValidators[this.operations[operation].appliesTo[0]];
|
||||
|
||||
if (op && input && validator) {
|
||||
if (this.operations[operation].appliesTo.length === 2) {
|
||||
if (this.operations[operation].appliesTo.length > 1) {
|
||||
return (this.validateNumberInput(input) || this.validateStringInput(input)) && op(input);
|
||||
} else {
|
||||
return validator(input) && op(input);
|
||||
@@ -372,7 +399,7 @@ define([], function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true only of the given operation applies to a given type
|
||||
* Returns true only if the given operation applies to a given type
|
||||
* @param {string} key The key of the operation
|
||||
* @param {string} type The value type to query
|
||||
* @returns {boolean} True if the condition applies, false otherwise
|
||||
|
||||
@@ -130,7 +130,9 @@ define ([
|
||||
this.telemetryTypesById[objectId] = {};
|
||||
Object.values(this.telemetryMetadataById[objectId]).forEach(function (valueMetadata) {
|
||||
var type;
|
||||
if (valueMetadata.hints.hasOwnProperty('range')) {
|
||||
if (valueMetadata.enumerations !== undefined) {
|
||||
type = 'enum';
|
||||
} else if (valueMetadata.hints.hasOwnProperty('range')) {
|
||||
type = 'number';
|
||||
} else if (valueMetadata.hints.hasOwnProperty('domain')) {
|
||||
type = 'number';
|
||||
@@ -163,11 +165,18 @@ define ([
|
||||
* @param {datum} datum The new data from the telemetry source
|
||||
* @private
|
||||
*/
|
||||
ConditionManager.prototype.handleSubscriptionCallback = function (objId, datum) {
|
||||
this.subscriptionCache[objId] = datum;
|
||||
ConditionManager.prototype.handleSubscriptionCallback = function (objId, telemetryDatum) {
|
||||
this.subscriptionCache[objId] = this.createNormalizedDatum(objId, telemetryDatum);
|
||||
this.eventEmitter.emit('receiveTelemetry');
|
||||
};
|
||||
|
||||
ConditionManager.prototype.createNormalizedDatum = function (objId, telemetryDatum) {
|
||||
return Object.values(this.telemetryMetadataById[objId]).reduce((normalizedDatum, metadatum) => {
|
||||
normalizedDatum[metadatum.key] = telemetryDatum[metadatum.source];
|
||||
return normalizedDatum;
|
||||
}, {});
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for an add event in this Summary Widget's composition.
|
||||
* Sets up subscription handlers and parses its property types.
|
||||
@@ -236,6 +245,7 @@ define ([
|
||||
id.namespace === identifier.namespace;
|
||||
});
|
||||
delete this.compositionObjs[objectId];
|
||||
delete this.subscriptionCache[objectId];
|
||||
this.subscriptions[objectId](); //unsubscribe from telemetry source
|
||||
delete this.subscriptions[objectId];
|
||||
this.eventEmitter.emit('remove', identifier);
|
||||
|
||||
@@ -110,9 +110,11 @@ define([
|
||||
|
||||
type = self.manager.getTelemetryPropertyType(self.config.object, key);
|
||||
|
||||
self.operationKeys = operations.filter(function (operation) {
|
||||
return self.evaluator.operationAppliesTo(operation, type);
|
||||
});
|
||||
if (type !== undefined) {
|
||||
self.operationKeys = operations.filter(function (operation) {
|
||||
return self.evaluator.operationAppliesTo(operation, type);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
OperationSelect.prototype.destroy = function () {
|
||||
|
||||
@@ -38,7 +38,7 @@ define([
|
||||
return this.openmct.time.getAllTimeSystems().map(function (ts, i) {
|
||||
return {
|
||||
key: ts.key,
|
||||
name: 'UTC',
|
||||
name: ts.name,
|
||||
format: ts.timeFormat,
|
||||
hints: {
|
||||
domain: i
|
||||
@@ -64,7 +64,7 @@ define([
|
||||
// Generally safe assumption is that we have one domain per timeSystem.
|
||||
values: this.getDomains().concat([
|
||||
{
|
||||
name: 'state',
|
||||
name: 'State',
|
||||
key: 'state',
|
||||
source: 'ruleIndex',
|
||||
format: 'enum',
|
||||
|
||||
@@ -174,7 +174,7 @@ define([
|
||||
return typeof input[0] === 'undefined';
|
||||
},
|
||||
text: 'is undefined',
|
||||
appliesTo: ['string', 'number'],
|
||||
appliesTo: ['string', 'number', 'enum'],
|
||||
inputCount: 0,
|
||||
getDescription: function () {
|
||||
return ' is undefined';
|
||||
@@ -185,11 +185,33 @@ define([
|
||||
return typeof input[0] !== 'undefined';
|
||||
},
|
||||
text: 'is defined',
|
||||
appliesTo: ['string', 'number'],
|
||||
appliesTo: ['string', 'number', 'enum'],
|
||||
inputCount: 0,
|
||||
getDescription: function () {
|
||||
return ' is defined';
|
||||
}
|
||||
},
|
||||
enumValueIs: {
|
||||
operation: function (input) {
|
||||
return input[0] === input[1];
|
||||
},
|
||||
text: 'is',
|
||||
appliesTo: ['enum'],
|
||||
inputCount: 1,
|
||||
getDescription: function (values) {
|
||||
return ' == ' + values[0];
|
||||
}
|
||||
},
|
||||
enumValueIsNot: {
|
||||
operation: function (input) {
|
||||
return input[0] !== input[1];
|
||||
},
|
||||
text: 'is not',
|
||||
appliesTo: ['enum'],
|
||||
inputCount: 1,
|
||||
getDescription: function (values) {
|
||||
return ' != ' + values[0];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ define([
|
||||
key: 'table-configuration',
|
||||
name: 'Telemetry Table Configuration',
|
||||
canView: function (selection) {
|
||||
if (selection.length === 0 || selection[0].length === 0) {
|
||||
if (selection.length !== 1 || selection[0].length === 0) {
|
||||
return false;
|
||||
}
|
||||
let object = selection[0][0].context.item;
|
||||
|
||||
@@ -26,6 +26,7 @@ define([
|
||||
'./collections/BoundedTableRowCollection',
|
||||
'./collections/FilteredTableRowCollection',
|
||||
'./TelemetryTableRow',
|
||||
'./TelemetryTableColumn',
|
||||
'./TelemetryTableConfiguration'
|
||||
], function (
|
||||
EventEmitter,
|
||||
@@ -33,6 +34,7 @@ define([
|
||||
BoundedTableRowCollection,
|
||||
FilteredTableRowCollection,
|
||||
TelemetryTableRow,
|
||||
TelemetryTableColumn,
|
||||
TelemetryTableConfiguration
|
||||
) {
|
||||
class TelemetryTable extends EventEmitter {
|
||||
@@ -47,6 +49,8 @@ define([
|
||||
this.telemetryObjects = [];
|
||||
this.outstandingRequests = 0;
|
||||
this.configuration = new TelemetryTableConfiguration(domainObject, openmct);
|
||||
this.paused = false;
|
||||
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
|
||||
this.addTelemetryObject = this.addTelemetryObject.bind(this);
|
||||
this.removeTelemetryObject = this.removeTelemetryObject.bind(this);
|
||||
@@ -94,8 +98,6 @@ define([
|
||||
this.tableComposition.load().then((composition) => {
|
||||
|
||||
composition = composition.filter(this.isTelemetryObject);
|
||||
|
||||
this.configuration.addColumnsForAllObjects(composition);
|
||||
composition.forEach(this.addTelemetryObject);
|
||||
|
||||
this.tableComposition.on('add', this.addTelemetryObject);
|
||||
@@ -105,7 +107,7 @@ define([
|
||||
}
|
||||
|
||||
addTelemetryObject(telemetryObject) {
|
||||
this.configuration.addColumnsForObject(telemetryObject, true);
|
||||
this.addColumnsForObject(telemetryObject, true);
|
||||
this.requestDataFor(telemetryObject);
|
||||
this.subscribeTo(telemetryObject);
|
||||
this.telemetryObjects.push(telemetryObject);
|
||||
@@ -144,14 +146,17 @@ define([
|
||||
let keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
let columnMap = this.getColumnMapForObject(keyString);
|
||||
let limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject);
|
||||
|
||||
let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
|
||||
this.boundedRows.add(telemetryRows);
|
||||
this.processHistoricalData(telemetryData, columnMap, keyString, limitEvaluator);
|
||||
}).finally(() => {
|
||||
this.decrementOutstandingRequests();
|
||||
});
|
||||
}
|
||||
|
||||
processHistoricalData(telemetryData, columnMap, keyString, limitEvaluator) {
|
||||
let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
|
||||
this.boundedRows.add(telemetryRows);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -191,6 +196,19 @@ define([
|
||||
}, {});
|
||||
}
|
||||
|
||||
addColumnsForObject(telemetryObject) {
|
||||
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
|
||||
|
||||
metadataValues.forEach(metadatum => {
|
||||
let column = this.createColumn(metadatum);
|
||||
this.configuration.addSingleColumnForObject(telemetryObject, column);
|
||||
});
|
||||
}
|
||||
|
||||
createColumn(metadatum) {
|
||||
return new TelemetryTableColumn(this.openmct, metadatum);
|
||||
}
|
||||
|
||||
subscribeTo(telemetryObject) {
|
||||
let subscribeOptions = this.buildOptionsFromConfiguration(telemetryObject);
|
||||
let keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
@@ -202,10 +220,17 @@ define([
|
||||
if (!this.telemetryObjects.includes(telemetryObject)) {
|
||||
return;
|
||||
}
|
||||
this.boundedRows.add(new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
|
||||
|
||||
if (!this.paused) {
|
||||
this.processRealtimeDatum(datum, columnMap, keyString, limitEvaluator);
|
||||
}
|
||||
}, subscribeOptions);
|
||||
}
|
||||
|
||||
processRealtimeDatum(datum, columnMap, keyString, limitEvaluator) {
|
||||
this.boundedRows.add(new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
|
||||
}
|
||||
|
||||
isTelemetryObject(domainObject) {
|
||||
return domainObject.hasOwnProperty('telemetry');
|
||||
}
|
||||
@@ -234,12 +259,24 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
pause() {
|
||||
this.paused = true;
|
||||
this.boundedRows.unsubscribeFromBounds();
|
||||
}
|
||||
|
||||
unpause() {
|
||||
this.paused = false;
|
||||
this.boundedRows.subscribeToBounds();
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.boundedRows.destroy();
|
||||
this.filteredRows.destroy();
|
||||
Object.keys(this.subscriptions).forEach(this.unsubscribe, this);
|
||||
this.openmct.time.off('bounds', this.refreshData);
|
||||
this.openmct.time.on('timeSystem', this.refreshData);
|
||||
this.openmct.time.off('timeSystem', this.refreshData);
|
||||
|
||||
if (this.filterObserver) {
|
||||
this.filterObserver();
|
||||
}
|
||||
|
||||
@@ -21,10 +21,11 @@
|
||||
*****************************************************************************/
|
||||
define(function () {
|
||||
class TelemetryTableColumn {
|
||||
constructor (openmct, metadatum) {
|
||||
constructor (openmct, metadatum, options = {selectable: false}) {
|
||||
this.metadatum = metadatum;
|
||||
this.formatter = openmct.telemetry.getValueFormatter(metadatum);
|
||||
this.titleValue = this.metadatum.name;
|
||||
this.selectable = options.selectable;
|
||||
}
|
||||
|
||||
getKey() {
|
||||
@@ -55,8 +56,7 @@ define(function () {
|
||||
return formattedValue;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
return TelemetryTableColumn;
|
||||
});
|
||||
|
||||
@@ -22,9 +22,8 @@
|
||||
|
||||
define([
|
||||
'lodash',
|
||||
'EventEmitter',
|
||||
'./TelemetryTableColumn'
|
||||
], function (_, EventEmitter, TelemetryTableColumn) {
|
||||
'EventEmitter'
|
||||
], function (_, EventEmitter) {
|
||||
|
||||
class TelemetryTableConfiguration extends EventEmitter {
|
||||
constructor(domainObject, openmct) {
|
||||
@@ -34,7 +33,6 @@ define([
|
||||
this.openmct = openmct;
|
||||
this.columns = {};
|
||||
|
||||
this.addColumnsForObject = this.addColumnsForObject.bind(this);
|
||||
this.removeColumnsForObject = this.removeColumnsForObject.bind(this);
|
||||
this.objectMutated = this.objectMutated.bind(this);
|
||||
//Make copy of configuration, otherwise change detection is impossible if shared instance is being modified.
|
||||
@@ -48,6 +46,7 @@ define([
|
||||
configuration.hiddenColumns = configuration.hiddenColumns || {};
|
||||
configuration.columnWidths = configuration.columnWidths || {};
|
||||
configuration.columnOrder = configuration.columnOrder || [];
|
||||
configuration.cellFormat = configuration.cellFormat || {};
|
||||
configuration.autosize = configuration.autosize === undefined ? true : configuration.autosize;
|
||||
|
||||
return configuration;
|
||||
@@ -65,26 +64,18 @@ define([
|
||||
//Synchronize domain object reference. Duplicate object otherwise change detection becomes impossible.
|
||||
this.domainObject = object;
|
||||
//Was it the configuration that changed?
|
||||
if (!_.eq(object.configuration, this.oldConfiguration)) {
|
||||
if (object.configuration !== undefined && !_.eq(object.configuration, this.oldConfiguration)) {
|
||||
//Make copy of configuration, otherwise change detection is impossible if shared instance is being modified.
|
||||
this.oldConfiguration = JSON.parse(JSON.stringify(this.getConfiguration()));
|
||||
this.emit('change', object.configuration);
|
||||
}
|
||||
}
|
||||
|
||||
addColumnsForAllObjects(objects) {
|
||||
objects.forEach(object => this.addColumnsForObject(object, false));
|
||||
}
|
||||
|
||||
addColumnsForObject(telemetryObject) {
|
||||
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
|
||||
addSingleColumnForObject(telemetryObject, column, position) {
|
||||
let objectKeyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
this.columns[objectKeyString] = [];
|
||||
|
||||
metadataValues.forEach(metadatum => {
|
||||
let column = new TelemetryTableColumn(this.openmct, metadatum);
|
||||
this.columns[objectKeyString].push(column);
|
||||
});
|
||||
this.columns[objectKeyString] = this.columns[objectKeyString] || [];
|
||||
position = position || this.columns[objectKeyString].length;
|
||||
this.columns[objectKeyString].splice(position, 0, column);
|
||||
}
|
||||
|
||||
removeColumnsForObject(objectIdentifier) {
|
||||
|
||||
@@ -42,12 +42,19 @@ define([], function () {
|
||||
return column && column.getFormattedValue(this.datum[key]);
|
||||
}
|
||||
|
||||
getRowLimitClass() {
|
||||
if (!this.rowLimitClass) {
|
||||
getCellComponentName(key) {
|
||||
let column = this.columns[key];
|
||||
return column &&
|
||||
column.getCellComponentName &&
|
||||
column.getCellComponentName();
|
||||
}
|
||||
|
||||
getRowClass() {
|
||||
if (!this.rowClass) {
|
||||
let limitEvaluation = this.limitEvaluator.evaluate(this.datum);
|
||||
this.rowLimitClass = limitEvaluation && limitEvaluation.cssClass;
|
||||
this.rowClass = limitEvaluation && limitEvaluation.cssClass;
|
||||
}
|
||||
return this.rowLimitClass;
|
||||
return this.rowClass;
|
||||
}
|
||||
|
||||
getCellLimitClasses() {
|
||||
|
||||
@@ -22,12 +22,10 @@
|
||||
|
||||
define([
|
||||
'./components/table.vue',
|
||||
'../../exporters/CSVExporter',
|
||||
'./TelemetryTable',
|
||||
'vue'
|
||||
], function (
|
||||
TableComponent,
|
||||
CSVExporter,
|
||||
TelemetryTable,
|
||||
Vue
|
||||
) {
|
||||
@@ -51,7 +49,6 @@ define([
|
||||
return domainObject.type === 'table';
|
||||
},
|
||||
view(domainObject) {
|
||||
let csvExporter = new CSVExporter.default();
|
||||
let table = new TelemetryTable(domainObject, openmct);
|
||||
let component;
|
||||
return {
|
||||
@@ -67,16 +64,18 @@ define([
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
csvExporter,
|
||||
table
|
||||
},
|
||||
el: element,
|
||||
template: '<table-component :isEditing="isEditing"></table-component>'
|
||||
template: '<table-component :isEditing="isEditing" :enableMarking="true"></table-component>'
|
||||
});
|
||||
},
|
||||
onEditModeChange(isEditing) {
|
||||
component.isEditing = isEditing;
|
||||
},
|
||||
onClearData() {
|
||||
table.refreshData();
|
||||
},
|
||||
destroy: function (element) {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
|
||||
@@ -31,9 +31,9 @@ define(
|
||||
) {
|
||||
|
||||
class BoundedTableRowCollection extends SortedTableRowCollection {
|
||||
constructor (openmct) {
|
||||
constructor(openmct) {
|
||||
super();
|
||||
|
||||
|
||||
this.futureBuffer = new SortedTableRowCollection();
|
||||
this.openmct = openmct;
|
||||
|
||||
@@ -43,15 +43,17 @@ define(
|
||||
this.sortByTimeSystem(openmct.time.timeSystem());
|
||||
|
||||
this.lastBounds = openmct.time.bounds();
|
||||
openmct.time.on('bounds', this.bounds);
|
||||
|
||||
this.subscribeToBounds();
|
||||
}
|
||||
|
||||
addOne (item) {
|
||||
addOne(item) {
|
||||
let parsedValue = this.getValueForSortColumn(item);
|
||||
// Insert into either in-bounds array, or the future buffer.
|
||||
// Data in the future buffer will be re-evaluated for possible
|
||||
// Data in the future buffer will be re-evaluated for possible
|
||||
// insertion on next bounds change
|
||||
let beforeStartOfBounds = this.parseTime(item.datum[this.sortOptions.key]) < this.lastBounds.start;
|
||||
let afterEndOfBounds = this.parseTime(item.datum[this.sortOptions.key]) > this.lastBounds.end;
|
||||
let beforeStartOfBounds = parsedValue < this.lastBounds.start;
|
||||
let afterEndOfBounds = parsedValue > this.lastBounds.end;
|
||||
|
||||
if (!afterEndOfBounds && !beforeStartOfBounds) {
|
||||
return super.addOne(item);
|
||||
@@ -86,13 +88,13 @@ define(
|
||||
* @fires TelemetryCollection#discarded
|
||||
* @param bounds
|
||||
*/
|
||||
bounds (bounds) {
|
||||
bounds(bounds) {
|
||||
let startChanged = this.lastBounds.start !== bounds.start;
|
||||
let endChanged = this.lastBounds.end !== bounds.end;
|
||||
|
||||
|
||||
let startIndex = 0;
|
||||
let endIndex = 0;
|
||||
|
||||
|
||||
let discarded = [];
|
||||
let added = [];
|
||||
let testValue = {
|
||||
@@ -135,9 +137,21 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
getValueForSortColumn(row) {
|
||||
return this.parseTime(row.datum[this.sortOptions.key]);
|
||||
}
|
||||
|
||||
unsubscribeFromBounds() {
|
||||
this.openmct.time.off('bounds', this.bounds);
|
||||
}
|
||||
|
||||
subscribeToBounds() {
|
||||
this.openmct.time.on('bounds', this.bounds);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.unsubscribeFromBounds();
|
||||
}
|
||||
}
|
||||
return BoundedTableRowCollection;
|
||||
});
|
||||
return BoundedTableRowCollection;
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ define(
|
||||
if (rowsAdded.length > 0) {
|
||||
this.emit('add', rowsAdded);
|
||||
}
|
||||
this.dupeCheck = true;
|
||||
this.dupeCheck = true;
|
||||
} else {
|
||||
let wasAdded = this.addOne(rows);
|
||||
if (wasAdded) {
|
||||
@@ -115,11 +115,10 @@ define(
|
||||
if (this.rows.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const sortOptionsKey = this.sortOptions.key;
|
||||
const testRowValue = testRow.datum[sortOptionsKey];
|
||||
const firstValue = this.rows[0].datum[sortOptionsKey];
|
||||
const lastValue = this.rows[this.rows.length - 1].datum[sortOptionsKey];
|
||||
|
||||
const testRowValue = this.getValueForSortColumn(testRow);
|
||||
const firstValue = this.getValueForSortColumn(this.rows[0]);
|
||||
const lastValue = this.getValueForSortColumn(this.rows[this.rows.length - 1]);
|
||||
|
||||
lodashFunction = lodashFunction || _.sortedIndex;
|
||||
|
||||
@@ -133,7 +132,7 @@ define(
|
||||
return 0;
|
||||
} else {
|
||||
return lodashFunction(rows, testRow, (thisRow) => {
|
||||
return thisRow.datum[sortOptionsKey];
|
||||
return this.getValueForSortColumn(thisRow);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -147,7 +146,7 @@ define(
|
||||
} else {
|
||||
// Use a custom comparison function to support descending sort.
|
||||
return lodashFunction(rows, testRow, (thisRow) => {
|
||||
const thisRowValue = thisRow.datum[sortOptionsKey];
|
||||
const thisRowValue = this.getValueForSortColumn(thisRow);
|
||||
if (testRowValue === thisRowValue) {
|
||||
return EQUAL;
|
||||
} else if (testRowValue < thisRowValue) {
|
||||
@@ -206,7 +205,7 @@ define(
|
||||
this.emit('sort');
|
||||
}
|
||||
// Return duplicate to avoid direct modification of underlying object
|
||||
return Object.assign({}, this.sortOptions);
|
||||
return Object.assign({}, this.sortOptions);
|
||||
}
|
||||
|
||||
removeAllRowsForObject(objectKeyString) {
|
||||
@@ -218,25 +217,32 @@ define(
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
this.emit('remove', removed);
|
||||
}
|
||||
|
||||
getValueForSortColumn(row) {
|
||||
return row.datum[this.sortOptions.key];
|
||||
}
|
||||
|
||||
remove(removedRows) {
|
||||
this.rows = this.rows.filter(row => {
|
||||
return removedRows.indexOf(row) === -1;
|
||||
});
|
||||
|
||||
this.emit('remove', removedRows);
|
||||
}
|
||||
|
||||
getRows () {
|
||||
getRows() {
|
||||
return this.rows;
|
||||
}
|
||||
|
||||
clear() {
|
||||
let removedRows = this.rows;
|
||||
this.rows = [];
|
||||
|
||||
this.emit('remove', removedRows);
|
||||
}
|
||||
}
|
||||
return SortedTableRowCollection;
|
||||
});
|
||||
return SortedTableRowCollection;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<div v-if="filterNames.length > 0"
|
||||
:title=title
|
||||
class="c-filter-indication"
|
||||
:class="{ 'c-filter-indication--mixed': mixed }">
|
||||
<span class="c-filter-indication__mixed">{{ label }}</span>
|
||||
<span v-for="(name, index) in filterNames"
|
||||
class="c-filter-indication__label">
|
||||
{{ name }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
.c-filter-indication {
|
||||
@include userSelectNone();
|
||||
background: $colorFilterBg;
|
||||
color: $colorFilterFg;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 0.9em;
|
||||
margin-top: $interiorMarginSm;
|
||||
padding: 2px;
|
||||
text-transform: uppercase;
|
||||
|
||||
&:before {
|
||||
font-family: symbolsfont-12px;
|
||||
content: $glyph-icon-filter;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
&__mixed {
|
||||
font-weight: bold;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
&--mixed {
|
||||
.c-filter-indication__mixed {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
+ .c-filter-indication__label {
|
||||
&:before {
|
||||
content: ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const FILTER_INDICATOR_LABEL = 'Filters:';
|
||||
const FILTER_INDICATOR_LABEL_MIXED = 'Mixed Filters:';
|
||||
const FILTER_INDICATOR_TITLE = 'Data filters are being applied to this view.';
|
||||
const FILTER_INDICATOR_TITLE_MIXED = 'A mix of data filter values are being applied to this view.';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'table'],
|
||||
data() {
|
||||
return {
|
||||
filterNames: [],
|
||||
filteredTelemetry: {},
|
||||
mixed: false,
|
||||
label: '',
|
||||
title: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isTelemetryObject(domainObject) {
|
||||
return domainObject.hasOwnProperty('telemetry');
|
||||
},
|
||||
setFilterNames() {
|
||||
let names = [];
|
||||
|
||||
this.composition && this.composition.load().then((domainObjects) => {
|
||||
domainObjects.forEach(telemetryObject => {
|
||||
let keyString= this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
let filters = this.filteredTelemetry[keyString];
|
||||
this.telemetryKeyStrings.add(keyString);
|
||||
|
||||
if (filters !== undefined) {
|
||||
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
|
||||
Object.keys(filters).forEach(key => {
|
||||
metadataValues.forEach(metadaum => {
|
||||
|
||||
if (key === metadaum.key) {
|
||||
names.push(metadaum.name);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
this.filterNames = Array.from(new Set(names));
|
||||
});
|
||||
},
|
||||
handleConfigurationChanges(configuration) {
|
||||
if (!_.eq(this.filteredTelemetry, configuration.filters)) {
|
||||
this.updateFilters(configuration.filters || {});
|
||||
}
|
||||
},
|
||||
checkFiltersForMixedValues() {
|
||||
let valueToCompare = this.filteredTelemetry[Object.keys(this.filteredTelemetry)[0]];
|
||||
let mixed = false;
|
||||
|
||||
Object.values(this.filteredTelemetry).forEach(value => {
|
||||
if (!_.isEqual(valueToCompare, value)) {
|
||||
mixed = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// If the filtered telemetry is not mixed at this point, check the number of available objects
|
||||
// with the number of filtered telemetry. If they are not equal, the filters must be mixed.
|
||||
if (mixed === false && _.size(this.filteredTelemetry) !== this.telemetryKeyStrings.size) {
|
||||
mixed = true;
|
||||
}
|
||||
|
||||
this.mixed = mixed;
|
||||
},
|
||||
setLabels() {
|
||||
if (this.mixed) {
|
||||
this.label = FILTER_INDICATOR_LABEL_MIXED;
|
||||
this.title = FILTER_INDICATOR_TITLE_MIXED;
|
||||
} else {
|
||||
this.label = FILTER_INDICATOR_LABEL;
|
||||
this.title = FILTER_INDICATOR_TITLE;
|
||||
}
|
||||
},
|
||||
updateFilters(filters) {
|
||||
this.filteredTelemetry = JSON.parse(JSON.stringify(filters));
|
||||
this.setFilterNames();
|
||||
this.updateIndicatorLabel();
|
||||
},
|
||||
addChildren(child) {
|
||||
let keyString = this.openmct.objects.makeKeyString(child.identifier);
|
||||
this.telemetryKeyStrings.add(keyString);
|
||||
this.updateIndicatorLabel();
|
||||
},
|
||||
removeChildren(identifier) {
|
||||
let keyString = this.openmct.objects.makeKeyString(identifier);
|
||||
this.telemetryKeyStrings.delete(keyString);
|
||||
this.updateIndicatorLabel();
|
||||
},
|
||||
updateIndicatorLabel() {
|
||||
this.checkFiltersForMixedValues();
|
||||
this.setLabels();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let filters = this.table.configuration.getConfiguration().filters || {};
|
||||
this.telemetryKeyStrings = new Set();
|
||||
this.composition = this.openmct.composition.get(this.table.configuration.domainObject);
|
||||
|
||||
if (this.composition) {
|
||||
this.composition.on('add', this.addChildren);
|
||||
this.composition.on('remove', this.removeChildren);
|
||||
}
|
||||
|
||||
this.table.configuration.on('change', this.handleConfigurationChanges);
|
||||
this.updateFilters(filters);
|
||||
},
|
||||
destroyed() {
|
||||
this.table.configuration.off('change', this.handleConfigurationChanges);
|
||||
|
||||
if (this.composition) {
|
||||
this.composition.off('add', this.addChildren);
|
||||
this.composition.off('remove', this.removeChildren);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
44
src/plugins/telemetryTable/components/table-cell.vue
Normal file
44
src/plugins/telemetryTable/components/table-cell.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||
*****************************************************************************/
|
||||
<template>
|
||||
<td>{{formattedValue}}</td>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
row: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
columnKey: {
|
||||
type: String,
|
||||
require: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
formattedValue() {
|
||||
return this.row.getFormattedValue(this.columnKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -23,6 +23,8 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import TelemetryTableColumn from '../TelemetryTableColumn';
|
||||
|
||||
export default {
|
||||
inject: ['tableConfiguration', 'openmct'],
|
||||
data() {
|
||||
@@ -43,7 +45,7 @@ export default {
|
||||
this.tableConfiguration.updateConfiguration(this.configuration);
|
||||
},
|
||||
addObject(domainObject) {
|
||||
this.tableConfiguration.addColumnsForObject(domainObject, true);
|
||||
this.addColumnsForObject(domainObject, true);
|
||||
this.updateHeaders(this.tableConfiguration.getAllHeaders());
|
||||
},
|
||||
removeObject(objectIdentifier) {
|
||||
@@ -56,6 +58,17 @@ export default {
|
||||
toggleAutosize() {
|
||||
this.configuration.autosize = !this.configuration.autosize;
|
||||
this.tableConfiguration.updateConfiguration(this.configuration);
|
||||
},
|
||||
addColumnsForAllObjects(objects) {
|
||||
objects.forEach(object => this.addColumnsForObject(object, false));
|
||||
},
|
||||
addColumnsForObject(telemetryObject) {
|
||||
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
|
||||
|
||||
metadataValues.forEach(metadatum => {
|
||||
let column = new TelemetryTableColumn(this.openmct, metadatum);
|
||||
this.tableConfiguration.addSingleColumnForObject(telemetryObject, column);
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -65,7 +78,7 @@ export default {
|
||||
|
||||
compositionCollection.load()
|
||||
.then((composition) => {
|
||||
this.tableConfiguration.addColumnsForAllObjects(composition);
|
||||
this.addColumnsForAllObjects(composition);
|
||||
this.updateHeaders(this.tableConfiguration.getAllHeaders());
|
||||
|
||||
compositionCollection.on('add', this.addObject);
|
||||
|
||||
@@ -20,26 +20,56 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
<template>
|
||||
<tr :style="{ top: rowTop }" :class="rowLimitClass">
|
||||
<td v-for="(title, key) in headers"
|
||||
<tr :style="{ top: rowTop }"
|
||||
class="noselect"
|
||||
:class="[
|
||||
rowClass,
|
||||
{'is-selected': marked}
|
||||
]"
|
||||
@click="markRow">
|
||||
<component v-for="(title, key) in headers"
|
||||
:key="key"
|
||||
:is="componentList[key]"
|
||||
:columnKey="key"
|
||||
:style="columnWidths[key] === undefined ? {} : { width: columnWidths[key] + 'px', 'max-width': columnWidths[key] + 'px'}"
|
||||
:title="formattedRow[key]"
|
||||
:class="cellLimitClasses[key]">{{formattedRow[key]}}</td>
|
||||
:class="[cellLimitClasses[key], selectableColumns[key] ? 'is-selectable' : '']"
|
||||
@click="selectCell($event.currentTarget, key)"
|
||||
:row="row">
|
||||
</component>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.noselect {
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-khtml-user-select: none; /* Konqueror HTML */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||
user-select: none; /* Non-prefixed version, currently
|
||||
supported by Chrome and Opera */
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import TableCell from './table-cell.vue';
|
||||
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
rowTop: (this.rowOffset + this.rowIndex) * this.rowHeight + 'px',
|
||||
formattedRow: this.row.getFormattedDatum(this.headers),
|
||||
rowLimitClass: this.row.getRowLimitClass(),
|
||||
cellLimitClasses: this.row.getCellLimitClasses()
|
||||
rowClass: this.row.getRowClass(),
|
||||
cellLimitClasses: this.row.getCellLimitClasses(),
|
||||
componentList: Object.keys(this.headers).reduce((components, header) => {
|
||||
components[header] = this.row.getCellComponentName(header) || 'table-cell';
|
||||
return components
|
||||
}, {}),
|
||||
selectableColumns : Object.keys(this.row.columns).reduce((selectable, columnKeys) => {
|
||||
selectable[columnKeys] = this.row.columns[columnKeys].selectable;
|
||||
return selectable;
|
||||
}, {})
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@@ -69,6 +99,11 @@ export default {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
marked: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -77,8 +112,44 @@ export default {
|
||||
},
|
||||
formatRow: function (row) {
|
||||
this.formattedRow = row.getFormattedDatum(this.headers);
|
||||
this.rowLimitClass = row.getRowLimitClass();
|
||||
this.rowClass = row.getRowClass();
|
||||
this.cellLimitClasses = row.getCellLimitClasses();
|
||||
},
|
||||
markRow: function (event) {
|
||||
let keyCtrlModifier = false;
|
||||
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
keyCtrlModifier = true;
|
||||
}
|
||||
|
||||
if (event.shiftKey) {
|
||||
this.$emit('markMultipleConcurrent', this.rowIndex);
|
||||
} else {
|
||||
if (this.marked) {
|
||||
this.$emit('unmark', this.rowIndex, keyCtrlModifier);
|
||||
} else {
|
||||
this.$emit('mark', this.rowIndex, keyCtrlModifier);
|
||||
}
|
||||
}
|
||||
},
|
||||
selectCell(element, columnKey) {
|
||||
if (this.selectableColumns[columnKey]) {
|
||||
//TODO: This is a hack. Cannot get parent this way.
|
||||
this.openmct.selection.select([{
|
||||
element: element,
|
||||
context: {
|
||||
type: 'table-cell',
|
||||
row: this.row.objectKeyString,
|
||||
column: columnKey
|
||||
}
|
||||
},{
|
||||
element: this.openmct.layout.$refs.browseObject.$el,
|
||||
context: {
|
||||
item: this.openmct.router.path[0]
|
||||
}
|
||||
}], false);
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
},
|
||||
// TODO: use computed properties
|
||||
@@ -88,6 +159,9 @@ export default {
|
||||
handler: 'formatRow',
|
||||
deep: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
TableCell
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -20,92 +20,134 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
<template>
|
||||
<div class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar"
|
||||
:class="{'loading': loading}">
|
||||
<div class="c-table__control-bar c-control-bar">
|
||||
<div class="c-table-wrapper">
|
||||
<div class="c-table-control-bar c-control-bar">
|
||||
<button class="c-button icon-download labeled"
|
||||
v-on:click="exportAsCSV()"
|
||||
title="Export This View's Data">
|
||||
<span class="c-button__label">Export As CSV</span>
|
||||
v-if="allowExport"
|
||||
v-on:click="exportAllDataAsCSV()"
|
||||
title="Export This View's Data">
|
||||
<span class="c-button__label">Export Table Data</span>
|
||||
</button>
|
||||
<button class="c-button icon-download labeled"
|
||||
v-if="allowExport"
|
||||
v-show="markedRows.length"
|
||||
v-on:click="exportMarkedDataAsCSV()"
|
||||
title="Export Marked Rows As CSV">
|
||||
<span class="c-button__label">Export Marked Rows</span>
|
||||
</button>
|
||||
<button class="c-button icon-x labeled"
|
||||
v-show="markedRows.length"
|
||||
v-on:click="unmarkAllRows()"
|
||||
title="Unmark All Rows">
|
||||
<span class="c-button__label">Unmark All Rows</span>
|
||||
</button>
|
||||
<div v-if="enableMarking"
|
||||
class="c-separator">
|
||||
</div>
|
||||
<button v-if="enableMarking"
|
||||
class="c-button icon-pause pause-play labeled"
|
||||
:class=" paused ? 'icon-play is-paused' : 'icon-pause'"
|
||||
v-on:click="togglePauseByButton()"
|
||||
:title="paused ? 'Continue Data Flow' : 'Pause Data Flow'">
|
||||
<span class="c-button__label">
|
||||
{{paused ? 'Play' : 'Pause'}}
|
||||
</span>
|
||||
</button>
|
||||
<slot name="buttons"></slot>
|
||||
</div>
|
||||
<div v-if="isDropTargetActive" class="c-telemetry-table__drop-target" :style="dropTargetStyle"></div>
|
||||
<!-- Headers table -->
|
||||
<div class="c-telemetry-table__headers-w js-table__headers-w" ref="headersTable" :style="{ 'max-width': widthWithScroll}">
|
||||
<table class="c-table__headers c-telemetry-table__headers">
|
||||
<thead>
|
||||
<tr class="c-telemetry-table__headers__labels">
|
||||
<table-column-header
|
||||
v-for="(title, key, headerIndex) in headers"
|
||||
:key="key"
|
||||
:headerKey="key"
|
||||
:headerIndex="headerIndex"
|
||||
@sort="sortBy(key)"
|
||||
@resizeColumn="resizeColumn"
|
||||
@dropTargetOffsetChanged="setDropTargetOffset"
|
||||
@dropTargetActive="dropTargetActive"
|
||||
@reorderColumn="reorderColumn"
|
||||
@resizeColumnEnd="updateConfiguredColumnWidths"
|
||||
:columnWidth="columnWidths[key]"
|
||||
:sortOptions="sortOptions"
|
||||
:isEditing="isEditing"
|
||||
><span class="c-telemetry-table__headers__label">{{title}}</span>
|
||||
</table-column-header>
|
||||
</tr>
|
||||
<tr class="c-telemetry-table__headers__filter">
|
||||
<table-column-header
|
||||
v-for="(title, key, headerIndex) in headers"
|
||||
:key="key"
|
||||
:headerKey="key"
|
||||
:headerIndex="headerIndex"
|
||||
@resizeColumn="resizeColumn"
|
||||
@dropTargetOffsetChanged="setDropTargetOffset"
|
||||
@dropTargetActive="dropTargetActive"
|
||||
@reorderColumn="reorderColumn"
|
||||
@resizeColumnEnd="updateConfiguredColumnWidths"
|
||||
:columnWidth="columnWidths[key]"
|
||||
:isEditing="isEditing"
|
||||
>
|
||||
<search class="c-table__search"
|
||||
v-model="filters[key]"
|
||||
v-on:input="filterChanged(key)"
|
||||
v-on:clear="clearFilter(key)" />
|
||||
</table-column-header>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<div class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar"
|
||||
:class="{
|
||||
'loading': loading,
|
||||
'paused' : paused
|
||||
}">
|
||||
|
||||
<div :style="{ 'max-width': widthWithScroll, 'min-width': '150px'}"><slot></slot></div>
|
||||
|
||||
<div v-if="isDropTargetActive" class="c-telemetry-table__drop-target" :style="dropTargetStyle"></div>
|
||||
<!-- Headers table -->
|
||||
<div class="c-telemetry-table__headers-w js-table__headers-w" ref="headersTable" :style="{ 'max-width': widthWithScroll}">
|
||||
<table class="c-table__headers c-telemetry-table__headers">
|
||||
<thead>
|
||||
<tr class="c-telemetry-table__headers__labels">
|
||||
<table-column-header
|
||||
v-for="(title, key, headerIndex) in headers"
|
||||
:key="key"
|
||||
:headerKey="key"
|
||||
:headerIndex="headerIndex"
|
||||
@sort="allowSorting && sortBy(key)"
|
||||
@resizeColumn="resizeColumn"
|
||||
@dropTargetOffsetChanged="setDropTargetOffset"
|
||||
@dropTargetActive="dropTargetActive"
|
||||
@reorderColumn="reorderColumn"
|
||||
@resizeColumnEnd="updateConfiguredColumnWidths"
|
||||
:columnWidth="columnWidths[key]"
|
||||
:sortOptions="sortOptions"
|
||||
:isEditing="isEditing"
|
||||
><span class="c-telemetry-table__headers__label">{{title}}</span>
|
||||
</table-column-header>
|
||||
</tr>
|
||||
<tr class="c-telemetry-table__headers__filter">
|
||||
<table-column-header
|
||||
v-for="(title, key, headerIndex) in headers"
|
||||
:key="key"
|
||||
:headerKey="key"
|
||||
:headerIndex="headerIndex"
|
||||
@resizeColumn="resizeColumn"
|
||||
@dropTargetOffsetChanged="setDropTargetOffset"
|
||||
@dropTargetActive="dropTargetActive"
|
||||
@reorderColumn="reorderColumn"
|
||||
@resizeColumnEnd="updateConfiguredColumnWidths"
|
||||
:columnWidth="columnWidths[key]"
|
||||
:isEditing="isEditing"
|
||||
>
|
||||
<search class="c-table__search"
|
||||
v-model="filters[key]"
|
||||
v-on:input="filterChanged(key)"
|
||||
v-on:clear="clearFilter(key)" />
|
||||
</table-column-header>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Content table -->
|
||||
<div class="c-table__body-w c-telemetry-table__body-w js-telemetry-table__body-w" @scroll="scroll" :style="{ 'max-width': widthWithScroll}">
|
||||
<div class="c-telemetry-table__scroll-forcer" :style="{ width: totalWidth + 'px' }"></div>
|
||||
<table class="c-table__body c-telemetry-table__body js-telemetry-table__content"
|
||||
:style="{ height: totalHeight + 'px'}">
|
||||
<tbody>
|
||||
<telemetry-table-row v-for="(row, rowIndex) in visibleRows"
|
||||
:headers="headers"
|
||||
:columnWidths="columnWidths"
|
||||
:rowIndex="rowIndex"
|
||||
:rowOffset="rowOffset"
|
||||
:rowHeight="rowHeight"
|
||||
:row="row"
|
||||
:marked="row.marked"
|
||||
@mark="markRow"
|
||||
@unmark="unmarkRow"
|
||||
@markMultipleConcurrent="markMultipleConcurrentRows">
|
||||
</telemetry-table-row>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Sizing table -->
|
||||
<table class="c-telemetry-table__sizing js-telemetry-table__sizing" :style="sizingTableWidth">
|
||||
<tr>
|
||||
<template v-for="(title, key) in headers">
|
||||
<th :key="key" :style="{ width: configuredColumnWidths[key] + 'px', 'max-width': configuredColumnWidths[key] + 'px'}">{{title}}</th>
|
||||
</template>
|
||||
</tr>
|
||||
<telemetry-table-row v-for="(sizingRowData, objectKeyString) in sizingRows"
|
||||
:key="objectKeyString"
|
||||
:headers="headers"
|
||||
:columnWidths="configuredColumnWidths"
|
||||
:row="sizingRowData">
|
||||
</telemetry-table-row>
|
||||
</table>
|
||||
<telemetry-filter-indicator></telemetry-filter-indicator>
|
||||
</div>
|
||||
<!-- Content table -->
|
||||
<div class="c-table__body-w c-telemetry-table__body-w js-telemetry-table__body-w" @scroll="scroll" :style="{ 'max-width': widthWithScroll}">
|
||||
<div class="c-telemetry-table__scroll-forcer" :style="{ width: totalWidth + 'px' }"></div>
|
||||
<table class="c-table__body c-telemetry-table__body"
|
||||
:style="{ height: totalHeight + 'px'}">
|
||||
<tbody>
|
||||
<telemetry-table-row v-for="(row, rowIndex) in visibleRows"
|
||||
:headers="headers"
|
||||
:columnWidths="columnWidths"
|
||||
:rowIndex="rowIndex"
|
||||
:rowOffset="rowOffset"
|
||||
:rowHeight="rowHeight"
|
||||
:row="row">
|
||||
</telemetry-table-row>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Sizing table -->
|
||||
<table class="c-telemetry-table__sizing js-telemetry-table__sizing" :style="sizingTableWidth">
|
||||
<tr>
|
||||
<template v-for="(title, key) in headers">
|
||||
<th :key="key" :style="{ width: configuredColumnWidths[key] + 'px', 'max-width': configuredColumnWidths[key] + 'px'}">{{title}}</th>
|
||||
</template>
|
||||
</tr>
|
||||
<telemetry-table-row v-for="(sizingRowData, objectKeyString) in sizingRows"
|
||||
:headers="headers"
|
||||
:columnWidths="configuredColumnWidths"
|
||||
:row="sizingRowData">
|
||||
</telemetry-table-row>
|
||||
</table>
|
||||
</div>
|
||||
</div><!-- closes c-table-wrapper -->
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -131,7 +173,7 @@
|
||||
display: block;
|
||||
flex: 1 0 auto;
|
||||
width: 100px;
|
||||
vertical-align: middle; // This is crucial to hiding f**king 4px height injected by browser by default
|
||||
vertical-align: middle; // This is crucial to hiding 4px height injected by browser by default
|
||||
}
|
||||
|
||||
td {
|
||||
@@ -216,6 +258,10 @@
|
||||
align-items: stretch;
|
||||
position: absolute;
|
||||
height: 18px; // Needed when a row has empty values in its cells
|
||||
|
||||
&.is-selected {
|
||||
background-color: $colorSelectedBg;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
@@ -266,6 +312,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.paused {
|
||||
border: 1px solid #ff9900;
|
||||
}
|
||||
|
||||
/******************************* LEGACY */
|
||||
.s-status-taking-snapshot,
|
||||
.overlay.snapshot {
|
||||
@@ -279,12 +329,14 @@
|
||||
import TelemetryTableRow from './table-row.vue';
|
||||
import search from '../../../ui/components/search.vue';
|
||||
import TableColumnHeader from './table-column-header.vue';
|
||||
import TelemetryFilterIndicator from './TelemetryFilterIndicator.vue';
|
||||
import CSVExporter from '../../../exporters/CSVExporter.js';
|
||||
import _ from 'lodash';
|
||||
|
||||
const VISIBLE_ROW_COUNT = 100;
|
||||
const ROW_HEIGHT = 17;
|
||||
const RESIZE_POLL_INTERVAL = 200;
|
||||
const AUTO_SCROLL_TRIGGER_HEIGHT = 20;
|
||||
const AUTO_SCROLL_TRIGGER_HEIGHT = 100;
|
||||
const RESIZE_HOT_ZONE = 10;
|
||||
const MOVE_TRIGGER_WAIT = 500;
|
||||
const VERTICAL_SCROLL_WIDTH = 30;
|
||||
@@ -293,13 +345,30 @@ export default {
|
||||
components: {
|
||||
TelemetryTableRow,
|
||||
TableColumnHeader,
|
||||
search
|
||||
search,
|
||||
TelemetryFilterIndicator
|
||||
},
|
||||
inject: ['table', 'openmct', 'csvExporter'],
|
||||
inject: ['table', 'openmct'],
|
||||
props: {
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
allowExport: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
allowFiltering: {
|
||||
'type': Boolean,
|
||||
'default': true
|
||||
},
|
||||
allowSorting: {
|
||||
'type': Boolean,
|
||||
'default': true
|
||||
},
|
||||
enableMarking: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -328,7 +397,10 @@ export default {
|
||||
dropOffsetLeft: undefined,
|
||||
isDropTargetActive: false,
|
||||
isAutosizeEnabled: configuration.autosize,
|
||||
scrollW: 0
|
||||
scrollW: 0,
|
||||
markCounter: 0,
|
||||
paused: false,
|
||||
markedRows: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -364,42 +436,48 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
updateVisibleRows() {
|
||||
if (!this.updatingView) {
|
||||
this.updatingView = true;
|
||||
requestAnimationFrame(()=> {
|
||||
|
||||
let start = 0;
|
||||
let end = VISIBLE_ROW_COUNT;
|
||||
let filteredRows = this.table.filteredRows.getRows();
|
||||
let filteredRowsLength = filteredRows.length;
|
||||
let start = 0;
|
||||
let end = VISIBLE_ROW_COUNT;
|
||||
let filteredRows = this.table.filteredRows.getRows();
|
||||
let filteredRowsLength = filteredRows.length;
|
||||
|
||||
this.totalHeight = this.rowHeight * filteredRowsLength - 1;
|
||||
if (filteredRowsLength < VISIBLE_ROW_COUNT) {
|
||||
end = filteredRowsLength;
|
||||
} else {
|
||||
let firstVisible = this.calculateFirstVisibleRow();
|
||||
let lastVisible = this.calculateLastVisibleRow();
|
||||
let totalVisible = lastVisible - firstVisible;
|
||||
|
||||
if (filteredRowsLength < VISIBLE_ROW_COUNT) {
|
||||
end = filteredRowsLength;
|
||||
} else {
|
||||
let firstVisible = this.calculateFirstVisibleRow();
|
||||
let lastVisible = this.calculateLastVisibleRow();
|
||||
let totalVisible = lastVisible - firstVisible;
|
||||
let numberOffscreen = VISIBLE_ROW_COUNT - totalVisible;
|
||||
start = firstVisible - Math.floor(numberOffscreen / 2);
|
||||
end = lastVisible + Math.ceil(numberOffscreen / 2);
|
||||
|
||||
let numberOffscreen = VISIBLE_ROW_COUNT - totalVisible;
|
||||
start = firstVisible - Math.floor(numberOffscreen / 2);
|
||||
end = lastVisible + Math.ceil(numberOffscreen / 2);
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
end = Math.min(VISIBLE_ROW_COUNT, filteredRowsLength);
|
||||
} else if (end >= filteredRowsLength) {
|
||||
end = filteredRowsLength;
|
||||
start = end - VISIBLE_ROW_COUNT + 1;
|
||||
}
|
||||
}
|
||||
this.rowOffset = start;
|
||||
this.visibleRows = filteredRows.slice(start, end);
|
||||
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
end = Math.min(VISIBLE_ROW_COUNT, filteredRowsLength);
|
||||
} else if (end >= filteredRowsLength) {
|
||||
end = filteredRowsLength;
|
||||
start = end - VISIBLE_ROW_COUNT + 1;
|
||||
}
|
||||
this.updatingView = false;
|
||||
});
|
||||
}
|
||||
this.rowOffset = start;
|
||||
this.visibleRows = filteredRows.slice(start, end);
|
||||
},
|
||||
calculateFirstVisibleRow() {
|
||||
return Math.floor(this.scrollable.scrollTop / this.rowHeight);
|
||||
let scrollTop = this.scrollable.scrollTop;
|
||||
return Math.floor(scrollTop / this.rowHeight);
|
||||
},
|
||||
calculateLastVisibleRow() {
|
||||
let bottomScroll = this.scrollable.scrollTop + this.scrollable.offsetHeight;
|
||||
return Math.floor(bottomScroll / this.rowHeight);
|
||||
let scrollBottom = this.scrollable.scrollTop + this.scrollable.offsetHeight;
|
||||
return Math.ceil(scrollBottom / this.rowHeight);
|
||||
},
|
||||
updateHeaders() {
|
||||
this.headers = this.table.configuration.getVisibleHeaders();
|
||||
@@ -443,81 +521,92 @@ export default {
|
||||
}
|
||||
this.table.sortBy(this.sortOptions);
|
||||
},
|
||||
scroll() {
|
||||
if (!this.processingScroll) {
|
||||
this.processingScroll = true;
|
||||
requestAnimationFrame(()=> {
|
||||
this.updateVisibleRows();
|
||||
this.synchronizeScrollX();
|
||||
scroll () {
|
||||
this.updateVisibleRows();
|
||||
this.synchronizeScrollX();
|
||||
|
||||
if (this.shouldSnapToBottom()) {
|
||||
this.autoScroll = true;
|
||||
} else {
|
||||
// If user scrolls away from bottom, disable auto-scroll.
|
||||
// Auto-scroll will be re-enabled if user scrolls to bottom again.
|
||||
this.autoScroll = false;
|
||||
}
|
||||
this.processingScroll = false;
|
||||
});
|
||||
if (this.shouldSnapToBottom()) {
|
||||
this.autoScroll = true;
|
||||
} else {
|
||||
// If user scrolls away from bottom, disable auto-scroll.
|
||||
// Auto-scroll will be re-enabled if user scrolls to bottom again.
|
||||
this.autoScroll = false;
|
||||
}
|
||||
},
|
||||
shouldSnapToBottom() {
|
||||
return this.scrollable.scrollTop >= (this.scrollable.scrollHeight - this.scrollable.offsetHeight - AUTO_SCROLL_TRIGGER_HEIGHT);
|
||||
},
|
||||
scrollToBottom() {
|
||||
this.scrollable.scrollTop = this.scrollable.scrollHeight;
|
||||
this.scrollable.scrollTop = Number.MAX_SAFE_INTEGER;
|
||||
},
|
||||
synchronizeScrollX() {
|
||||
this.headersHolderEl.scrollLeft = this.scrollable.scrollLeft;
|
||||
},
|
||||
filterChanged(columnKey) {
|
||||
this.table.filteredRows.setColumnFilter(columnKey, this.filters[columnKey]);
|
||||
this.setHeight();
|
||||
},
|
||||
clearFilter(columnKey) {
|
||||
this.filters[columnKey] = '';
|
||||
this.table.filteredRows.setColumnFilter(columnKey, '');
|
||||
this.setHeight();
|
||||
},
|
||||
rowsAdded(rows) {
|
||||
rowsAdded (rows) {
|
||||
this.setHeight();
|
||||
|
||||
let sizingRow;
|
||||
if (Array.isArray(rows)) {
|
||||
sizingRow = rows[0];
|
||||
} else {
|
||||
sizingRow = rows;
|
||||
}
|
||||
|
||||
if (!this.sizingRows[sizingRow.objectKeyString]) {
|
||||
this.sizingRows[sizingRow.objectKeyString] = sizingRow;
|
||||
this.$nextTick().then(this.calculateColumnWidths);
|
||||
}
|
||||
|
||||
if (!this.updatingView) {
|
||||
this.updatingView = true;
|
||||
requestAnimationFrame(()=> {
|
||||
this.updateVisibleRows();
|
||||
if (this.autoScroll) {
|
||||
this.$nextTick().then(this.scrollToBottom);
|
||||
}
|
||||
this.updatingView = false;
|
||||
});
|
||||
if (this.autoScroll) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
this.updateVisibleRows();
|
||||
},
|
||||
rowsRemoved(rows) {
|
||||
if (!this.updatingView) {
|
||||
this.updatingView = true;
|
||||
requestAnimationFrame(()=> {
|
||||
this.updateVisibleRows();
|
||||
this.updatingView = false;
|
||||
});
|
||||
}
|
||||
rowsRemoved (rows) {
|
||||
this.setHeight();
|
||||
this.updateVisibleRows();
|
||||
},
|
||||
exportAsCSV() {
|
||||
/**
|
||||
* Calculates height based on total number of rows, and sets table height.
|
||||
*/
|
||||
setHeight() {
|
||||
let filteredRowsLength = this.table.filteredRows.getRows().length;
|
||||
this.totalHeight = this.rowHeight * filteredRowsLength - 1;
|
||||
// Set element height directly to avoid having to wait for Vue to update DOM
|
||||
// which causes subsequent scroll to use an out of date height.
|
||||
this.contentTable.style.height = this.totalHeight + 'px';
|
||||
},
|
||||
exportAsCSV(data) {
|
||||
const headerKeys = Object.keys(this.headers);
|
||||
const justTheData = this.table.filteredRows.getRows()
|
||||
.map(row => row.getFormattedDatum(this.headers));
|
||||
this.csvExporter.export(justTheData, {
|
||||
|
||||
this.csvExporter.export(data, {
|
||||
filename: this.table.domainObject.name + '.csv',
|
||||
headers: headerKeys
|
||||
});
|
||||
},
|
||||
exportAllDataAsCSV() {
|
||||
const justTheData = this.table.filteredRows.getRows()
|
||||
.map(row => row.getFormattedDatum(this.headers));
|
||||
|
||||
this.exportAsCSV(justTheData);
|
||||
},
|
||||
exportMarkedDataAsCSV() {
|
||||
const data = this.table.filteredRows.getRows()
|
||||
.filter(row => row.marked === true)
|
||||
.map(row => row.getFormattedDatum(this.headers));
|
||||
|
||||
this.exportAsCSV(data);
|
||||
},
|
||||
outstandingRequests(loading) {
|
||||
this.loading = loading;
|
||||
},
|
||||
@@ -595,23 +684,133 @@ export default {
|
||||
this.calculateTableSize();
|
||||
// On some resize events scrollTop is reset to 0. Possibly due to a transition we're using?
|
||||
// Need to preserve scroll position in this case.
|
||||
this.scrollable.scrollTop = scrollTop;
|
||||
if (this.autoScroll) {
|
||||
this.scrollToBottom();
|
||||
} else {
|
||||
this.scrollable.scrollTop = scrollTop;
|
||||
}
|
||||
width = el.clientWidth;
|
||||
height = el.clientHeight;
|
||||
}
|
||||
scrollTop = this.scrollable.scrollTop;
|
||||
}, RESIZE_POLL_INTERVAL);
|
||||
},
|
||||
clearRowsAndRerender() {
|
||||
this.visibleRows = [];
|
||||
this.$nextTick().then(this.updateVisibleRows);
|
||||
},
|
||||
pause(pausedByButton) {
|
||||
if (pausedByButton) {
|
||||
this.pausedByButton = true;
|
||||
}
|
||||
this.paused = true;
|
||||
this.table.pause();
|
||||
},
|
||||
unpause(unpausedByButton) {
|
||||
if (unpausedByButton) {
|
||||
this.paused = false;
|
||||
this.table.unpause();
|
||||
this.markedRows = [];
|
||||
this.pausedByButton = false;
|
||||
} else {
|
||||
if (!this.pausedByButton) {
|
||||
this.paused = false;
|
||||
this.table.unpause();
|
||||
this.markedRows = [];
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
togglePauseByButton() {
|
||||
if (this.paused) {
|
||||
this.unpause(true);
|
||||
} else {
|
||||
this.pause(true);
|
||||
}
|
||||
},
|
||||
undoMarkedRows(unpause) {
|
||||
this.markedRows.forEach(r => r.marked = false);
|
||||
this.markedRows = [];
|
||||
},
|
||||
unmarkRow(rowIndex) {
|
||||
this.undoMarkedRows();
|
||||
this.unpause();
|
||||
},
|
||||
markRow(rowIndex, keyModifier) {
|
||||
if (!this.enableMarking) {
|
||||
return;
|
||||
}
|
||||
|
||||
let insertMethod = 'unshift';
|
||||
|
||||
if (this.markedRows.length && !keyModifier) {
|
||||
this.undoMarkedRows();
|
||||
insertMethod = 'push';
|
||||
}
|
||||
|
||||
let markedRow = this.visibleRows[rowIndex];
|
||||
|
||||
this.$set(markedRow, 'marked', true);
|
||||
this.pause();
|
||||
|
||||
this.markedRows[insertMethod](markedRow);
|
||||
},
|
||||
unmarkAllRows(skipUnpause) {
|
||||
this.markedRows.forEach(row => row.marked = false);
|
||||
this.markedRows = [];
|
||||
this.unpause();
|
||||
},
|
||||
markMultipleConcurrentRows(rowIndex) {
|
||||
if (!this.enableMarking) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.markedRows.length) {
|
||||
this.markRow(rowIndex);
|
||||
} else {
|
||||
if (this.markedRows.length > 1) {
|
||||
this.markedRows.forEach((r,i) => {
|
||||
if (i !== 0) {
|
||||
r.marked = false;
|
||||
}
|
||||
});
|
||||
this.markedRows.splice(1);
|
||||
}
|
||||
let lastRowToBeMarked = this.visibleRows[rowIndex];
|
||||
|
||||
let allRows = this.table.filteredRows.getRows(),
|
||||
firstRowIndex = allRows.indexOf(this.markedRows[0]),
|
||||
lastRowIndex = allRows.indexOf(lastRowToBeMarked);
|
||||
|
||||
//supports backward selection
|
||||
if (lastRowIndex < firstRowIndex) {
|
||||
let temp = lastRowIndex;
|
||||
|
||||
lastRowIndex = firstRowIndex;
|
||||
firstRowIndex = temp - 1;
|
||||
}
|
||||
|
||||
for (var i = firstRowIndex + 1; i <= lastRowIndex; i++) {
|
||||
let row = allRows[i];
|
||||
row.marked = true;
|
||||
this.markedRows.push(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.filterChanged = _.debounce(this.filterChanged, 500);
|
||||
},
|
||||
mounted() {
|
||||
this.csvExporter = new CSVExporter();
|
||||
this.rowsAdded = _.throttle(this.rowsAdded, 200);
|
||||
this.rowsRemoved = _.throttle(this.rowsRemoved, 200);
|
||||
this.scroll = _.throttle(this.scroll, 100);
|
||||
|
||||
this.table.on('object-added', this.addObject);
|
||||
this.table.on('object-removed', this.removeObject);
|
||||
this.table.on('outstanding-requests', this.outstandingRequests);
|
||||
this.table.on('refresh', this.clearRowsAndRerender);
|
||||
|
||||
this.table.filteredRows.on('add', this.rowsAdded);
|
||||
this.table.filteredRows.on('remove', this.rowsRemoved);
|
||||
@@ -621,6 +820,7 @@ export default {
|
||||
//Default sort
|
||||
this.sortOptions = this.table.filteredRows.sortBy();
|
||||
this.scrollable = this.$el.querySelector('.js-telemetry-table__body-w');
|
||||
this.contentTable = this.$el.querySelector('.js-telemetry-table__content');
|
||||
this.sizingTable = this.$el.querySelector('.js-telemetry-table__sizing');
|
||||
this.headersHolderEl = this.$el.querySelector('.js-table__headers-w');
|
||||
|
||||
@@ -636,6 +836,7 @@ export default {
|
||||
this.table.off('object-added', this.addObject);
|
||||
this.table.off('object-removed', this.removeObject);
|
||||
this.table.off('outstanding-requests', this.outstandingRequests);
|
||||
this.table.off('refresh', this.clearRowsAndRerender);
|
||||
|
||||
this.table.filteredRows.off('add', this.rowsAdded);
|
||||
this.table.filteredRows.off('remove', this.rowsRemoved);
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<tr :style="{ top: rowTop }" :class="rowLimitClass">
|
||||
<td v-for="(title, key, headerIndex) in headers"
|
||||
:style="{ width: columnWidths[headerIndex], 'max-width': columnWidths[headerIndex]}"
|
||||
:title="formattedRow[key]"
|
||||
:class="cellLimitClasses[key]">{{formattedRow[key]}}</td>
|
||||
</tr>
|
||||
@@ -54,10 +54,11 @@
|
||||
|
||||
&:after {
|
||||
// App logo
|
||||
top: 0;
|
||||
right: 15%;
|
||||
bottom: 0;
|
||||
left: 15%;
|
||||
$d: 25%;
|
||||
top: $d;
|
||||
right: $d;
|
||||
bottom: $d;
|
||||
left: $d;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,12 +76,20 @@
|
||||
|
||||
&__image,
|
||||
&__text {
|
||||
height: 50%;
|
||||
flex: 1 1 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&__image {
|
||||
height: 35%;
|
||||
}
|
||||
|
||||
&__text {
|
||||
height: 65%;
|
||||
overflow: auto;
|
||||
> * + * {
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
margin-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
&--licenses {
|
||||
@@ -107,7 +116,7 @@
|
||||
|
||||
h1, h2, h3 {
|
||||
font-weight: normal;
|
||||
margin-bottom: 1em;
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
||||
@@ -70,9 +70,6 @@ $colorBodyFgEm: #fff;
|
||||
$colorGenBg: #222;
|
||||
$colorHeadBg: #262626;
|
||||
$colorHeadFg: $colorBodyFg;
|
||||
$colorStatusBarBg: $colorHeadBg;
|
||||
$colorStatusBarFg: $colorBodyFg;
|
||||
$colorStatusBarFgHov: #aaa;
|
||||
$colorKey: #0099cc;
|
||||
$colorKeyFg: #fff;
|
||||
$colorKeyHov: #26d8ff;
|
||||
@@ -101,10 +98,12 @@ $colorStatusAlertFilter: invert(78%) sepia(26%) saturate(1160%) hue-rotate(324de
|
||||
$colorStatusError: #da0004;
|
||||
$colorStatusErrorFilter: invert(10%) sepia(96%) saturate(4360%) hue-rotate(351deg) brightness(111%) contrast(115%);
|
||||
$colorStatusBtnBg: #666; // Where is this used?
|
||||
$colorStatusPartialBg: #3f5e8b;
|
||||
$colorStatusCompleteBg: #457638;
|
||||
$colorAlert: #ff3c00;
|
||||
$colorAlertFg: #fff;
|
||||
$colorWarningHi: #990000;
|
||||
$colorWarningHiFg: #FF9594;
|
||||
$colorWarningHi: #ff0000;
|
||||
$colorWarningHiFg: #ffdad0;
|
||||
$colorWarningLo: #ff9900;
|
||||
$colorWarningLoFg: #523400;
|
||||
$colorDiagnostic: #a4b442;
|
||||
@@ -115,6 +114,8 @@ $colorInfo: #2294a2;
|
||||
$colorInfoFg: #fff;
|
||||
$colorOk: #33cc33;
|
||||
$colorOkFg: #fff;
|
||||
$colorFilterBg: #44449c;
|
||||
$colorFilterFg: #8984e9;
|
||||
|
||||
// States
|
||||
$colorPausedBg: #ff9900;
|
||||
@@ -277,6 +278,11 @@ $colorIndicatorAvailable: $colorKey;
|
||||
$colorIndicatorDisabled: #555555;
|
||||
$colorIndicatorOn: $colorOk;
|
||||
$colorIndicatorOff: #777777;
|
||||
$colorIndicatorBgHov: rgba($colorHeadFg, 0.1);
|
||||
$colorIndicatorMenuBg: $colorHeadBg;
|
||||
$colorIndicatorMenuBgShdw: rgba(white, 0.6) 0 0 6px;
|
||||
$colorIndicatorMenuFg: $colorHeadFg;
|
||||
$colorIndicatorMenuFgHov: pullForward($colorHeadFg, 10%);
|
||||
|
||||
// Staleness
|
||||
$colorTelemFresh: pullForward($colorBodyFg, 20%);
|
||||
|
||||
@@ -74,9 +74,6 @@ $colorBodyFgEm: #fff;
|
||||
$colorGenBg: #222;
|
||||
$colorHeadBg: #262626;
|
||||
$colorHeadFg: $colorBodyFg;
|
||||
$colorStatusBarBg: $colorHeadBg;
|
||||
$colorStatusBarFg: $colorBodyFg;
|
||||
$colorStatusBarFgHov: #aaa;
|
||||
$colorKey: #0099cc;
|
||||
$colorKeyFg: #fff;
|
||||
$colorKeyHov: #26d8ff;
|
||||
@@ -105,10 +102,12 @@ $colorStatusAlertFilter: invert(78%) sepia(26%) saturate(1160%) hue-rotate(324de
|
||||
$colorStatusError: #da0004;
|
||||
$colorStatusErrorFilter: invert(10%) sepia(96%) saturate(4360%) hue-rotate(351deg) brightness(111%) contrast(115%);
|
||||
$colorStatusBtnBg: #666; // Where is this used?
|
||||
$colorStatusPartialBg: #3f5e8b;
|
||||
$colorStatusCompleteBg: #457638;
|
||||
$colorAlert: #ff3c00;
|
||||
$colorAlertFg: #fff;
|
||||
$colorWarningHi: #990000;
|
||||
$colorWarningHiFg: #FF9594;
|
||||
$colorWarningHi: #ff0000;
|
||||
$colorWarningHiFg: #ffdad0;
|
||||
$colorWarningLo: #ff9900;
|
||||
$colorWarningLoFg: #523400;
|
||||
$colorDiagnostic: #a4b442;
|
||||
@@ -119,6 +118,8 @@ $colorInfo: #2294a2;
|
||||
$colorInfoFg: #fff;
|
||||
$colorOk: #33cc33;
|
||||
$colorOkFg: #fff;
|
||||
$colorFilterBg: #44449c;
|
||||
$colorFilterFg: #8984e9;
|
||||
|
||||
// States
|
||||
$colorPausedBg: #ff9900;
|
||||
@@ -281,6 +282,11 @@ $colorIndicatorAvailable: $colorKey;
|
||||
$colorIndicatorDisabled: #555555;
|
||||
$colorIndicatorOn: $colorOk;
|
||||
$colorIndicatorOff: #777777;
|
||||
$colorIndicatorBgHov: rgba($colorHeadFg, 0.1);
|
||||
$colorIndicatorMenuBg: $colorHeadBg;
|
||||
$colorIndicatorMenuBgShdw: rgba(white, 0.6) 0 0 6px;
|
||||
$colorIndicatorMenuFg: $colorHeadFg;
|
||||
$colorIndicatorMenuFgHov: pullForward($colorHeadFg, 10%);
|
||||
|
||||
// Staleness
|
||||
$colorTelemFresh: pullForward($colorBodyFg, 20%);
|
||||
|
||||
@@ -70,9 +70,6 @@ $colorBodyFgEm: #333;
|
||||
$colorGenBg: #fff;
|
||||
$colorHeadBg: #eee;
|
||||
$colorHeadFg: $colorBodyFg;
|
||||
$colorStatusBarBg: #000;
|
||||
$colorStatusBarFg: #999;
|
||||
$colorStatusBarFgHov: #aaa;
|
||||
$colorKey: #0099cc;
|
||||
$colorKeyFg: #fff;
|
||||
$colorKeyHov: #00c0f6;
|
||||
@@ -101,6 +98,8 @@ $colorStatusAlertFilter: invert(89%) sepia(26%) saturate(5035%) hue-rotate(316de
|
||||
$colorStatusError: #da0004;
|
||||
$colorStatusErrorFilter: invert(8%) sepia(96%) saturate(4511%) hue-rotate(352deg) brightness(136%) contrast(114%);
|
||||
$colorStatusBtnBg: #666; // Where is this used?
|
||||
$colorStatusPartialBg: #c9d6ff;
|
||||
$colorStatusCompleteBg: #a4e4b4;
|
||||
$colorAlert: #ff3c00;
|
||||
$colorAlertFg: #fff;
|
||||
$colorWarningHi: #990000;
|
||||
@@ -115,6 +114,8 @@ $colorInfo: #2294a2;
|
||||
$colorInfoFg: #fff;
|
||||
$colorOk: #33cc33;
|
||||
$colorOkFg: #fff;
|
||||
$colorFilterBg: #a29fe2;
|
||||
$colorFilterFg: #fff;
|
||||
|
||||
// States
|
||||
$colorPausedBg: #ff9900;
|
||||
@@ -277,6 +278,11 @@ $colorIndicatorAvailable: $colorKey;
|
||||
$colorIndicatorDisabled: #444;
|
||||
$colorIndicatorOn: $colorOk;
|
||||
$colorIndicatorOff: #666;
|
||||
$colorIndicatorBgHov: rgba($colorHeadFg, 0.1);
|
||||
$colorIndicatorMenuBg: white;
|
||||
$colorIndicatorMenuBgShdw: rgba(black, 0.6) 0 0 6px;
|
||||
$colorIndicatorMenuFg: $colorHeadFg;
|
||||
$colorIndicatorMenuFgHov: pullForward($colorHeadFg, 10%);
|
||||
|
||||
// Staleness
|
||||
$colorTelemFresh: pullForward($colorBodyFg, 20%);
|
||||
|
||||
@@ -141,6 +141,8 @@ $glyph-icon-grid: '\e922';
|
||||
$glyph-icon-grippy-ew: '\e923';
|
||||
$glyph-icon-columns: '\e924';
|
||||
$glyph-icon-rows: '\e925';
|
||||
$glyph-icon-filter: '\e926';
|
||||
$glyph-icon-filter-outline: '\e927';
|
||||
$glyph-icon-arrows-right-left: '\ea00';
|
||||
$glyph-icon-arrows-up-down: '\ea01';
|
||||
$glyph-icon-bullet: '\ea02';
|
||||
|
||||
@@ -49,6 +49,21 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
&[class*='__collapse-button'] {
|
||||
box-shadow: none;
|
||||
background: $splitterBtnColorBg;
|
||||
color: $splitterBtnColorFg;
|
||||
border-radius: $smallCr;
|
||||
font-size: 6px;
|
||||
line-height: 90%;
|
||||
padding: 3px 15px;
|
||||
|
||||
@include hover() {
|
||||
background: $colorBtnBgHov;
|
||||
color: $colorBtnFgHov;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background: $colorBtnActiveBg;
|
||||
color: $colorBtnActiveFg;
|
||||
@@ -60,23 +75,23 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
/********* Icon Buttons */
|
||||
/********* Icon Buttons and Links */
|
||||
.c-click-icon {
|
||||
@include cClickIcon();
|
||||
}
|
||||
|
||||
.c-click-link {
|
||||
// A clickable element, typically inline, with an icon and label
|
||||
@include cControl();
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.c-icon-button,
|
||||
.c-click-swatch {
|
||||
@include cClickIconButton();
|
||||
|
||||
&--menu {
|
||||
&:after {
|
||||
content: $glyph-icon-arrow-down;
|
||||
font-family: symbolsfont;
|
||||
font-size: 0.7em;
|
||||
margin-left: floor($interiorMarginSm * 0.8);
|
||||
opacity: 0.5;
|
||||
}
|
||||
@include hasMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +141,7 @@ button {
|
||||
|
||||
/******************************************************** DISCLOSURE CONTROLS */
|
||||
/********* Disclosure Button */
|
||||
// Provides a downward arrow icon that when clicked displays a context menu
|
||||
// Provides a downward arrow icon that when clicked displays additional options and/or info.
|
||||
// Always placed AFTER an element
|
||||
.c-disclosure-button {
|
||||
@include cClickIcon();
|
||||
@@ -393,6 +408,11 @@ select {
|
||||
color: $colorMenuIc;
|
||||
font-size: 1em;
|
||||
margin-right: $interiorMargin;
|
||||
min-width: 1em;
|
||||
}
|
||||
|
||||
&:not([class]):before {
|
||||
content: ''; // Add this element so that menu items without an icon still indent properly
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,15 +600,15 @@ select {
|
||||
margin-right: $m;
|
||||
}
|
||||
|
||||
.c-separator {
|
||||
@include cToolbarSeparator();
|
||||
}
|
||||
|
||||
.c-toolbar {
|
||||
> * + * {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
&__button {
|
||||
|
||||
}
|
||||
|
||||
&__separator {
|
||||
@include cToolbarSeparator();
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
}
|
||||
|
||||
@font-face {
|
||||
// Use https://icomoon.io/app with icomoon-project-openmct-symbols-12px.json to generate font files
|
||||
// Use https://icomoon.io/app with icomoon-project-Open-MCT-Symbols-12px.json to generate font files
|
||||
font-family: 'symbolsfont-12px';
|
||||
src: url('./fonts/openmct-symbols-12px.woff') format('woff'),
|
||||
url('./fonts/openmct-symbols-12px.ttf') format('truetype');
|
||||
src: url('./fonts/Open-MCT-Symbols-12px.woff') format('woff'),
|
||||
url('./fonts/Open-MCT-Symbols-12px.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -77,6 +77,8 @@
|
||||
.icon-grippy-ew { @include glyphBefore($glyph-icon-grippy-ew); }
|
||||
.icon-columns { @include glyphBefore($glyph-icon-columns); }
|
||||
.icon-rows { @include glyphBefore($glyph-icon-rows); }
|
||||
.icon-filter { @include glyphBefore($glyph-icon-filter); }
|
||||
.icon-filter-outline { @include glyphBefore($glyph-icon-filter-outline); }
|
||||
.icon-arrows-right-left { @include glyphBefore($glyph-icon-arrows-right-left); }
|
||||
.icon-arrows-up-down { @include glyphBefore($glyph-icon-arrows-up-down); }
|
||||
.icon-bullet { @include glyphBefore($glyph-icon-bullet); }
|
||||
@@ -164,6 +166,8 @@
|
||||
|
||||
/************************** 12 PX CLASSES */
|
||||
// TODO: sync with 16px redo as of 10/25/18
|
||||
.icon-filter-12px { @include glyphBefore($glyph-icon-filter,'symbolsfont-12px'); }
|
||||
.icon-filter-outline-12px { @include glyphBefore($glyph-icon-filter-outline,'symbolsfont-12px'); }
|
||||
.icon-crosshair-12px { @include glyphBefore($glyph-icon-crosshair,'symbolsfont-12px'); }
|
||||
.icon-folder-12px { @include glyphBefore($glyph-icon-folder,'symbolsfont-12px'); }
|
||||
.icon-list-view-12px { @include glyphBefore($glyph-icon-list-view,'symbolsfont-12px'); }
|
||||
|
||||
@@ -782,126 +782,6 @@ mct-indicators mct-include {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.ls-indicator {
|
||||
$bg: rgba(white, 0.2) !important;
|
||||
$hbg: $colorStatusBarBg;
|
||||
$hshdw: rgba(white, 0.4) 0 0 3px;
|
||||
$br: $controlCr;
|
||||
$hoverYOffset: -35px;
|
||||
background: transparent !important;
|
||||
border-radius: $br;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding: 1px $interiorMarginSm; // Use padding instead of margin to keep hover chatter to a minimum
|
||||
text-transform: uppercase;
|
||||
|
||||
&:before {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.label {
|
||||
// Hover bubbles that appear when hovering on an Indicator
|
||||
display: inline-block;
|
||||
|
||||
a,
|
||||
button,
|
||||
s-button,
|
||||
.c-button {
|
||||
// Make <a> in label look like buttons
|
||||
transition: $transIn;
|
||||
background: transparent;
|
||||
border: 1px solid rgba($colorStatusBarFg, 0.5);
|
||||
border-radius: $br;
|
||||
box-sizing: border-box;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
height: auto;
|
||||
line-height: normal;
|
||||
padding: 0 2px;
|
||||
&:hover {
|
||||
background: $bg;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
[class*='icon-'] {
|
||||
// If any elements within label include the class 'icon-*' then deal with their :before's
|
||||
&:before {
|
||||
font-size: 0.8em;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.no-collapse {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
|
||||
> *,
|
||||
&:before {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&:before {
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.no-collapse) {
|
||||
&:before {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.label {
|
||||
transition: all 250ms ease-in 100ms;
|
||||
background: $hbg;
|
||||
border-radius: $br;
|
||||
font-size: .6rem;
|
||||
left: 0;
|
||||
bottom: 140%;
|
||||
opacity: 0;
|
||||
padding: $interiorMarginSm $interiorMargin;
|
||||
position: absolute;
|
||||
transform-origin: 10px 100%;
|
||||
transform: scale(0.0);
|
||||
white-space: nowrap;
|
||||
z-index: 50;
|
||||
|
||||
&:before {
|
||||
// Infobubble-style arrow element
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
@include triangle('down', $size: 4px, $ratio: 1, $color: $hbg);
|
||||
}
|
||||
}
|
||||
|
||||
@include hover() {
|
||||
background: $bg;
|
||||
|
||||
.label {
|
||||
opacity: 1;
|
||||
transform: scale(1.0);
|
||||
transition: all 100ms ease-out 0s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.float-right {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
// Hide the clock indicator when we're phone portrait
|
||||
body.phone.portrait {
|
||||
.ls-indicator.t-indicator-clock {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************* DATETIME UI */
|
||||
@mixin complexFieldHolder($myW) {
|
||||
width: $myW + $interiorMargin;
|
||||
|
||||
@@ -420,20 +420,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
@mixin cClickIconButton() {
|
||||
// A clickable element that just includes the icon
|
||||
// Background is displayed on hover
|
||||
// Padding is included to facilitate a bigger hit area
|
||||
// Make the icon bigger relative to its container
|
||||
@mixin cClickIconButtonLayout() {
|
||||
$pLR: 4px;
|
||||
$pTB: 4px;
|
||||
|
||||
@include cControl();
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
transition: $transOut;
|
||||
border-radius: $controlCr;
|
||||
padding: $pTB $pLR;
|
||||
|
||||
&:before,
|
||||
@@ -442,6 +431,20 @@
|
||||
// Needed for c-togglebutton.
|
||||
font-size: 1.25em;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin cClickIconButton() {
|
||||
// A clickable element that just includes the icon
|
||||
// Background is displayed on hover
|
||||
// Padding is included to facilitate a bigger hit area
|
||||
// Make the icon bigger relative to its container
|
||||
@include cControl();
|
||||
@include cClickIconButtonLayout();
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
transition: $transOut;
|
||||
border-radius: $controlCr;
|
||||
|
||||
@include hover() {
|
||||
transition: $transIn;
|
||||
@@ -478,6 +481,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
@mixin hasMenu() {
|
||||
&:after {
|
||||
content: $glyph-icon-arrow-down;
|
||||
font-family: symbolsfont;
|
||||
font-size: 0.7em;
|
||||
margin-left: floor($interiorMarginSm * 0.8);
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin cSelect($bg, $fg, $arwClr, $shdw) {
|
||||
$svgArwClr: str-slice(inspect($arwClr), 2, str-length(inspect($arwClr))); // Remove initial # in color value
|
||||
background: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3e%3cpath fill='%23#{$svgArwClr}' d='M5 5l5-5H0z'/%3e%3c/svg%3e"), $bg;
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
|
||||
@mixin indicatorStatusColors($c) {
|
||||
&:before, .count {
|
||||
&:before, .c-indicator__count {
|
||||
color: $c;
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ tr {
|
||||
.s-status-icon-ok:before { content: $glyph-icon-check; }
|
||||
|
||||
/*************************************************** INDICATOR COLORING */
|
||||
.ls-indicator {
|
||||
.c-indicator {
|
||||
&.s-status-info {
|
||||
@include indicatorStatusColors($colorInfo);
|
||||
}
|
||||
@@ -159,3 +159,16 @@ tr {
|
||||
@include indicatorStatusColors($colorStatusError);
|
||||
}
|
||||
}
|
||||
|
||||
.s-status {
|
||||
&--partial {
|
||||
// Partially completed things, such as a file downloading or process that's running
|
||||
background-color: $colorStatusPartialBg;
|
||||
}
|
||||
|
||||
&--complete {
|
||||
// Completed things, such as a file downloaded or process that's finished
|
||||
background-color: $colorStatusCompleteBg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,23 +76,43 @@ div.c-table {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.c-table-wrapper {
|
||||
// Wraps .c-control-bar and .c-table
|
||||
@include abs();
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> .c-table {
|
||||
height: auto;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.c-table-control-bar {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.c-table {
|
||||
// Can be used by any type of table, scrolling, LAD, etc.
|
||||
$min-w: 50px;
|
||||
|
||||
width: 100%;
|
||||
|
||||
&__control-bar,
|
||||
&__headers-w {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
/******************************* ELEMENTS */
|
||||
|
||||
&__control-bar {
|
||||
margin-bottom: $interiorMarginSm;
|
||||
}
|
||||
|
||||
thead tr,
|
||||
&.c-table__headers {
|
||||
background: $colorTabHeaderBg;
|
||||
|
||||
@@ -33,3 +33,4 @@
|
||||
@import "table";
|
||||
@import "legacy";
|
||||
@import "legacy-plots";
|
||||
@import "legacy-messages";
|
||||
|
||||
@@ -1,19 +1,35 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "openmct-symbols-12px",
|
||||
"name": "Open MCT Symbols 12px",
|
||||
"lastOpened": 0,
|
||||
"created": 1527031065005
|
||||
"created": 1561483556329
|
||||
},
|
||||
"iconSets": [
|
||||
{
|
||||
"selection": [
|
||||
{
|
||||
"order": 12,
|
||||
"id": 10,
|
||||
"name": "icon12-filter",
|
||||
"prevSize": 12,
|
||||
"code": 59686,
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 14,
|
||||
"id": 11,
|
||||
"name": "icon12-filter-outline",
|
||||
"prevSize": 12,
|
||||
"code": 59687,
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 9,
|
||||
"id": 6,
|
||||
"name": "icon12-crosshair",
|
||||
"prevSize": 12,
|
||||
"code": 59696,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 11,
|
||||
@@ -21,7 +37,7 @@
|
||||
"name": "icon12-grippy",
|
||||
"prevSize": 12,
|
||||
"code": 59697,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 10,
|
||||
@@ -29,7 +45,7 @@
|
||||
"name": "icon12-list-view",
|
||||
"prevSize": 12,
|
||||
"code": 921666,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 6,
|
||||
@@ -37,14 +53,14 @@
|
||||
"prevSize": 12,
|
||||
"code": 921865,
|
||||
"name": "icon12-folder",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
}
|
||||
],
|
||||
"id": 0,
|
||||
"metadata": {
|
||||
"name": "openmct-symbols-12px",
|
||||
"name": "Open MCT Symbols 12px",
|
||||
"importSize": {
|
||||
"width": 279,
|
||||
"width": 384,
|
||||
"height": 384
|
||||
},
|
||||
"designer": "Charles Hacskaylo"
|
||||
@@ -52,6 +68,28 @@
|
||||
"height": 1024,
|
||||
"prevSize": 12,
|
||||
"icons": [
|
||||
{
|
||||
"id": 10,
|
||||
"paths": [
|
||||
"M853.333 0h-682.667c-94.135 0.302-170.364 76.532-170.667 170.638l-0 0.029v682.667c0.302 94.135 76.532 170.364 170.638 170.667l0.029 0h256v-341.333l-341.333-341.333h853.333l-341.333 341.333 1.067 341.333h254.933c94.135-0.302 170.364-76.532 170.667-170.638l0-0.029v-682.667c-0.302-94.135-76.532-170.364-170.638-170.667l-0.029-0z"
|
||||
],
|
||||
"attrs": [],
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon12-filter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"paths": [
|
||||
"M853.333 0h-682.667c-94.135 0.302-170.364 76.532-170.667 170.638l-0 0.029v682.667c0.302 94.135 76.532 170.364 170.638 170.667l0.029 0h682.667c94.135-0.302 170.364-76.532 170.667-170.638l0-0.029v-682.667c-0.302-94.135-76.532-170.364-170.638-170.667l-0.029-0zM170.933 853.333h-0.267v-512l256 256v256zM853.067 853.333h-255.2l-0.533-256 256-256v511.733zM853.333 341.333h-682.667v-170.4h682.667z"
|
||||
],
|
||||
"attrs": [],
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon12-filter-outline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"paths": [
|
||||
@@ -60,26 +98,11 @@
|
||||
"M597.333 768h-170.667v256h170.667v-256z",
|
||||
"M256 426.667h-256v170.667h256v-170.667z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"attrs": [],
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon12-crosshair"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"1161751": [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
@@ -95,39 +118,12 @@
|
||||
"M744.773 511.867c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z",
|
||||
"M744.773 791.36c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"attrs": [],
|
||||
"width": 745,
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon12-grippy"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"1161751": [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
@@ -136,24 +132,11 @@
|
||||
"M0 426.667h1024v170.667h-1024v-170.667z",
|
||||
"M0 853.333h1024v170.667h-1024v-170.667z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"attrs": [],
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon12-list-view"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"1161751": [
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
@@ -162,40 +145,14 @@
|
||||
"M85.333 426.667h853.333c47.128 0 85.333 38.205 85.333 85.333v426.667c0 47.128-38.205 85.333-85.333 85.333h-853.333c-47.128 0-85.333-38.205-85.333-85.333v-426.667c0-47.128 38.205-85.333 85.333-85.333z"
|
||||
],
|
||||
"attrs": [],
|
||||
"isMulticolor": false,
|
||||
"grid": 0,
|
||||
"tags": [
|
||||
"icon12-folder"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"1161751": [
|
||||
{
|
||||
"f": 0
|
||||
},
|
||||
{
|
||||
"f": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"invisible": false,
|
||||
"colorThemes": [
|
||||
[
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
[
|
||||
0,
|
||||
161,
|
||||
75,
|
||||
1
|
||||
]
|
||||
]
|
||||
],
|
||||
"colorThemes": [],
|
||||
"colorThemeIdx": 0
|
||||
}
|
||||
],
|
||||
@@ -206,9 +163,9 @@
|
||||
"showQuickUse2": true,
|
||||
"showSVGs": true,
|
||||
"fontPref": {
|
||||
"prefix": "icon-",
|
||||
"prefix": "openmct-symbols-",
|
||||
"metadata": {
|
||||
"fontFamily": "openmct-symbols-12px",
|
||||
"fontFamily": "Open-MCT-Symbols-12px",
|
||||
"majorVersion": 1,
|
||||
"minorVersion": 0
|
||||
},
|
||||
@@ -217,7 +174,12 @@
|
||||
"baseline": 6.25,
|
||||
"whitespace": 50
|
||||
},
|
||||
"embed": false
|
||||
"embed": false,
|
||||
"noie8": true,
|
||||
"ie7": false,
|
||||
"showMetadata": false,
|
||||
"includeMetadata": false,
|
||||
"showMetrics": true
|
||||
},
|
||||
"imagePref": {
|
||||
"prefix": "icon-",
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "Open MCT Symbols",
|
||||
"name": "Open MCT Symbols 16px",
|
||||
"lastOpened": 0,
|
||||
"created": 1541830438012
|
||||
"created": 1561482854927
|
||||
},
|
||||
"iconSets": [
|
||||
{
|
||||
@@ -317,13 +317,29 @@
|
||||
"code": 59685,
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 161,
|
||||
"id": 142,
|
||||
"name": "icon-filter",
|
||||
"prevSize": 32,
|
||||
"code": 59686,
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 162,
|
||||
"id": 141,
|
||||
"name": "icon-filter-outline",
|
||||
"prevSize": 32,
|
||||
"code": 59687,
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 27,
|
||||
"id": 105,
|
||||
"name": "icon-arrows-right-left",
|
||||
"prevSize": 32,
|
||||
"code": 59904,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 26,
|
||||
@@ -331,7 +347,7 @@
|
||||
"name": "icon-arrows-up-down",
|
||||
"prevSize": 32,
|
||||
"code": 59905,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 68,
|
||||
@@ -339,7 +355,7 @@
|
||||
"name": "icon-bullet",
|
||||
"prevSize": 32,
|
||||
"code": 59906,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 150,
|
||||
@@ -347,7 +363,7 @@
|
||||
"prevSize": 32,
|
||||
"code": 59907,
|
||||
"name": "icon-calendar",
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 45,
|
||||
@@ -355,7 +371,7 @@
|
||||
"name": "icon-chain-links",
|
||||
"prevSize": 32,
|
||||
"code": 59908,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 73,
|
||||
@@ -363,7 +379,7 @@
|
||||
"name": "icon-download",
|
||||
"prevSize": 32,
|
||||
"code": 59909,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 39,
|
||||
@@ -371,7 +387,7 @@
|
||||
"name": "icon-duplicate",
|
||||
"prevSize": 32,
|
||||
"code": 59910,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 50,
|
||||
@@ -379,7 +395,7 @@
|
||||
"name": "icon-folder-new",
|
||||
"prevSize": 32,
|
||||
"code": 59911,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 138,
|
||||
@@ -387,7 +403,7 @@
|
||||
"name": "icon-fullscreen-collapse",
|
||||
"prevSize": 32,
|
||||
"code": 59912,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 139,
|
||||
@@ -395,7 +411,7 @@
|
||||
"name": "icon-fullscreen-expand",
|
||||
"prevSize": 32,
|
||||
"code": 59913,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 122,
|
||||
@@ -403,7 +419,7 @@
|
||||
"name": "icon-layers",
|
||||
"prevSize": 32,
|
||||
"code": 59914,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 151,
|
||||
@@ -411,7 +427,7 @@
|
||||
"name": "icon-line-horz",
|
||||
"prevSize": 32,
|
||||
"code": 59915,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 100,
|
||||
@@ -419,7 +435,7 @@
|
||||
"name": "icon-magnify",
|
||||
"prevSize": 32,
|
||||
"code": 59916,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 99,
|
||||
@@ -427,7 +443,7 @@
|
||||
"name": "icon-magnify-in",
|
||||
"prevSize": 32,
|
||||
"code": 59917,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 101,
|
||||
@@ -435,7 +451,7 @@
|
||||
"name": "icon-magnify-out-v2",
|
||||
"prevSize": 32,
|
||||
"code": 59918,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 103,
|
||||
@@ -443,7 +459,7 @@
|
||||
"name": "icon-menu",
|
||||
"prevSize": 32,
|
||||
"code": 59919,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 124,
|
||||
@@ -451,7 +467,7 @@
|
||||
"name": "icon-move",
|
||||
"prevSize": 32,
|
||||
"code": 59920,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 7,
|
||||
@@ -459,7 +475,7 @@
|
||||
"name": "icon-new-window",
|
||||
"prevSize": 32,
|
||||
"code": 59921,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 63,
|
||||
@@ -467,7 +483,7 @@
|
||||
"name": "icon-paint-bucket-v2",
|
||||
"prevSize": 32,
|
||||
"code": 59922,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 15,
|
||||
@@ -475,7 +491,7 @@
|
||||
"name": "icon-pencil",
|
||||
"prevSize": 32,
|
||||
"code": 59923,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 54,
|
||||
@@ -483,7 +499,7 @@
|
||||
"name": "icon-pencil-edit-in-place",
|
||||
"prevSize": 32,
|
||||
"code": 59924,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 40,
|
||||
@@ -491,7 +507,7 @@
|
||||
"name": "icon-play",
|
||||
"prevSize": 32,
|
||||
"code": 59925,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 125,
|
||||
@@ -499,7 +515,7 @@
|
||||
"name": "icon-pause",
|
||||
"prevSize": 32,
|
||||
"code": 59926,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 119,
|
||||
@@ -507,7 +523,7 @@
|
||||
"name": "icon-plot-resource",
|
||||
"prevSize": 32,
|
||||
"code": 59927,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 48,
|
||||
@@ -515,7 +531,7 @@
|
||||
"name": "icon-pointer-left",
|
||||
"prevSize": 32,
|
||||
"code": 59928,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 47,
|
||||
@@ -523,7 +539,7 @@
|
||||
"name": "icon-pointer-right",
|
||||
"prevSize": 32,
|
||||
"code": 59929,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 85,
|
||||
@@ -531,7 +547,7 @@
|
||||
"name": "icon-refresh",
|
||||
"prevSize": 32,
|
||||
"code": 59930,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 55,
|
||||
@@ -539,7 +555,7 @@
|
||||
"name": "icon-save",
|
||||
"prevSize": 32,
|
||||
"code": 59931,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 56,
|
||||
@@ -547,7 +563,7 @@
|
||||
"name": "icon-save-as",
|
||||
"prevSize": 32,
|
||||
"code": 59932,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 58,
|
||||
@@ -555,7 +571,7 @@
|
||||
"name": "icon-sine",
|
||||
"prevSize": 32,
|
||||
"code": 59933,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 113,
|
||||
@@ -563,7 +579,7 @@
|
||||
"name": "icon-font",
|
||||
"prevSize": 32,
|
||||
"code": 59934,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 41,
|
||||
@@ -571,7 +587,7 @@
|
||||
"name": "icon-thumbs-strip",
|
||||
"prevSize": 32,
|
||||
"code": 59935,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 146,
|
||||
@@ -579,7 +595,7 @@
|
||||
"name": "icon-two-parts-both",
|
||||
"prevSize": 32,
|
||||
"code": 59936,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 145,
|
||||
@@ -587,7 +603,7 @@
|
||||
"name": "icon-two-parts-one-only",
|
||||
"prevSize": 32,
|
||||
"code": 59937,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 82,
|
||||
@@ -595,7 +611,7 @@
|
||||
"name": "icon-resync",
|
||||
"prevSize": 32,
|
||||
"code": 59938,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 86,
|
||||
@@ -603,7 +619,7 @@
|
||||
"name": "icon-reset",
|
||||
"prevSize": 32,
|
||||
"code": 59939,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 61,
|
||||
@@ -611,7 +627,7 @@
|
||||
"name": "icon-x-in-circle",
|
||||
"prevSize": 32,
|
||||
"code": 59940,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 84,
|
||||
@@ -619,7 +635,7 @@
|
||||
"name": "icon-brightness",
|
||||
"prevSize": 32,
|
||||
"code": 59941,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 83,
|
||||
@@ -627,7 +643,7 @@
|
||||
"name": "icon-contrast",
|
||||
"prevSize": 32,
|
||||
"code": 59942,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 87,
|
||||
@@ -635,7 +651,7 @@
|
||||
"name": "icon-expand",
|
||||
"prevSize": 32,
|
||||
"code": 59943,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 89,
|
||||
@@ -643,7 +659,7 @@
|
||||
"name": "icon-list-view",
|
||||
"prevSize": 32,
|
||||
"code": 59944,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 133,
|
||||
@@ -651,7 +667,7 @@
|
||||
"name": "icon-grid-snap-to",
|
||||
"prevSize": 32,
|
||||
"code": 59945,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 132,
|
||||
@@ -659,7 +675,7 @@
|
||||
"name": "icon-grid-snap-no",
|
||||
"prevSize": 32,
|
||||
"code": 59946,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 94,
|
||||
@@ -667,7 +683,7 @@
|
||||
"name": "icon-frame-show",
|
||||
"prevSize": 32,
|
||||
"code": 59947,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 95,
|
||||
@@ -675,7 +691,7 @@
|
||||
"name": "icon-frame-hide",
|
||||
"prevSize": 32,
|
||||
"code": 59948,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 97,
|
||||
@@ -683,7 +699,7 @@
|
||||
"name": "icon-import",
|
||||
"prevSize": 32,
|
||||
"code": 59949,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 96,
|
||||
@@ -691,7 +707,7 @@
|
||||
"name": "icon-export",
|
||||
"prevSize": 32,
|
||||
"code": 59950,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 114,
|
||||
@@ -699,7 +715,7 @@
|
||||
"name": "icon-font-size",
|
||||
"prevSize": 32,
|
||||
"code": 59951,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 144,
|
||||
@@ -707,7 +723,7 @@
|
||||
"name": "icon-activity",
|
||||
"prevSize": 32,
|
||||
"code": 60160,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 104,
|
||||
@@ -715,7 +731,7 @@
|
||||
"name": "icon-activity-mode",
|
||||
"prevSize": 32,
|
||||
"code": 60161,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 137,
|
||||
@@ -723,7 +739,7 @@
|
||||
"name": "icon-autoflow-tabular",
|
||||
"prevSize": 32,
|
||||
"code": 60162,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 115,
|
||||
@@ -731,7 +747,7 @@
|
||||
"name": "icon-clock",
|
||||
"prevSize": 32,
|
||||
"code": 60163,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 2,
|
||||
@@ -739,7 +755,7 @@
|
||||
"name": "icon-database",
|
||||
"prevSize": 32,
|
||||
"code": 60164,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 3,
|
||||
@@ -747,7 +763,7 @@
|
||||
"name": "icon-database-query",
|
||||
"prevSize": 32,
|
||||
"code": 60165,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 67,
|
||||
@@ -755,7 +771,7 @@
|
||||
"name": "icon-dataset",
|
||||
"prevSize": 32,
|
||||
"code": 60166,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 59,
|
||||
@@ -763,7 +779,7 @@
|
||||
"name": "icon-datatable",
|
||||
"prevSize": 32,
|
||||
"code": 60167,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 136,
|
||||
@@ -771,7 +787,7 @@
|
||||
"name": "icon-dictionary",
|
||||
"prevSize": 32,
|
||||
"code": 60168,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 51,
|
||||
@@ -779,7 +795,7 @@
|
||||
"name": "icon-folder",
|
||||
"prevSize": 32,
|
||||
"code": 60169,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 147,
|
||||
@@ -787,7 +803,7 @@
|
||||
"name": "icon-image",
|
||||
"prevSize": 32,
|
||||
"code": 60170,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 4,
|
||||
@@ -795,7 +811,7 @@
|
||||
"name": "icon-layout",
|
||||
"prevSize": 32,
|
||||
"code": 60171,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 24,
|
||||
@@ -803,7 +819,7 @@
|
||||
"name": "icon-object",
|
||||
"prevSize": 32,
|
||||
"code": 60172,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 52,
|
||||
@@ -811,7 +827,7 @@
|
||||
"name": "icon-object-unknown",
|
||||
"prevSize": 32,
|
||||
"code": 60173,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 105,
|
||||
@@ -819,7 +835,7 @@
|
||||
"name": "icon-packet",
|
||||
"prevSize": 32,
|
||||
"code": 60174,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 126,
|
||||
@@ -827,7 +843,7 @@
|
||||
"name": "icon-page",
|
||||
"prevSize": 32,
|
||||
"code": 60175,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 130,
|
||||
@@ -835,7 +851,7 @@
|
||||
"name": "icon-plot-overlay",
|
||||
"prevSize": 32,
|
||||
"code": 60176,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 80,
|
||||
@@ -843,7 +859,7 @@
|
||||
"name": "icon-plot-stacked",
|
||||
"prevSize": 32,
|
||||
"code": 60177,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 134,
|
||||
@@ -851,7 +867,7 @@
|
||||
"name": "icon-session",
|
||||
"prevSize": 32,
|
||||
"code": 60178,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 109,
|
||||
@@ -859,7 +875,7 @@
|
||||
"name": "icon-tabular",
|
||||
"prevSize": 32,
|
||||
"code": 60179,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 107,
|
||||
@@ -867,7 +883,7 @@
|
||||
"name": "icon-tabular-lad",
|
||||
"prevSize": 32,
|
||||
"code": 60180,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 106,
|
||||
@@ -875,7 +891,7 @@
|
||||
"name": "icon-tabular-lad-set",
|
||||
"prevSize": 32,
|
||||
"code": 60181,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 70,
|
||||
@@ -883,7 +899,7 @@
|
||||
"name": "icon-tabular-realtime",
|
||||
"prevSize": 32,
|
||||
"code": 60182,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 60,
|
||||
@@ -891,7 +907,7 @@
|
||||
"name": "icon-tabular-scrolling",
|
||||
"prevSize": 32,
|
||||
"code": 60183,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 131,
|
||||
@@ -899,7 +915,7 @@
|
||||
"name": "icon-telemetry",
|
||||
"prevSize": 32,
|
||||
"code": 60184,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 108,
|
||||
@@ -907,7 +923,7 @@
|
||||
"name": "icon-timeline",
|
||||
"prevSize": 32,
|
||||
"code": 60185,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 81,
|
||||
@@ -915,7 +931,7 @@
|
||||
"name": "icon-timer",
|
||||
"prevSize": 32,
|
||||
"code": 60186,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 69,
|
||||
@@ -923,7 +939,7 @@
|
||||
"name": "icon-topic",
|
||||
"prevSize": 32,
|
||||
"code": 60187,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 79,
|
||||
@@ -931,7 +947,7 @@
|
||||
"name": "icon-box-with-dashed-lines-v2",
|
||||
"prevSize": 32,
|
||||
"code": 60188,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 90,
|
||||
@@ -939,7 +955,7 @@
|
||||
"name": "icon-summary-widget",
|
||||
"prevSize": 32,
|
||||
"code": 60189,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 92,
|
||||
@@ -947,7 +963,7 @@
|
||||
"name": "icon-notebook",
|
||||
"prevSize": 32,
|
||||
"code": 60190,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 118,
|
||||
@@ -955,7 +971,7 @@
|
||||
"name": "icon-tabs-view",
|
||||
"prevSize": 32,
|
||||
"code": 60191,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 117,
|
||||
@@ -963,7 +979,7 @@
|
||||
"name": "icon-flexible-layout",
|
||||
"prevSize": 32,
|
||||
"code": 60192,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 152,
|
||||
@@ -971,7 +987,7 @@
|
||||
"name": "icon-generator-sine",
|
||||
"prevSize": 32,
|
||||
"code": 60193,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 153,
|
||||
@@ -979,7 +995,7 @@
|
||||
"name": "icon-generator-event",
|
||||
"prevSize": 32,
|
||||
"code": 60194,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 160,
|
||||
@@ -987,7 +1003,7 @@
|
||||
"name": "icon-gauge",
|
||||
"prevSize": 32,
|
||||
"code": 60195,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
}
|
||||
],
|
||||
"id": 0,
|
||||
@@ -1602,6 +1618,46 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 142,
|
||||
"paths": [
|
||||
"M896 0h-768c-70.601 0.227-127.773 57.399-128 127.978l-0 0.022v768c0.227 70.601 57.399 127.773 127.978 128l0.022 0h256v-512l-192-192h640l-192 192v512h256c70.601-0.227 127.773-57.399 128-127.978l0-0.022v-768c-0.227-70.601-57.399-127.773-127.978-128l-0.022-0z"
|
||||
],
|
||||
"attrs": [
|
||||
{}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"grid": 1,
|
||||
"tags": [
|
||||
"icon-filter"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"11841841841": [
|
||||
{}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 141,
|
||||
"paths": [
|
||||
"M896 0h-768c-70.601 0.227-127.773 57.399-128 127.978l-0 0.022v768c0.227 70.601 57.399 127.773 127.978 128l0.022 0h768c70.601-0.227 127.773-57.399 128-127.978l0-0.022v-768c-0.227-70.601-57.399-127.773-127.978-128l-0.022-0zM896 895.8h-256v-383.8l192-192h-640l192 192v384h-256v-767.8h768z"
|
||||
],
|
||||
"attrs": [
|
||||
{}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"grid": 1,
|
||||
"tags": [
|
||||
"icon-filter-outline"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"11841841841": [
|
||||
{}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 105,
|
||||
"paths": [
|
||||
BIN
src/styles-new/fonts/Open-MCT-Symbols-12px.ttf
Normal file
BIN
src/styles-new/fonts/Open-MCT-Symbols-12px.ttf
Normal file
Binary file not shown.
BIN
src/styles-new/fonts/Open-MCT-Symbols-12px.woff
Normal file
BIN
src/styles-new/fonts/Open-MCT-Symbols-12px.woff
Normal file
Binary file not shown.
BIN
src/styles-new/fonts/Open-MCT-Symbols-16px.ttf
Executable file → Normal file
BIN
src/styles-new/fonts/Open-MCT-Symbols-16px.ttf
Executable file → Normal file
Binary file not shown.
BIN
src/styles-new/fonts/Open-MCT-Symbols-16px.woff
Executable file → Normal file
BIN
src/styles-new/fonts/Open-MCT-Symbols-16px.woff
Executable file → Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -123,7 +123,12 @@
|
||||
.c-click-icon,
|
||||
.c-button {
|
||||
// Shrink buttons a bit when they appear in a frame
|
||||
font-size: 0.8em;
|
||||
align-items: baseline;
|
||||
font-size: 0.85em;
|
||||
padding: 3px 5px;
|
||||
&:before {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -34,10 +34,10 @@ export default {
|
||||
this.currentObject = this.object;
|
||||
this.updateView();
|
||||
this.$el.addEventListener('dragover', this.onDragOver);
|
||||
this.$el.addEventListener('drop', this.addObjectToParent);
|
||||
this.$el.addEventListener('drop', this.editIfEditable, {
|
||||
capture: true
|
||||
});
|
||||
this.$el.addEventListener('drop', this.addObjectToParent);
|
||||
},
|
||||
methods: {
|
||||
clear() {
|
||||
@@ -57,6 +57,12 @@ export default {
|
||||
this.removeSelectable();
|
||||
delete this.removeSelectable;
|
||||
}
|
||||
|
||||
if (this.composition) {
|
||||
this.composition._destroy();
|
||||
}
|
||||
|
||||
this.openmct.objectViews.off('clearData', this.clearData);
|
||||
},
|
||||
invokeEditModeHandler(editMode) {
|
||||
this.currentView.onEditModeChange(editMode);
|
||||
@@ -70,6 +76,13 @@ export default {
|
||||
if (!this.currentObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.composition = this.openmct.composition.get(this.currentObject);
|
||||
if (this.composition) {
|
||||
this.composition._synchronize();
|
||||
this.loadComposition();
|
||||
}
|
||||
|
||||
this.viewContainer = document.createElement('div');
|
||||
this.viewContainer.classList.add('c-object-view','u-contents');
|
||||
this.$el.append(this.viewContainer);
|
||||
@@ -101,6 +114,8 @@ export default {
|
||||
this.removeSelectable = openmct.selection.selectable(
|
||||
this.$el, this.getSelectionContext(), true);
|
||||
}
|
||||
|
||||
this.openmct.objectViews.on('clearData', this.clearData);
|
||||
},
|
||||
show(object, viewKey, immediatelySelect) {
|
||||
if (this.unlisten) {
|
||||
@@ -112,6 +127,10 @@ export default {
|
||||
delete this.removeSelectable;
|
||||
}
|
||||
|
||||
if (this.composition) {
|
||||
this.composition._destroy();
|
||||
}
|
||||
|
||||
this.currentObject = object;
|
||||
this.unlisten = this.openmct.objects.observe(this.currentObject, '*', (mutatedObject) => {
|
||||
this.currentObject = mutatedObject;
|
||||
@@ -120,6 +139,9 @@ export default {
|
||||
this.viewKey = viewKey;
|
||||
this.updateView(immediatelySelect);
|
||||
},
|
||||
loadComposition() {
|
||||
return this.composition.load();
|
||||
},
|
||||
getSelectionContext() {
|
||||
if (this.currentView.getSelectionContext) {
|
||||
return this.currentView.getSelectionContext();
|
||||
@@ -133,10 +155,12 @@ export default {
|
||||
}
|
||||
},
|
||||
addObjectToParent(event) {
|
||||
if (this.hasComposableDomainObject(event)) {
|
||||
if (this.hasComposableDomainObject(event) && this.composition) {
|
||||
let composableDomainObject = this.getComposableDomainObject(event);
|
||||
this.currentObject.composition.push(composableDomainObject.identifier);
|
||||
this.openmct.objects.mutate(this.currentObject, 'composition', this.currentObject.composition);
|
||||
this.loadComposition().then(() => {
|
||||
this.composition.add(composableDomainObject);
|
||||
});
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
@@ -155,6 +179,7 @@ export default {
|
||||
editIfEditable(event) {
|
||||
let provider = this.getViewProvider();
|
||||
if (provider &&
|
||||
provider.canEdit &&
|
||||
provider.canEdit(this.currentObject) &&
|
||||
!this.openmct.editor.isEditing()) {
|
||||
this.openmct.editor.edit();
|
||||
@@ -166,6 +191,22 @@ export default {
|
||||
getComposableDomainObject(event) {
|
||||
let serializedDomainObject = event.dataTransfer.getData('openmct/composable-domain-object');
|
||||
return JSON.parse(serializedDomainObject);
|
||||
},
|
||||
clearData(domainObject) {
|
||||
if (domainObject) {
|
||||
let clearKeyString = this.openmct.objects.makeKeyString(domainObject.identifier),
|
||||
currentObjectKeyString = this.openmct.objects.makeKeyString(this.currentObject.identifier);
|
||||
|
||||
if (clearKeyString === currentObjectKeyString) {
|
||||
if (this.currentView.onClearData) {
|
||||
this.currentView.onClearData();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.currentView.onClearData) {
|
||||
this.currentView.onClearData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,6 @@ import _ from 'lodash';
|
||||
},
|
||||
methods: {
|
||||
updateSelection(selection) {
|
||||
if (_.isEqual(this.selection, selection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selection = selection;
|
||||
|
||||
if (this.selectedViews) {
|
||||
@@ -38,10 +34,6 @@ import _ from 'lodash';
|
||||
this.$el.innerHTML = '';
|
||||
}
|
||||
|
||||
if (selection.length > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedViews = this.openmct.inspectorViews.get(selection);
|
||||
this.selectedViews.forEach(selectedView => {
|
||||
let viewContainer = document.createElement('div');
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
<template>
|
||||
<div class="c-about c-about--splash">
|
||||
<div v-if="!branding.aboutHtml" class="c-about__image c-splash-image"></div>
|
||||
|
||||
<div class="c-about__image c-splash-image"></div>
|
||||
<div class="c-about__text s-text">
|
||||
<div v-if="branding.aboutHtml" class="s-text l-content" v-html="branding.aboutHtml"></div>
|
||||
<h1 class="l-title s-title">Open MCT</h1>
|
||||
<div class="l-description s-description">
|
||||
<p>Open MCT, Copyright © 2014-2019, United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All rights reserved.</p>
|
||||
<p>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 <a target="_blank" href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>.</p>
|
||||
<p>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.</p>
|
||||
<p>Open MCT includes source code licensed under additional open source licenses. See the Open Source Licenses file included with this distribution or <a @click="showLicenses">click here for third party licensing information</a>.</p>
|
||||
<div class="c-about__text__element" v-if="branding.aboutHtml" v-html="branding.aboutHtml"></div>
|
||||
<div class="c-about__text__element">
|
||||
<h1 class="l-title s-title">Open MCT</h1>
|
||||
<div class="l-description s-description">
|
||||
<p>Open MCT, Copyright © 2014-2019, United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All rights reserved.</p>
|
||||
<p>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 <a target="_blank" href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>.</p>
|
||||
<p>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.</p>
|
||||
<p>Open MCT includes source code licensed under additional open source licenses. See the Open Source Licenses file included with this distribution or <a @click="showLicenses">click here for third party licensing information</a>.</p>
|
||||
</div>
|
||||
<h2>Version Information</h2>
|
||||
<ul class="t-info l-info s-info">
|
||||
<li>Version: {{buildInfo.version || 'Unknown'}}</li>
|
||||
<li>Build Date: {{buildInfo.buildDate || 'Unknown'}}</li>
|
||||
<li>Revision: {{buildInfo.revision || 'Unknown'}}</li>
|
||||
<li>Branch: {{buildInfo.branch || 'Unknown'}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h2>Version Information</h2>
|
||||
<ul class="t-info l-info s-info">
|
||||
<li>Version: {{buildInfo.version || 'Unknown'}}</li>
|
||||
<li>Build Date: {{buildInfo.buildDate || 'Unknown'}}</li>
|
||||
<li>Revision: {{buildInfo.revision || 'Unknown'}}</li>
|
||||
<li>Branch: {{buildInfo.branch || 'Unknown'}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
<div class="l-shell" :class="{
|
||||
'is-editing': isEditing
|
||||
}">
|
||||
<div class="l-shell__head">
|
||||
<div class="l-shell__head" :class="{
|
||||
'l-shell__head--expanded': headExpanded,
|
||||
'l-shell__head--minify-indicators': !headExpanded
|
||||
}">
|
||||
<CreateButton class="l-shell__create-button"></CreateButton>
|
||||
<div class="l-shell__controls">
|
||||
<indicators class="l-shell__head-section l-shell__indicators">
|
||||
</indicators>
|
||||
<notification-banner></notification-banner>
|
||||
<div class="l-shell__head-section l-shell__controls">
|
||||
<button class="c-icon-button c-icon-button--major icon-new-window" title="Open in a new browser tab"
|
||||
@click="openInNewTab"
|
||||
target="_blank">
|
||||
@@ -15,6 +21,8 @@
|
||||
</button>
|
||||
</div>
|
||||
<app-logo></app-logo>
|
||||
<button class="l-shell__head__collapse-button c-button"
|
||||
@click="toggleShellHead"></button>
|
||||
</div>
|
||||
<multipane class="l-shell__main"
|
||||
type="horizontal">
|
||||
@@ -44,9 +52,6 @@
|
||||
<Inspector :isEditing="isEditing" ref="inspector"></Inspector>
|
||||
</pane>
|
||||
</multipane>
|
||||
<div class="l-shell__status">
|
||||
<StatusBar></StatusBar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -61,12 +66,6 @@
|
||||
flex-flow: column nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
&__status {
|
||||
background: $colorStatusBarBg;
|
||||
color: $colorStatusBarFg;
|
||||
padding: $interiorMarginSm;
|
||||
}
|
||||
|
||||
&__pane-tree {
|
||||
width: 40%;
|
||||
|
||||
@@ -160,14 +159,52 @@
|
||||
}
|
||||
|
||||
&__head {
|
||||
align-items: center;
|
||||
align-items: stretch;
|
||||
background: $colorHeadBg;
|
||||
justify-content: space-between;
|
||||
padding: $interiorMargin;
|
||||
padding: $interiorMargin $interiorMargin + 2;
|
||||
|
||||
> [class*="__"] + [class*="__"] {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
|
||||
[class*='__head__collapse-button'] {
|
||||
align-self: start;
|
||||
$p: 6px;
|
||||
padding-left: $p !important;
|
||||
padding-right: $p !important;
|
||||
|
||||
&:before {
|
||||
content: $glyph-icon-arrow-down;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
}
|
||||
|
||||
&-section {
|
||||
// Subdivides elements across the head
|
||||
display: flex;
|
||||
flex: 0 1 auto;
|
||||
padding: 0 $interiorMargin;
|
||||
}
|
||||
|
||||
&--expanded {
|
||||
.c-indicator__label {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
[class*='__head__collapse-button'] {
|
||||
&:before {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__controls {
|
||||
$brdr: 1px solid $colorInteriorBorder;
|
||||
border-right: $brdr;
|
||||
border-left: $brdr;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
&__create-button,
|
||||
@@ -175,11 +212,17 @@
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&__controls {
|
||||
flex: 1 1 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-right: 2.5%;
|
||||
&__create-button { margin-right: $interiorMarginLg; }
|
||||
|
||||
&__indicators {
|
||||
//@include test();
|
||||
flex: 1 1 auto;
|
||||
flex-wrap: wrap;
|
||||
[class*='indicator-clock'] { order: 90; }
|
||||
|
||||
.c-indicator .label {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* MAIN AREA */
|
||||
@@ -266,9 +309,10 @@
|
||||
import multipane from './multipane.vue';
|
||||
import pane from './pane.vue';
|
||||
import BrowseBar from './BrowseBar.vue';
|
||||
import StatusBar from './status-bar/StatusBar.vue';
|
||||
import Toolbar from '../toolbar/Toolbar.vue';
|
||||
import AppLogo from './AppLogo.vue';
|
||||
import Indicators from './status-bar/Indicators.vue';
|
||||
import NotificationBanner from './status-bar/NotificationBanner.vue';
|
||||
|
||||
var enterFullScreen = () => {
|
||||
var docElm = document.documentElement;
|
||||
@@ -309,9 +353,10 @@
|
||||
multipane,
|
||||
pane,
|
||||
BrowseBar,
|
||||
StatusBar,
|
||||
Toolbar,
|
||||
AppLogo
|
||||
AppLogo,
|
||||
Indicators,
|
||||
NotificationBanner
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.editor.on('isEditing', (isEditing)=>{
|
||||
@@ -321,11 +366,18 @@
|
||||
this.openmct.selection.on('change', this.toggleHasToolbar);
|
||||
},
|
||||
data: function () {
|
||||
let storedHeadProps = window.localStorage.getItem('openmct-shell-head');
|
||||
let headExpanded = true;
|
||||
if (storedHeadProps) {
|
||||
headExpanded = JSON.parse(storedHeadProps).expanded;
|
||||
}
|
||||
|
||||
return {
|
||||
fullScreen: false,
|
||||
conductorComponent: undefined,
|
||||
isEditing: false,
|
||||
hasToolbar: false
|
||||
hasToolbar: false,
|
||||
headExpanded
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -334,6 +386,18 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleShellHead() {
|
||||
this.headExpanded = !this.headExpanded;
|
||||
|
||||
window.localStorage.setItem(
|
||||
'openmct-shell-head',
|
||||
JSON.stringify(
|
||||
{
|
||||
expanded: this.headExpanded
|
||||
}
|
||||
)
|
||||
);
|
||||
},
|
||||
fullScreenToggle() {
|
||||
if (this.fullScreen) {
|
||||
this.fullScreen = false;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user