Compare commits

..

7 Commits

Author SHA1 Message Date
charlesh88
38c1a981e8 Clock element as a standalone component
- Was intended to replace clock indicator;
- WIP!
2019-06-25 10:10:58 -07:00
charlesh88
50944cfed0 Status bar migration to top of layout, WIP
- Added tracking style to indicator-template;
- Moved click action to button in label of globalClearIndicator;
- Removed unnecessary markup in Indicators.vue;
- Commented out __head collapse button for now in Layout.vue;
2019-06-07 19:04:30 -07:00
charlesh88
27b236ffe4 Status bar migration to top of layout, WIP
- Refine styles and markup for Indicators;
- Better separation of styles for clickable and non-clickable
Indicators;
2019-06-07 18:30:08 -07:00
charlesh88
b7e75bcc22 Status bar migration to top of layout, WIP
- Refine and remove legacy styles for Indicators;
- Significant cleanup in Indicator markup;
- Remove unnecessary wrapper component StatusBar.vue;
- Move collapse-button styles to a more general location in _controls
.scss;
- New hasMenu mixin to allow easier application of disclosure control
styling;
2019-06-07 16:07:50 -07:00
Deep Tailor
210a23dfe2 styling 2019-06-06 15:29:19 -07:00
Deep Tailor
84bfb9e8cc global clear works on plots 2019-06-06 15:06:03 -07:00
Deep Tailor
fd749253d9 first proto of global clear, working on tables 2019-06-06 14:38:41 -07:00
105 changed files with 930 additions and 2737 deletions

View File

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

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="DialogLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<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>
<div class="c-indicator c-indicator--clickable 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>
</span></div>
</span>

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="NotificationLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<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>
<div class="c-indicator c-indicator--clickable 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>
</span></div>
</span>

View File

@@ -50,6 +50,7 @@
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"
}));
@@ -79,9 +80,14 @@
}));
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.install(openmct.plugins.GoToOriginalAction());
openmct.install(openmct.plugins.GlobalClearIndicator());
openmct.start();
</script>
</html>

View File

@@ -1,10 +1,9 @@
{
"name": "openmct",
"version": "1.0.0-beta",
"version": "0.14.0-SNAPSHOT",
"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",
@@ -56,7 +55,7 @@
"node-bourbon": "^4.2.3",
"node-sass": "^4.9.2",
"painterro": "^0.2.65",
"printj": "^1.2.1",
"printj": "^1.1.0",
"raw-loader": "^0.5.1",
"request": "^2.69.0",
"split": "^1.0.0",

View File

@@ -23,5 +23,5 @@
<div class="c-indicator {{ngModel.getCssClass()}}"
title="{{ngModel.getDescription()}}"
ng-show="ngModel.getText().length > 0">
<span class="label c-indicator__label">{{ngModel.getText()}}</span>
<span class="label">{{ngModel.getText()}}</span>
</div>

View File

@@ -1,8 +1,8 @@
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div ng-show="notifications.length > 0" class="c-indicator c-indicator--clickable s-status-{{highest.severity}} icon-bell"
ng-controller="NotificationIndicatorController">
<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>
<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>
</div>

View File

@@ -49,7 +49,7 @@ define(
};
ClockIndicator.prototype.getCssClass = function () {
return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable";
return "t-indicator-clock icon-clock no-collapse c-indicator--not-clickable";
};
ClockIndicator.prototype.getText = function () {

View File

@@ -64,30 +64,12 @@ 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');
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();
}
}
]
});
}
// 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);
};
ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) {

View File

@@ -29,7 +29,6 @@ define([
"./res/templates/search.html",
"./res/templates/search-menu.html",
"raw-loader!./src/services/GenericSearchWorker.js",
"raw-loader!./src/services/BareBonesSearchWorker.js",
'legacyRegistry'
], function (
SearchController,
@@ -40,7 +39,6 @@ define([
searchTemplate,
searchMenuTemplate,
searchWorkerText,
BareBonesSearchWorkerText,
legacyRegistry
) {
@@ -117,10 +115,6 @@ define([
}
],
"workers": [
{
"key": "bareBonesSearchWorker",
"scriptText": BareBonesSearchWorkerText
},
{
"key": "genericSearchWorker",
"scriptText": searchWorkerText

View File

@@ -1,80 +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.
*****************************************************************************/
/*global self*/
/**
* Module defining GenericSearchWorker. Created by shale on 07/21/2015.
*/
(function () {
// An array of objects composed of domain object IDs and models
// {id: domainObject's ID, model: domainObject's model}
var indexedItems = [];
function indexItem(id, model) {
indexedItems.push({
id: id,
name: model.name.toLowerCase()
});
}
/**
* Gets search results from the indexedItems based on provided search
* input. Returns matching results from indexedItems
*
* @param data An object which contains:
* * input: The original string which we are searching with
* * maxResults: The maximum number of search results desired
* * queryId: an id identifying this query, will be returned.
*/
function search(data) {
// This results dictionary will have domain object ID keys which
// point to the value the domain object's score.
var results,
input = data.input.trim().toLowerCase(),
message = {
request: 'search',
results: {},
total: 0,
queryId: data.queryId
};
results = indexedItems.filter((indexedItem) => {
return indexedItem.name.includes(input);
});
message.total = results.length;
message.results = results
.slice(0, data.maxResults);
return message;
}
self.onmessage = function (event) {
if (event.data.request === 'index') {
indexItem(event.data.id, event.data.model);
} else if (event.data.request === 'search') {
self.postMessage(search(event.data));
}
};
}());

View File

@@ -58,8 +58,6 @@ define([
this.pendingQueries = {};
this.useBareBones = true;
this.worker = this.startWorker(workerService);
this.indexOnMutation(topic);
@@ -103,14 +101,8 @@ define([
* @returns worker the created search worker.
*/
GenericSearchProvider.prototype.startWorker = function (workerService) {
var provider = this,
worker;
if (this.useBareBones) {
worker = workerService.run('bareBonesSearchWorker');
} else {
worker = workerService.run('genericSearchWorker');
}
var worker = workerService.run('genericSearchWorker'),
provider = this;
worker.addEventListener('message', function (messageEvent) {
provider.onWorkerMessage(messageEvent);
@@ -250,34 +242,18 @@ define([
return;
}
var pendingQuery,
modelResults;
if (this.useBareBones) {
pendingQuery = this.pendingQueries[event.data.queryId];
var pendingQuery = this.pendingQueries[event.data.queryId],
modelResults = {
total: event.data.total
};
modelResults.hits = event.data.results.map(function (hit) {
return {
id: hit.id
};
});
} else {
pendingQuery = this.pendingQueries[event.data.queryId];
modelResults = {
total: event.data.total
modelResults.hits = event.data.results.map(function (hit) {
return {
id: hit.item.id,
model: hit.item.model,
score: hit.matchCount
};
modelResults.hits = event.data.results.map(function (hit) {
return {
id: hit.item.id,
model: hit.item.model,
score: hit.matchCount
};
});
}
});
pendingQuery.resolve(modelResults);
delete this.pendingQueries[event.data.queryId];

View File

@@ -144,8 +144,6 @@
message.results = results
.slice(0, data.maxResults);
console.log(message);
return message;
}

View File

@@ -246,21 +246,12 @@ 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));

View File

@@ -26,7 +26,6 @@ const OUTSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "properties", "move", "li
export default class LegacyContextMenuAction {
constructor(openmct, LegacyAction) {
this.openmct = openmct;
this.key = LegacyAction.definition.key;
this.name = LegacyAction.definition.name;
this.description = LegacyAction.definition.description;
this.cssClass = LegacyAction.definition.cssClass;

View File

@@ -108,9 +108,6 @@ define([
link();
}
},
onClearData() {
scope.$broadcast('clearData');
},
destroy: function () {
element.off();
element.remove();

View File

@@ -25,7 +25,7 @@ define([
cssClass: representation.cssClass,
description: representation.description,
canView: function (selection) {
if (selection.length !== 1 || selection[0].length === 0) {
if (selection.length === 0 || selection[0].length === 0) {
return false;
}

View File

@@ -49,9 +49,6 @@ class ContextMenuAPI {
* a single sentence or short paragraph) of this kind of view
* @property {string} cssClass the CSS class to apply to labels for this
* view (to add icons, for instance)
* @property {string} key unique key to identify the context menu action
* (used in custom context menu eg table rows, to identify which actions to include)
* @property {boolean} hideInDefaultMenu optional flag to hide action from showing in the default context menu (tree item)
*/
/**
* @method appliesTo
@@ -75,21 +72,12 @@ class ContextMenuAPI {
/**
* @private
*/
_showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded) {
_showContextMenuForObjectPath(objectPath, x, y) {
let applicableActions = this._allActions.filter((action) => {
if (actionsToBeIncluded) {
if (action.appliesTo === undefined && actionsToBeIncluded.includes(action.key)) {
return true;
}
return action.appliesTo(objectPath, actionsToBeIncluded) && actionsToBeIncluded.includes(action.key);
} else {
if (action.appliesTo === undefined) {
return true;
}
return action.appliesTo(objectPath) && !action.hideInDefaultMenu;
if (action.appliesTo === undefined) {
return true;
}
return action.appliesTo(objectPath);
});
if (this._activeContextMenu) {

View File

@@ -28,7 +28,7 @@ define(['zepto', './res/indicator-template.html'],
this.openmct = openmct;
this.element = $(indicatorTemplate)[0];
this.textElement = this.element.querySelector('.js-indicator-text');
this.textElement = this.element.querySelector('.indicator-text');
//Set defaults
this.text('New Indicator');

View File

@@ -1,3 +1,3 @@
<div class="c-indicator c-indicator--clickable c-indicator--simple" title="">
<span class="label js-indicator-text c-indicator__label"></span>
<span class="label indicator-text"></span>
</div>

View File

@@ -93,7 +93,7 @@
&.message-severity-error:before {
@include legacyMessage();
content: $glyph-icon-alert-triangle;
color: $colorWarningHi;
color: $colorWarningLo;
}
// Messages in a list

View File

@@ -69,7 +69,6 @@
flex: 1 1 auto;
display: flex;
flex-direction: column;
overflow: hidden;
}
&__top-bar {

View File

@@ -38,7 +38,7 @@ define([
canEdit: function (domainObject) {
return domainObject.type === 'LadTableSet';
},
view: function (domainObject, isEditing, objectPath) {
view: function (domainObject) {
let component;
return {
@@ -49,8 +49,7 @@ define([
},
provide: {
openmct,
domainObject,
objectPath
domainObject
},
el: element,
template: '<lad-table-set></lad-table-set>'

View File

@@ -38,7 +38,7 @@ define([
canEdit: function (domainObject) {
return domainObject.type === 'LadTable';
},
view: function (domainObject, isEditing, objectPath) {
view: function (domainObject) {
let component;
return {
@@ -49,8 +49,7 @@ define([
},
provide: {
openmct,
domainObject,
objectPath
domainObject
},
el: element,
template: '<lad-table-component></lad-table-component>'

View File

@@ -1,4 +1,3 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
@@ -22,7 +21,7 @@
*****************************************************************************/
<template>
<tr @contextmenu.prevent="showContextMenu">
<tr>
<td>{{name}}</td>
<td>{{timestamp}}</td>
<td :class="valueClass">
@@ -36,25 +35,15 @@
</style>
<script>
const CONTEXT_MENU_ACTIONS = [
'viewHistoricalData',
'remove'
];
export default {
inject: ['openmct', 'objectPath'],
inject: ['openmct'],
props: ['domainObject'],
data() {
let currentObjectPath = this.objectPath.slice();
currentObjectPath.unshift(this.domainObject);
return {
name: this.domainObject.name,
timestamp: '---',
value: '---',
valueClass: '',
currentObjectPath
valueClass: ''
}
},
methods: {
@@ -84,15 +73,11 @@ export default {
.request(this.domainObject, {strategy: 'latest'})
.then((array) => this.updateValues(array[array.length - 1]));
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
}
},
mounted() {
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.limitEvaluator = openmct
.telemetry

View File

@@ -44,7 +44,7 @@ import lodash from 'lodash';
import LadRow from './LADRow.vue';
export default {
inject: ['openmct', 'domainObject', 'objectPath'],
inject: ['openmct', 'domainObject'],
components: {
LadRow
},

View File

@@ -1,39 +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.
*****************************************************************************/
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;
}
}

View File

@@ -1,62 +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.
*****************************************************************************/
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]);
});
});

View File

@@ -1,78 +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([
'./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 (domainObject, isEditing, objectPath) {
let component;
return {
show: function (element) {
component = new Vue({
provide: {
openmct,
objectPath
},
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;
});

View File

@@ -1,90 +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.
*****************************************************************************/
<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>

View File

@@ -48,8 +48,7 @@
:multiSelect="selectedLayoutItems.length > 1"
@move="move"
@endMove="endMove"
@endLineResize='endLineResize'
@formatChanged='updateTelemetryFormat'>
@endLineResize='endLineResize'>
</component>
<edit-marquee v-if='showMarquee'
:gridSize="gridSize"
@@ -202,7 +201,7 @@
return selectionPath && selectionPath.length > 1 && !singleSelectedLine;
}
},
inject: ['openmct', 'options', 'objectPath'],
inject: ['openmct', 'options'],
props: ['domainObject'],
components: components,
methods: {
@@ -558,11 +557,6 @@
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() {

View File

@@ -27,7 +27,7 @@
@endMove="() => $emit('endMove')">
<object-frame v-if="domainObject"
:domain-object="domainObject"
:object-path="currentObjectPath"
:object-path="objectPath"
:has-frame="item.hasFrame"
:show-edit-view="false"
ref="objectFrame">
@@ -71,7 +71,7 @@
hasFrame: hasFrameByDefault(domainObject.type)
};
},
inject: ['openmct', 'objectPath'],
inject: ['openmct'],
props: {
item: Object,
gridSize: Array,
@@ -81,7 +81,7 @@
data() {
return {
domainObject: undefined,
currentObjectPath: []
objectPath: []
}
},
components: {
@@ -100,7 +100,7 @@
methods: {
setObject(domainObject) {
this.domainObject = domainObject;
this.currentObjectPath = [this.domainObject].concat(this.objectPath.slice());
this.objectPath = [this.domainObject].concat(this.openmct.router.path);
this.$nextTick(function () {
let childContext = this.$refs.objectFrame.getSelectionContext();
childContext.item = domainObject;

View File

@@ -27,8 +27,7 @@
@endMove="() => $emit('endMove')">
<div class="c-telemetry-view"
:style="styleObject"
v-if="domainObject"
@contextmenu.prevent="showContextMenu">
v-if="domainObject">
<div v-if="showLabel"
class="c-telemetry-view__label">
<div class="c-telemetry-view__label-text">{{ domainObject.name }}</div>
@@ -80,11 +79,9 @@
<script>
import LayoutFrame from './LayoutFrame.vue'
import printj from 'printj'
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
DEFAULT_POSITION = [1, 1],
CONTEXT_MENU_ACTIONS = ['viewHistoricalData'];
DEFAULT_POSITION = [1, 1];
export default {
makeDefinition(openmct, gridSize, domainObject, position) {
@@ -105,7 +102,7 @@
size: "13px"
};
},
inject: ['openmct', 'objectPath'],
inject: ['openmct'],
props: {
item: Object,
gridSize: Array,
@@ -146,10 +143,6 @@
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() {
@@ -165,8 +158,7 @@
return {
datum: undefined,
formats: undefined,
domainObject: undefined,
currentObjectPath: undefined
domainObject: undefined
}
},
watch: {
@@ -176,9 +168,6 @@
}
this.context.index = newIndex;
},
item(newItem) {
this.context.layoutItem = newItem;
}
},
methods: {
@@ -221,30 +210,19 @@
},
setObject(domainObject) {
this.domainObject = domainObject;
this.keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.requestHistoricalData();
this.subscribeToObject();
this.currentObjectPath = this.objectPath.slice();
this.currentObjectPath.unshift(this.domainObject);
this.context = {
item: domainObject,
layoutItem: this.item,
index: this.index,
updateTelemetryFormat: this.updateTelemetryFormat
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, this.context, this.initSelect);
},
updateTelemetryFormat(format) {
this.$emit('formatChanged', this.item, format);
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
}
},
mounted() {

View File

@@ -25,8 +25,6 @@ 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({
@@ -37,7 +35,7 @@ export default function DisplayLayoutPlugin(options) {
canEdit: function (domainObject) {
return domainObject.type === 'layout';
},
view: function (domainObject, isEditing, objectPath) {
view: function (domainObject) {
let component;
return {
show(container) {
@@ -49,14 +47,13 @@ export default function DisplayLayoutPlugin(options) {
provide: {
openmct,
objectUtils,
options,
objectPath
options
},
el: container,
data () {
return {
domainObject: domainObject
};
}
}
});
},
@@ -79,8 +76,7 @@ export default function DisplayLayoutPlugin(options) {
}
});
openmct.types.addType('layout', DisplayLayoutType());
openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct, options));
openmct.inspectorViews.addProvider(new AlphaNumericFormatViewProvider(openmct, options));
openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct));
openmct.composition.addPolicy((parent, child) => {
if (parent.type === 'layout' && child.type === 'folder') {
return false;

View File

@@ -1,20 +1,19 @@
<template>
<div class="c-properties__section c-filter-settings">
<li class="c-properties__row c-filter-settings__setting"
<div class="u-contents c-filter-settings">
<li class="grid-row c-filter-settings__setting"
v-for="(filter, index) in filterField.filters"
:key="index">
<div class="c-properties__label label"
:disabled="useGlobal">
<div class="grid-cell label">
{{ filterField.name }} =
</div>
<div class="c-properties__value value">
<div class="grid-cell value">
<!-- EDITING -->
<!-- String input, editing -->
<template v-if="!filter.possibleValues && isEditing">
<input class="c-input--flex"
type="text"
placeholder="Enter Value"
:id="`${filter}filterControl`"
:disabled="useGlobal"
:value="persistedValue(filter)"
@change="updateFilterValue($event, filter)">
</template>
@@ -22,16 +21,15 @@
<!-- Checkbox list, editing -->
<template v-if="filter.possibleValues && isEditing">
<div class="c-checkbox-list__row"
v-for="option in filter.possibleValues"
:key="option.value">
v-for="value in filter.possibleValues"
:key="value">
<input class="c-checkbox-list__input"
type="checkbox"
:id="`${option.value}filterControl`"
:disabled="useGlobal"
@change="updateFilterValue($event, filter.comparator, option.value)"
:checked="isChecked(filter.comparator, option.value)">
:id="`${value}filterControl`"
@change="onUserSelect($event, filter.comparator, value)"
:checked="isChecked(filter.comparator, value)">
<span class="c-checkbox-list__value">
{{ option.label }}
{{ value }}
</span>
</div>
</template>
@@ -44,8 +42,9 @@
<!-- Checkbox list, NOT editing -->
<template v-if="filter.possibleValues && !isEditing">
<span v-if="persistedFilters[filter.comparator]">
{{ getFilterLabels(filter) }}
<span
v-if="persistedFilters[filter.comparator]">
{{persistedFilters[filter.comparator].join(', ')}}
</span>
</template>
</div>
@@ -53,14 +52,26 @@
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-filter-settings {
&__setting {
.grid-cell.label {
white-space: nowrap;
}
}
}
</style>
<script>
export default {
inject: [
'openmct'
],
props: {
filterField: Object,
useGlobal: Boolean,
filterField: Object,
persistedFilters: {
type: Object,
default: () => {
@@ -70,6 +81,7 @@ export default {
},
data() {
return {
expanded: false,
isEditing: this.openmct.editor.isEditing()
}
},
@@ -77,6 +89,9 @@ export default {
toggleIsEditing(isEditing) {
this.isEditing = isEditing;
},
onUserSelect(event, comparator, value){
this.$emit('onUserSelect', this.filterField.key, comparator, value, event.target.checked);
},
isChecked(comparator, value) {
if (this.persistedFilters[comparator] && this.persistedFilters[comparator].includes(value)) {
return true;
@@ -87,25 +102,8 @@ export default {
persistedValue(comparator) {
return this.persistedFilters && this.persistedFilters[comparator];
},
updateFilterValue(event, comparator, value) {
if (value !== undefined) {
this.$emit('filterSelected', this.filterField.key, comparator, value, event.target.checked);
} else {
this.$emit('filterTextValueChanged', this.filterField.key, comparator, event.target.value);
}
},
getFilterLabels(filter) {
return this.persistedFilters[filter.comparator].reduce((accum, filterValue) => {
accum.push(filter.possibleValues.reduce((label, possibleValue) => {
if (filterValue === possibleValue.value) {
label = possibleValue.label;
}
return label;
}, ''));
return accum;
}, []).join(', ');
updateFilterValue(event, comparator) {
this.$emit('onTextEnter', this.filterField.key, comparator, event.target.value);
}
},
mounted() {

View File

@@ -1,12 +1,10 @@
<template>
<li class="c-tree__item-h">
<li>
<div class="c-tree__item menus-to-left"
@click="toggleExpanded">
<div class="c-filter-tree-item__filter-indicator"
:class="{'icon-filter': hasActiveFilters }"></div>
<span class="c-disclosure-triangle is-enabled flex-elem"
:class="{'c-disclosure-triangle--expanded': expanded}"></span>
<div class="c-tree__item__label c-object-label">
<div class="c-tree__item__label">
<div class="c-object-label">
<div class="c-object-label__type-icon"
:class="objectCssClass">
@@ -15,47 +13,30 @@
</div>
</div>
</div>
<div v-if="expanded">
<ul class="c-properties">
<div class="c-properties__label span-all"
v-if="!isEditing && persistedFilters.useGlobal">
Uses global filter
</div>
<div class="c-properties__label span-all"
v-if="isEditing">
<toggle-switch
:id="keyString"
@change="useGlobalFilter"
:checked="persistedFilters.useGlobal">
</toggle-switch>
Use global filter
</div>
<filter-field
v-if="(!persistedFilters.useGlobal && !isEditing) || isEditing"
v-for="metadatum in filterObject.metadataWithFilters"
:key="metadatum.key"
:filterField="metadatum"
:useGlobal="persistedFilters.useGlobal"
:persistedFilters="updatedFilters[metadatum.key]"
@filterSelected="updateFiltersWithSelectedValue"
@filterTextValueChanged="updateFiltersWithTextValue">
</filter-field>
</ul>
</div>
<ul class="grid-properties" v-if="expanded">
<filter-field
v-for="field in filterObject.valuesWithFilters"
:key="field.key"
:filterField="field"
:persistedFilters="persistedFilters[field.key]"
@onUserSelect="collectUserSelects"
@onTextEnter="updateTextFilter">
</filter-field>
</ul>
</li>
</template>
<style lang="scss">
</style>
<script>
import FilterField from './FilterField.vue';
import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue';
export default {
inject: ['openmct'],
components: {
FilterField,
ToggleSwitch
FilterField
},
props: {
filterObject: Object,
@@ -70,74 +51,44 @@ export default {
return {
expanded: false,
objectCssClass: undefined,
updatedFilters: JSON.parse(JSON.stringify(this.persistedFilters)),
isEditing: this.openmct.editor.isEditing()
}
},
watch: {
persistedFilters: {
handler: function checkFilters(newpersistedFilters) {
this.updatedFilters = JSON.parse(JSON.stringify(newpersistedFilters));
},
deep: true
}
},
computed: {
hasActiveFilters() {
// Should be true when the user has entered any filter values.
return Object.values(this.persistedFilters).some(comparator => {
return (typeof(comparator) === 'object' && !_.isEmpty(comparator));
});
updatedFilters: this.persistedFilters
}
},
methods: {
toggleExpanded() {
this.expanded = !this.expanded;
},
updateFiltersWithSelectedValue(key, comparator, valueName, value) {
collectUserSelects(key, comparator, valueName, value) {
let filterValue = this.updatedFilters[key];
if (filterValue[comparator]) {
if (value === true) {
filterValue[comparator].push(valueName);
if (filterValue && filterValue[comparator]) {
if (value === false) {
filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
} else {
if (filterValue[comparator].length === 1) {
this.$set(this.updatedFilters, key, {});
} else {
filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
}
filterValue[comparator].push(valueName);
}
} else {
this.$set(this.updatedFilters[key], comparator, [valueName]);
if (!this.updatedFilters[key]) {
this.$set(this.updatedFilters, key, {});
}
this.$set(this.updatedFilters[key], comparator, [value ? valueName : undefined]);
}
this.$emit('updateFilters', this.keyString, this.updatedFilters);
},
updateFiltersWithTextValue(key, comparator, value) {
if (value.trim() === '') {
updateTextFilter(key, comparator, value) {
if (!this.updatedFilters[key]) {
this.$set(this.updatedFilters, key, {});
} else {
this.$set(this.updatedFilters[key], comparator, value);
this.$set(this.updatedFilters[key], comparator, '');
}
this.updatedFilters[key][comparator] = value;
this.$emit('updateFilters', this.keyString, this.updatedFilters);
},
useGlobalFilter(checked) {
this.updatedFilters.useGlobal = checked;
this.$emit('updateFilters', this.keyString, this.updatedFilters, checked);
},
toggleIsEditing(isEditing) {
this.isEditing = isEditing;
},
}
},
mounted() {
let type = this.openmct.types.get(this.filterObject.domainObject.type) || {};
this.keyString = this.openmct.objects.makeKeyString(this.filterObject.domainObject.identifier);
this.objectCssClass = type.definition.cssClass;
this.openmct.editor.on('isEditing', this.toggleIsEditing);
},
beforeDestroy() {
this.openmct.editor.off('isEditing', this.toggleIsEditing);
}
}
</script>

View File

@@ -1,14 +1,6 @@
<template>
<ul class="c-tree c-filter-tree" v-if="Object.keys(children).length">
<h2>Data Filters</h2>
<div class="c-filter-indication"
v-if="hasActiveFilters">{{ label }}
</div>
<global-filters
:globalFilters="globalFilters"
:globalMetadata="globalMetadata"
@persistGlobalFilters="persistGlobalFilters">
</global-filters>
<ul class="tree c-tree c-properties__section" v-if="Object.keys(children).length">
<h2 class="c-properties__header">Filters</h2>
<filter-object
v-for="(child, key) in children"
:key="key"
@@ -20,230 +12,76 @@
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-inspector {
.c-filter-indication {
border-radius: $smallCr;
font-size: inherit;
padding: $interiorMarginSm $interiorMargin;
text-transform: inherit;
}
.c-filter-tree {
// Filters UI uses a tree-based structure
.c-properties {
// Add extra margin to account for filter-indicator
margin-left: 38px;
}
}
}
</style>
<script>
import FilterObject from './FilterObject.vue';
import GlobalFilters from './GlobalFilters.vue'
import FilterObject from './FilterObject.vue';
const FILTER_VIEW_TITLE = 'Filters applied';
const FILTER_VIEW_TITLE_MIXED = 'Mixed filters applied';
const USE_GLOBAL = 'useGlobal';
export default {
components: {
FilterObject
},
inject: [
'openmct'
],
data() {
let providedObject = this.openmct.selection.get()[0][0].context.item;
let persistedFilters = {};
export default {
components: {
FilterObject,
GlobalFilters
},
inject: [
'openmct'
],
data() {
let providedObject = this.openmct.selection.get()[0][0].context.item;
let configuration = providedObject.configuration;
if (providedObject.configuration && providedObject.configuration.filters) {
persistedFilters = providedObject.configuration.filters;
}
return {
persistedFilters: (configuration && configuration.filters) || {},
globalFilters: (configuration && configuration.globalFilters) || {},
globalMetadata: {},
providedObject,
children: {}
}
},
computed: {
hasActiveFilters() {
// Should be true when the user has entered any filter values.
return Object.values(this.persistedFilters).some(filters => {
return Object.values(filters).some(comparator => {
return (typeof(comparator) === 'object' && !_.isEmpty(comparator));
});
});
},
hasMixedFilters() {
// Should be true when filter values are mixed.
let filtersToCompare = _.omit(this.persistedFilters[Object.keys(this.persistedFilters)[0]], [USE_GLOBAL]);
return Object.values(this.persistedFilters).some(filters => {
return !_.isEqual(filtersToCompare, _.omit(filters, [USE_GLOBAL]));
});
},
label() {
if (this.hasActiveFilters) {
if (this.hasMixedFilters) {
return FILTER_VIEW_TITLE_MIXED;
} else {
return FILTER_VIEW_TITLE;
}
}
}
},
methods: {
addChildren(domainObject) {
let keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
let metadata = this.openmct.telemetry.getMetadata(domainObject);
let metadataWithFilters = metadata.valueMetadatas.filter(value => value.filters);
let hasFiltersWithKeyString = this.persistedFilters[keyString] !== undefined;
let mutateFilters = false;
let childObject = {
name: domainObject.name,
domainObject: domainObject,
metadataWithFilters
return {
providedObject,
persistedFilters,
children: {}
}
},
methods: {
addChildren(child) {
let keyString = this.openmct.objects.makeKeyString(child.identifier),
metadata = this.openmct.telemetry.getMetadata(child),
valuesWithFilters = metadata.valueMetadatas.filter((value) => value.filters),
childObject = {
name: child.name,
domainObject: child,
valuesWithFilters
};
if (metadataWithFilters.length) {
this.$set(this.children, keyString, childObject);
metadataWithFilters.forEach(metadatum => {
if (!this.globalFilters[metadatum.key]) {
this.$set(this.globalFilters, metadatum.key, {});
}
if (!this.globalMetadata[metadatum.key]) {
this.$set(this.globalMetadata, metadatum.key, metadatum);
}
if (!hasFiltersWithKeyString) {
if (!this.persistedFilters[keyString]) {
this.$set(this.persistedFilters, keyString, {});
this.$set(this.persistedFilters[keyString], 'useGlobal', true);
mutateFilters = true;
}
this.$set(this.persistedFilters[keyString], metadatum.key, this.globalFilters[metadatum.key]);
}
});
}
if (mutateFilters) {
this.mutateConfigurationFilters();
}
},
removeChildren(identifier) {
let keyString = this.openmct.objects.makeKeyString(identifier);
let globalFiltersToRemove = this.getGlobalFiltersToRemove(keyString);
if (globalFiltersToRemove.length > 0) {
globalFiltersToRemove.forEach(key => {
this.$delete(this.globalFilters, key);
this.$delete(this.globalMetadata, key);
});
this.mutateConfigurationGlobalFilters();
}
this.$delete(this.children, keyString);
this.$delete(this.persistedFilters, keyString);
this.mutateConfigurationFilters();
},
getGlobalFiltersToRemove(keyString) {
let filtersToRemove = new Set();
this.children[keyString].metadataWithFilters.forEach(metadatum => {
let keepFilter = false
Object.keys(this.children).forEach(childKeyString => {
if (childKeyString !== keyString) {
let filterMatched = this.children[childKeyString].metadataWithFilters.some(childMetadatum => childMetadatum.key === metadatum.key);
if (filterMatched) {
keepFilter = true;
return;
}
}
});
if (!keepFilter) {
filtersToRemove.add(metadatum.key);
}
});
return Array.from(filtersToRemove);
},
persistFilters(keyString, updatedFilters, useGlobalValues) {
this.persistedFilters[keyString] = updatedFilters;
if (useGlobalValues) {
Object.keys(this.persistedFilters[keyString]).forEach(key => {
if (typeof(this.persistedFilters[keyString][key]) === 'object') {
this.persistedFilters[keyString][key] = this.globalFilters[key];
}
});
}
this.mutateConfigurationFilters();
},
updatePersistedFilters(filters) {
this.persistedFilters = filters;
},
persistGlobalFilters(key, filters) {
this.globalFilters[key] = filters[key];
this.mutateConfigurationGlobalFilters();
let mutateFilters = false;
Object.keys(this.children).forEach(keyString => {
if (this.persistedFilters[keyString].useGlobal !== false && this.containsField(keyString, key)) {
if (!this.persistedFilters[keyString][key]) {
this.$set(this.persistedFilters[keyString], key, {});
}
this.$set(this.persistedFilters[keyString], key, filters[key]);
mutateFilters = true;
}
});
if (mutateFilters) {
this.mutateConfigurationFilters();
}
},
updateGlobalFilters(filters) {
this.globalFilters = filters;
},
containsField(keyString, field) {
let hasField = false;
this.children[keyString].metadataWithFilters.forEach(metadatum => {
if (metadatum.key === field) {
hasField = true;
return;
}
});
return hasField;
},
mutateConfigurationFilters() {
this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
},
mutateConfigurationGlobalFilters() {
this.openmct.objects.mutate(this.providedObject, 'configuration.globalFilters', this.globalFilters);
if (childObject.valuesWithFilters.length) {
this.$set(this.children, keyString, childObject);
} else {
return;
}
},
mounted(){
this.composition = this.openmct.composition.get(this.providedObject);
this.composition.on('add', this.addChildren);
this.composition.on('remove', this.removeChildren);
this.composition.load();
this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
this.unobserveGlobalFilters = this.openmct.objects.observe(this.providedObject, 'configuration.globalFilters', this.updateGlobalFilters);
this.unobserveAllMutation = this.openmct.objects.observe(this.providedObject, '*', (mutatedObject) => this.providedObject = mutatedObject);
removeChildren(identifier) {
let keyString = this.openmct.objects.makeKeyString(identifier);
this.$delete(this.children, keyString);
this.persistFilters(keyString);
},
beforeDestroy() {
this.composition.off('add', this.addChildren);
this.composition.off('remove', this.removeChildren);
this.unobserve();
this.unobserveGlobalFilters();
this.unobserveAllMutation();
persistFilters(keyString, userSelects) {
this.persistedFilters[keyString] = userSelects;
this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
},
updatePersistedFilters(filters) {
this.persistedFilters = filters;
}
},
mounted(){
this.composition = this.openmct.composition.get(this.providedObject);
this.composition.on('add', this.addChildren);
this.composition.on('remove', this.removeChildren);
this.composition.load();
this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
this.unobserveAllMutation = this.openmct.objects.observe(this.providedObject, '*', (mutatedObject) => this.providedObject = mutatedObject);
},
beforeDestroy() {
this.composition.off('add', this.addChildren);
this.composition.off('remove', this.removeChildren);
this.unobserve();
this.unobserveAllMutation();
}
}
</script>

View File

@@ -1,134 +0,0 @@
<template>
<li class="c-tree__item-h">
<div class="c-tree__item menus-to-left"
@click="toggleExpanded">
<div class="c-filter-tree-item__filter-indicator"
:class="{'icon-filter': hasActiveGlobalFilters }"></div>
<span class="c-disclosure-triangle is-enabled flex-elem"
:class="{'c-disclosure-triangle--expanded': expanded}"></span>
<div class="c-tree__item__label c-object-label">
<div class="c-object-label">
<div class="c-object-label__type-icon icon-gear"></div>
<div class="c-object-label__name flex-elem grows">Global Filtering</div>
</div>
</div>
</div>
<ul class="c-properties" v-if="expanded">
<filter-field
v-for="metadatum in globalMetadata"
:key="metadatum.key"
:filterField="metadatum"
:persistedFilters="updatedFilters[metadatum.key]"
@filterSelected="updateFiltersWithSelectedValue"
@filterTextValueChanged="updateFiltersWithTextValue">
</filter-field>
</ul>
</li>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-filter-indication {
// Appears as a block element beneath tables
@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;
}
}
.c-filter-tree-item {
&__filter-indicator {
color: $colorFilter;
width: 1.2em; // Set width explicitly for layout reasons: will either have class icon-filter, or none.
}
}
</style>
<script>
import FilterField from './FilterField.vue';
export default {
inject: ['openmct'],
components: {
FilterField
},
props: {
globalMetadata: Object,
globalFilters: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
expanded: false,
updatedFilters: JSON.parse(JSON.stringify(this.globalFilters))
}
},
computed: {
hasActiveGlobalFilters() {
return Object.values(this.globalFilters).some(field => {
return Object.values(field).some(comparator => {
return (comparator && (comparator !== '' || comparator.length > 0));
});
});
}
},
watch: {
globalFilters: {
handler: function checkFilters(newGlobalFilters) {
this.updatedFilters = JSON.parse(JSON.stringify(newGlobalFilters));
},
deep: true
}
},
methods: {
toggleExpanded() {
this.expanded = !this.expanded;
},
updateFiltersWithSelectedValue(key, comparator, valueName, value) {
let filterValue = this.updatedFilters[key];
if (filterValue[comparator]) {
if (value === true) {
filterValue[comparator].push(valueName);
} else {
if (filterValue[comparator].length === 1) {
this.$set(this.updatedFilters, key, {});
} else {
filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
}
}
} else {
this.$set(this.updatedFilters[key], comparator, [valueName]);
}
this.$emit('persistGlobalFilters', key, this.updatedFilters);
},
updateFiltersWithTextValue(key, comparator, value) {
if (value.trim() === '') {
this.$set(this.updatedFilters, key, {});
} else {
this.$set(this.updatedFilters[key], comparator, value);
}
this.$emit('persistGlobalFilters', key, this.updatedFilters);
}
}
}
</script>

View File

@@ -21,7 +21,7 @@
*****************************************************************************/
define([
'./FiltersInspectorViewProvider'
'./filtersInspectorViewProvider'
], function (
FiltersInspectorViewProvider
) {

View File

@@ -1,6 +1,6 @@
<template>
<div class="c-indicator c-indicator--clickable icon-session">
<span class="label c-indicator__label">
<span class="label">
<button @click="globalClearEmit">Clear All Data</button>
</span>
</div>
@@ -11,7 +11,7 @@ export default {
inject: ['openmct'],
methods: {
globalClearEmit() {
this.openmct.objectViews.emit('clearData');
this.openmct.notifications.emit('clear');
}
}
}

View File

@@ -22,16 +22,12 @@
define([
'./components/globalClearIndicator.vue',
'./clearDataAction',
'vue'
], function (
GlobaClearIndicator,
ClearDataAction,
Vue
) {
return function plugin(appliesToObjects) {
appliesToObjects = appliesToObjects || [];
return function plugin() {
return function install(openmct) {
let component = new Vue ({
provide: {
@@ -47,8 +43,6 @@ define([
};
openmct.indicators.add(indicator);
openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
};
};
});

View File

@@ -23,7 +23,6 @@
export default class GoToOriginalAction {
constructor(openmct) {
this.name = 'Go To Original';
this.key = 'goToOriginal';
this.description = 'Go to the original unlinked instance of this object';
this._openmct = openmct;

View File

@@ -115,22 +115,10 @@
width: (tickWidth + 30) + 'px'
}">
<div class="gl-plot-label gl-plot-y-label" ng-if="!yKeyOptions">
<div class="gl-plot-label gl-plot-y-label">
{{ yAxis.get('label') }}
</div>
<div class="gl-plot-label gl-plot-y-label" ng-if="yKeyOptions.length > 1 && series.length === 1">
<select class="gl-plot-y-label__select"
ng-model="yAxisLabel" ng-change="plot.toggleYAxisLabel(yAxisLabel, yKeyOptions, series[0])">
<option ng-repeat="option in yKeyOptions"
value="{{option.name}}"
ng-selected="option.name === yAxisLabel">
{{option.name}}
</option>
</select>
</div>
<mct-ticks axis="yAxis">
<div ng-repeat="tick in ticks track by tick.text"
class="gl-plot-tick gl-plot-y-tick-label"

View File

@@ -93,8 +93,6 @@ define([
this.$scope.series = this.config.series.models;
this.$scope.legend = this.config.legend;
this.$scope.yAxisLabel = this.config.yAxis.get('label');
this.cursorGuideVertical = this.$element[0].querySelector('.js-cursor-guide--v');
this.cursorGuideHorizontal = this.$element[0].querySelector('.js-cursor-guide--h');
this.cursorGuide = false;
@@ -105,35 +103,9 @@ define([
this.listenTo(this.$scope, 'plot:tickWidth', this.onTickWidthChange, this);
this.listenTo(this.$scope, 'plot:highlight:set', this.onPlotHighlightSet, this);
this.listenTo(this.$scope, 'plot:reinitializeCanvas', this.initCanvas, this);
this.listenTo(this.config.xAxis, 'change:displayRange', this.onXAxisChange, this);
this.listenTo(this.config.yAxis, 'change:displayRange', this.onYAxisChange, this);
this.setUpYAxisOptions();
};
MCTPlotController.prototype.setUpYAxisOptions = function () {
if (this.$scope.series.length === 1) {
let metadata = this.$scope.series[0].metadata;
this.$scope.yKeyOptions = metadata
.valuesForHints(['range'])
.map(function (o) {
return {
name: o.name,
key: o.key
};
});
// set yAxisLabel if none is set yet
if (this.$scope.yAxisLabel === 'none') {
let yKey = this.$scope.series[0].model.yKey,
yKeyModel = this.$scope.yKeyOptions.filter(o => o.key === yKey)[0];
this.$scope.yAxisLabel = yKeyModel.name;
}
} else {
this.$scope.yKeyOptions = undefined;
}
};
MCTPlotController.prototype.onXAxisChange = function (displayBounds) {
@@ -521,13 +493,5 @@ define([
this.cursorGuide = !this.cursorGuide;
};
MCTPlotController.prototype.toggleYAxisLabel = function (label, options, series) {
let yAxisObject = options.filter(o => o.name === label)[0];
if (yAxisObject) {
series.emit('change:yKey', yAxisObject.key);
}
};
return MCTPlotController;
});

View File

@@ -63,11 +63,8 @@ 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);
@@ -77,13 +74,16 @@ 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,
'configuration.filters',
this.updateFiltersAndResubscribe.bind(this)
);
this.refresh = this.refresh.bind(this);
this.openmct.notifications.on('clear', this.refresh);
}
eventHelpers.extend(PlotController.prototype);
@@ -170,6 +170,8 @@ define([
if (this.filterObserver) {
this.filterObserver();
}
this.openmct.notifications.off('clear', this.refresh);
};
PlotController.prototype.loadMoreData = function (range, purge) {
@@ -267,7 +269,7 @@ define([
});
};
PlotController.prototype.clearData = function () {
PlotController.prototype.refresh = function (updatedFilters) {
this.config.series.forEach(function (series) {
series.refresh();
});

View File

@@ -44,7 +44,7 @@ define([
'./filters/plugin',
'./objectMigration/plugin',
'./goToOriginalAction/plugin',
'./clearData/plugin'
'./globalClearIndicator/plugin'
], function (
_,
UTCTimeSystem,
@@ -69,7 +69,7 @@ define([
Filters,
ObjectMigration,
GoToOriginalAction,
ClearData
GlobalClearIndicator
) {
var bundleMap = {
LocalStorage: 'platform/persistence/local',
@@ -168,7 +168,7 @@ define([
plugins.Filters = Filters;
plugins.ObjectMigration = ObjectMigration.default;
plugins.GoToOriginalAction = GoToOriginalAction.default;
plugins.ClearData = ClearData;
plugins.GlobalClearIndicator = GlobalClearIndicator;
return plugins;
});

View File

@@ -23,7 +23,6 @@
export default class RemoveAction {
constructor(openmct) {
this.name = 'Remove';
this.key = 'remove';
this.description = 'Remove this object from its containing object.';
this.cssClass = "icon-trash";

View File

@@ -37,7 +37,7 @@ define([
key: 'table-configuration',
name: 'Telemetry Table Configuration',
canView: function (selection) {
if (selection.length !== 1 || selection[0].length === 0) {
if (selection.length === 0 || selection[0].length === 0) {
return false;
}
let object = selection[0][0].context.item;

View File

@@ -26,7 +26,6 @@ define([
'./collections/BoundedTableRowCollection',
'./collections/FilteredTableRowCollection',
'./TelemetryTableRow',
'./TelemetryTableColumn',
'./TelemetryTableConfiguration'
], function (
EventEmitter,
@@ -34,7 +33,6 @@ define([
BoundedTableRowCollection,
FilteredTableRowCollection,
TelemetryTableRow,
TelemetryTableColumn,
TelemetryTableConfiguration
) {
class TelemetryTable extends EventEmitter {
@@ -49,8 +47,6 @@ 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);
@@ -66,6 +62,7 @@ define([
openmct.time.on('bounds', this.refreshData);
openmct.time.on('timeSystem', this.refreshData);
openmct.notifications.on('clear', this.refreshData);
}
initialize() {
@@ -98,6 +95,8 @@ 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);
@@ -107,7 +106,7 @@ define([
}
addTelemetryObject(telemetryObject) {
this.addColumnsForObject(telemetryObject, true);
this.configuration.addColumnsForObject(telemetryObject, true);
this.requestDataFor(telemetryObject);
this.subscribeTo(telemetryObject);
this.telemetryObjects.push(telemetryObject);
@@ -146,17 +145,14 @@ define([
let keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
let columnMap = this.getColumnMapForObject(keyString);
let limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject);
this.processHistoricalData(telemetryData, columnMap, keyString, limitEvaluator);
let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
this.boundedRows.add(telemetryRows);
}).finally(() => {
this.decrementOutstandingRequests();
});
}
processHistoricalData(telemetryData, columnMap, keyString, limitEvaluator) {
let telemetryRows = telemetryData.map(datum => new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
this.boundedRows.add(telemetryRows);
}
/**
* @private
*/
@@ -196,19 +192,6 @@ 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);
@@ -220,17 +203,10 @@ define([
if (!this.telemetryObjects.includes(telemetryObject)) {
return;
}
if (!this.paused) {
this.processRealtimeDatum(datum, columnMap, keyString, limitEvaluator);
}
this.boundedRows.add(new TelemetryTableRow(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');
}
@@ -259,24 +235,13 @@ 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.off('timeSystem', this.refreshData);
this.openmct.notifications.off('clear', this.refreshData);
if (this.filterObserver) {
this.filterObserver();
}

View File

@@ -21,11 +21,10 @@
*****************************************************************************/
define(function () {
class TelemetryTableColumn {
constructor (openmct, metadatum, options = {selectable: false}) {
constructor (openmct, metadatum) {
this.metadatum = metadatum;
this.formatter = openmct.telemetry.getValueFormatter(metadatum);
this.titleValue = this.metadatum.name;
this.selectable = options.selectable;
}
getKey() {
@@ -56,7 +55,8 @@ define(function () {
return formattedValue;
}
}
}
};
return TelemetryTableColumn;
});

View File

@@ -22,8 +22,9 @@
define([
'lodash',
'EventEmitter'
], function (_, EventEmitter) {
'EventEmitter',
'./TelemetryTableColumn'
], function (_, EventEmitter, TelemetryTableColumn) {
class TelemetryTableConfiguration extends EventEmitter {
constructor(domainObject, openmct) {
@@ -33,6 +34,7 @@ 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.
@@ -46,7 +48,6 @@ 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;
@@ -64,18 +65,26 @@ define([
//Synchronize domain object reference. Duplicate object otherwise change detection becomes impossible.
this.domainObject = object;
//Was it the configuration that changed?
if (object.configuration !== undefined && !_.eq(object.configuration, this.oldConfiguration)) {
if (!_.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);
}
}
addSingleColumnForObject(telemetryObject, column, position) {
addColumnsForAllObjects(objects) {
objects.forEach(object => this.addColumnsForObject(object, false));
}
addColumnsForObject(telemetryObject) {
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
let objectKeyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
this.columns[objectKeyString] = this.columns[objectKeyString] || [];
position = position || this.columns[objectKeyString].length;
this.columns[objectKeyString].splice(position, 0, column);
this.columns[objectKeyString] = [];
metadataValues.forEach(metadatum => {
let column = new TelemetryTableColumn(this.openmct, metadatum);
this.columns[objectKeyString].push(column);
});
}
removeColumnsForObject(objectIdentifier) {

View File

@@ -29,7 +29,7 @@ define([], function () {
this.limitEvaluator = limitEvaluator;
this.objectKeyString = objectKeyString;
}
getFormattedDatum(headers) {
return Object.keys(headers).reduce((formattedDatum, columnKey) => {
formattedDatum[columnKey] = this.getFormattedValue(columnKey);
@@ -42,19 +42,12 @@ define([], function () {
return column && column.getFormattedValue(this.datum[key]);
}
getCellComponentName(key) {
let column = this.columns[key];
return column &&
column.getCellComponentName &&
column.getCellComponentName();
}
getRowClass() {
if (!this.rowClass) {
getRowLimitClass() {
if (!this.rowLimitClass) {
let limitEvaluation = this.limitEvaluator.evaluate(this.datum);
this.rowClass = limitEvaluation && limitEvaluation.cssClass;
this.rowLimitClass = limitEvaluation && limitEvaluation.cssClass;
}
return this.rowClass;
return this.rowLimitClass;
}
getCellLimitClasses() {
@@ -62,16 +55,12 @@ define([], function () {
this.cellLimitClasses = Object.values(this.columns).reduce((alarmStateMap, column) => {
let limitEvaluation = this.limitEvaluator.evaluate(this.datum, column.getMetadatum());
alarmStateMap[column.getKey()] = limitEvaluation && limitEvaluation.cssClass;
return alarmStateMap;
}, {});
}
return this.cellLimitClasses;
}
getContextMenuActions() {
return [];
}
}
/**
@@ -89,4 +78,4 @@ define([], function () {
}
return TelemetryTableRow;
});
});

View File

@@ -22,10 +22,12 @@
define([
'./components/table.vue',
'../../exporters/CSVExporter',
'./TelemetryTable',
'vue'
], function (
TableComponent,
CSVExporter,
TelemetryTable,
Vue
) {
@@ -48,7 +50,8 @@ define([
canEdit(domainObject) {
return domainObject.type === 'table';
},
view(domainObject, isEditing, objectPath) {
view(domainObject) {
let csvExporter = new CSVExporter.default();
let table = new TelemetryTable(domainObject, openmct);
let component;
return {
@@ -64,19 +67,16 @@ define([
},
provide: {
openmct,
table,
objectPath
csvExporter,
table
},
el: element,
template: '<table-component :isEditing="isEditing" :enableMarking="true"></table-component>'
template: '<table-component :isEditing="isEditing"></table-component>'
});
},
onEditModeChange(isEditing) {
component.isEditing = isEditing;
},
onClearData() {
table.refreshData();
},
destroy: function (element) {
component.$destroy();
component = undefined;

View File

@@ -43,8 +43,7 @@ define(
this.sortByTimeSystem(openmct.time.timeSystem());
this.lastBounds = openmct.time.bounds();
this.subscribeToBounds();
openmct.time.on('bounds', this.bounds);
}
addOne(item) {
@@ -141,16 +140,8 @@ define(
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();
this.openmct.time.off('bounds', this.bounds);
}
}
return BoundedTableRowCollection;

View File

@@ -1,165 +0,0 @@
<template>
<div v-if="filterNames.length > 0"
:title=title
class="c-filter-indication"
:class="{ 'c-filter-indication--mixed': hasMixedFilters }">
<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 {
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.';
const USE_GLOBAL = 'useGlobal';
export default {
inject: ['openmct', 'table'],
data() {
return {
filterNames: [],
filteredTelemetry: {}
}
},
computed: {
hasMixedFilters() {
let filtersToCompare = _.omit(this.filteredTelemetry[Object.keys(this.filteredTelemetry)[0]], [USE_GLOBAL]);
return Object.values(this.filteredTelemetry).some(filters => {
return !_.isEqual(filtersToCompare, _.omit(filters, [USE_GLOBAL]));
});
},
label() {
if (this.hasMixedFilters) {
return FILTER_INDICATOR_LABEL_MIXED;
} else {
return FILTER_INDICATOR_LABEL;
}
},
title() {
if (this.hasMixedFilters) {
return FILTER_INDICATOR_TITLE_MIXED;
} else {
return FILTER_INDICATOR_TITLE;
}
}
},
methods: {
setFilterNames() {
let names = [];
let composition = this.openmct.composition.get(this.table.configuration.domainObject);
composition && composition.load().then((domainObjects) => {
domainObjects.forEach(telemetryObject => {
let keyString= this.openmct.objects.makeKeyString(telemetryObject.identifier);
let metadataValues = this.openmct.telemetry.getMetadata(telemetryObject).values();
let filters = this.filteredTelemetry[keyString];
if (filters !== undefined) {
names.push(this.getFilterNamesFromMetadata(filters, metadataValues));
}
});
names = _.flatten(names);
this.filterNames = names.length === 0 ? names : Array.from(new Set(names));
});
},
getFilterNamesFromMetadata(filters, metadataValues) {
let filterNames = [];
filters = _.omit(filters, [USE_GLOBAL]);
Object.keys(filters).forEach(key => {
if (!_.isEmpty(filters[key])) {
metadataValues.forEach(metadatum => {
if (key === metadatum.key) {
if (typeof metadatum.filters[0] === "object") {
filterNames.push(this.getFilterLabels(filters[key], metadatum));
} else {
filterNames.push(metadatum.name);
}
}
});
}
});
return _.flatten(filterNames);
},
getFilterLabels(filterObject, metadatum, ) {
let filterLabels = [];
Object.values(filterObject).forEach(comparator => {
comparator.forEach(filterValue => {
metadatum.filters[0].possibleValues.forEach(option => {
if (option.value === filterValue) {
filterLabels.push(option.label);
}
});
});
});
return filterLabels;
},
handleConfigurationChanges(configuration) {
if (!_.eq(this.filteredTelemetry, configuration.filters)) {
this.updateFilters(configuration.filters || {});
}
},
updateFilters(filters) {
this.filteredTelemetry = JSON.parse(JSON.stringify(filters));
this.setFilterNames();
}
},
mounted() {
let filters = this.table.configuration.getConfiguration().filters || {};
this.table.configuration.on('change', this.handleConfigurationChanges);
this.updateFilters(filters);
},
destroyed() {
this.table.configuration.off('change', this.handleConfigurationChanges);
}
}
</script>

View File

@@ -1,71 +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.
*****************************************************************************/
<template>
<td @click="selectCell($event.currentTarget, columnKey)" :title="formattedValue">{{formattedValue}}</td>
</template>
<script>
export default {
inject: ['openmct'],
props: {
row: {
type: Object,
required: true
},
columnKey: {
type: String,
require: true
},
objectPath: {
type: Array,
require: false
}
},
methods: {
selectCell(element, columnKey) {
if (this.isSelectable) {
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.objectPath[0]
}
}], false);
event.stopPropagation();
}
},
},
computed: {
formattedValue() {
return this.row.getFormattedValue(this.columnKey);
},
isSelectable() {
return this.row.columns[this.columnKey].selectable;
}
}
};
</script>

View File

@@ -4,14 +4,14 @@
<div class="c-properties__header">Table Column Size</div>
<ul class="c-properties__section">
<li class="c-properties__row">
<div class="c-properties__label" title="Auto-size table"><label for="AutoSizeControl">Auto-size</label></div>
<div class="c-properties__label" title="Show or Hide Column"><label for="AutoSizeControl">Auto-size</label></div>
<div class="c-properties__value"><input type="checkbox" id="AutoSizeControl" :checked="configuration.autosize !== false" @change="toggleAutosize()"></div>
</li>
</ul>
<div class="c-properties__header">Table Column Visibility</div>
<ul class="c-properties__section">
<li class="c-properties__row" v-for="(title, key) in headers">
<div class="c-properties__label" title="Show or hide column"><label :for="key + 'ColumnControl'">{{title}}</label></div>
<div class="c-properties__label" title="Show or Hide Column"><label :for="key + 'ColumnControl'">{{title}}</label></div>
<div class="c-properties__value"><input type="checkbox" :id="key + 'ColumnControl'" :checked="configuration.hiddenColumns[key] !== true" @change="toggleColumn(key)"></div>
</li>
</ul>
@@ -23,8 +23,6 @@
</style>
<script>
import TelemetryTableColumn from '../TelemetryTableColumn';
export default {
inject: ['tableConfiguration', 'openmct'],
data() {
@@ -45,7 +43,7 @@ export default {
this.tableConfiguration.updateConfiguration(this.configuration);
},
addObject(domainObject) {
this.addColumnsForObject(domainObject, true);
this.tableConfiguration.addColumnsForObject(domainObject, true);
this.updateHeaders(this.tableConfiguration.getAllHeaders());
},
removeObject(objectIdentifier) {
@@ -58,17 +56,6 @@ 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() {
@@ -78,7 +65,7 @@ export default {
compositionCollection.load()
.then((composition) => {
this.addColumnsForAllObjects(composition);
this.tableConfiguration.addColumnsForAllObjects(composition);
this.updateHeaders(this.tableConfiguration.getAllHeaders());
compositionCollection.on('add', this.addObject);

View File

@@ -20,55 +20,26 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<tr :style="{ top: rowTop }"
class="noselect"
:class="[
rowClass,
{'is-selected': marked}
]"
v-on="listeners">
<component v-for="(title, key) in headers"
<tr :style="{ top: rowTop }" :class="rowLimitClass">
<td 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'}"
:class="[cellLimitClasses[key], selectableColumns[key] ? 'is-selectable' : '']"
:objectPath="objectPath"
:row="row">
</component>
:title="formattedRow[key]"
:class="cellLimitClasses[key]">{{formattedRow[key]}}</td>
</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 {
inject: ['openmct', 'objectPath'],
data: function () {
return {
rowTop: (this.rowOffset + this.rowIndex) * this.rowHeight + 'px',
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;
}, {})
formattedRow: this.row.getFormattedDatum(this.headers),
rowLimitClass: this.row.getRowLimitClass(),
cellLimitClasses: this.row.getCellLimitClasses()
}
},
props: {
@@ -84,10 +55,6 @@ export default {
type: Object,
required: true
},
objectPath: {
type: Array,
required: false
},
rowIndex: {
type: Number,
required: false,
@@ -102,11 +69,6 @@ export default {
type: Number,
required: false,
default: 0
},
marked: {
type: Boolean,
required: false,
default: false
}
},
methods: {
@@ -114,54 +76,9 @@ export default {
this.rowTop = (rowOffset + this.rowIndex) * this.rowHeight + 'px';
},
formatRow: function (row) {
this.rowClass = row.getRowClass();
this.formattedRow = row.getFormattedDatum(this.headers);
this.rowLimitClass = row.getRowLimitClass();
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();
}
},
showContextMenu: function (event) {
event.preventDefault();
this.openmct.objects.get(this.row.objectKeyString).then((domainObject) => {
let contextualObjectPath = this.objectPath.slice();
contextualObjectPath.unshift(domainObject);
this.openmct.contextMenu._showContextMenuForObjectPath(contextualObjectPath, event.x, event.y, this.row.getContextMenuActions());
});
}
},
// TODO: use computed properties
@@ -171,22 +88,6 @@ export default {
handler: 'formatRow',
deep: false
}
},
components: {
TableCell
},
computed: {
listeners() {
let listenersObject = {
click: this.markRow
}
if (this.row.getContextMenuActions().length) {
listenersObject.contextmenu = this.showContextMenu;
}
return listenersObject;
}
}
}
</script>

View File

@@ -20,135 +20,92 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="c-table-wrapper">
<div class="c-table-control-bar c-control-bar">
<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">
<button class="c-button icon-download labeled"
v-if="allowExport"
v-on:click="exportAllDataAsCSV()"
title="Export This View's Data">
<span class="c-button__label">Export Table Data</span>
v-on:click="exportAsCSV()"
title="Export This View's Data">
<span class="c-button__label">Export As CSV</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 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"
:objectPath="objectPath"
: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>
<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>
</table>
<telemetry-filter-indicator></telemetry-filter-indicator>
</div>
</div><!-- closes c-table-wrapper -->
<!-- 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">
</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>
</template>
<style lang="scss">
@@ -174,7 +131,7 @@
display: block;
flex: 1 0 auto;
width: 100px;
vertical-align: middle; // This is crucial to hiding 4px height injected by browser by default
vertical-align: middle; // This is crucial to hiding f**king 4px height injected by browser by default
}
td {
@@ -259,10 +216,6 @@
align-items: stretch;
position: absolute;
height: 18px; // Needed when a row has empty values in its cells
&.is-selected {
background-color: $colorSelectedBg;
}
}
td {
@@ -313,10 +266,6 @@
}
}
.paused {
border: 1px solid #ff9900;
}
/******************************* LEGACY */
.s-status-taking-snapshot,
.overlay.snapshot {
@@ -330,8 +279,6 @@
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;
@@ -346,30 +293,13 @@ export default {
components: {
TelemetryTableRow,
TableColumnHeader,
search,
TelemetryFilterIndicator
search
},
inject: ['table', 'openmct', 'objectPath'],
inject: ['table', 'openmct', 'csvExporter'],
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() {
@@ -398,10 +328,7 @@ export default {
dropOffsetLeft: undefined,
isDropTargetActive: false,
isAutosizeEnabled: configuration.autosize,
scrollW: 0,
markCounter: 0,
paused: false,
markedRows: []
scrollW: 0
}
},
computed: {
@@ -587,27 +514,15 @@ export default {
// which causes subsequent scroll to use an out of date height.
this.contentTable.style.height = this.totalHeight + 'px';
},
exportAsCSV(data) {
exportAsCSV() {
const headerKeys = Object.keys(this.headers);
this.csvExporter.export(data, {
const justTheData = this.table.filteredRows.getRows()
.map(row => row.getFormattedDatum(this.headers));
this.csvExporter.export(justTheData, {
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;
},
@@ -696,114 +611,12 @@ export default {
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);
@@ -811,7 +624,6 @@ export default {
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);
@@ -837,7 +649,6 @@ 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);

View File

@@ -0,0 +1,6 @@
<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>

View File

@@ -167,7 +167,6 @@ export default {
this.xAxis.scale(this.xScale);
this.xAxis.tickFormat(utcMultiTimeFormat);
this.axisElement.call(this.xAxis);
this.setScale();
},
getActiveFormatter() {
let timeSystem = this.openmct.time.timeSystem();

View File

@@ -60,6 +60,7 @@ export default {
.filter(menuOption => menuOption.clock === (clock && clock.key))
.map(menuOption => JSON.parse(JSON.stringify(this.openmct.time.timeSystems.get(menuOption.timeSystem))));
},
setTimeSystemFromView(timeSystem) {
if (timeSystem.key !== this.selectedTimeSystem.key) {
let activeClock = this.openmct.time.clock();
@@ -68,15 +69,7 @@ export default {
timeSystem: timeSystem.key
});
if (activeClock === undefined) {
let bounds;
if (this.selectedTimeSystem.isUTCBased && timeSystem.isUTCBased) {
bounds = this.openmct.time.bounds();
} else {
bounds = configuration.bounds;
}
this.openmct.time.timeSystem(timeSystem.key, bounds);
this.openmct.time.timeSystem(timeSystem.key, configuration.bounds);
} else {
this.openmct.time.timeSystem(timeSystem.key);
this.openmct.time.clockOffsets(configuration.clockOffsets);

View File

@@ -70,6 +70,9 @@ $colorBodyFgEm: #fff;
$colorGenBg: #222;
$colorHeadBg: #262626;
$colorHeadFg: $colorBodyFg;
$colorStatusBarBg: $colorHeadBg;
$colorStatusBarFg: $colorBodyFg;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #26d8ff;
@@ -98,12 +101,10 @@ $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: #ff0000;
$colorWarningHiFg: #ffdad0;
$colorWarningHi: #990000;
$colorWarningHiFg: #FF9594;
$colorWarningLo: #ff9900;
$colorWarningLoFg: #523400;
$colorDiagnostic: #a4b442;
@@ -114,9 +115,6 @@ $colorInfo: #2294a2;
$colorInfoFg: #fff;
$colorOk: #33cc33;
$colorOkFg: #fff;
$colorFilterBg: #44449c;
$colorFilterFg: #8984e9;
$colorFilter: $colorFilterFg; // Standalone against $colorBodyBg
// States
$colorPausedBg: #ff9900;
@@ -212,10 +210,6 @@ $btnStdH: 24px;
$colorCursorGuide: rgba(white, 0.6);
$shdwCursorGuide: rgba(black, 0.4) 0 0 2px;
$colorLocalControlOvrBg: rgba($colorBodyBg, 0.8);
$colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due to usage of SVG bg in selects
$colorSelectFg: $colorBtnFg;
$colorSelectArw: lighten($colorBtnBg, 20%);
$shdwSelect: rgba(black, 0.5) 0 0.5px 3px;
// Menus
$colorMenuBg: pullForward($colorBodyBg, 15%);
@@ -283,11 +277,6 @@ $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%);
@@ -430,3 +419,7 @@ $createBtnTextTransform: uppercase;
background: linear-gradient(pullForward($c, 5%), $c);
box-shadow: rgba(black, 0.5) 0 0.5px 2px;
}
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect(linear-gradient(lighten($bg, 5%), $bg), $fg, lighten($bg, 20%), rgba(black, 0.5) 0 0.5px 3px);
}

View File

@@ -74,6 +74,9 @@ $colorBodyFgEm: #fff;
$colorGenBg: #222;
$colorHeadBg: #262626;
$colorHeadFg: $colorBodyFg;
$colorStatusBarBg: $colorHeadBg;
$colorStatusBarFg: $colorBodyFg;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #26d8ff;
@@ -102,12 +105,10 @@ $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: #ff0000;
$colorWarningHiFg: #ffdad0;
$colorWarningHi: #990000;
$colorWarningHiFg: #FF9594;
$colorWarningLo: #ff9900;
$colorWarningLoFg: #523400;
$colorDiagnostic: #a4b442;
@@ -118,9 +119,6 @@ $colorInfo: #2294a2;
$colorInfoFg: #fff;
$colorOk: #33cc33;
$colorOkFg: #fff;
$colorFilterBg: #44449c;
$colorFilterFg: #8984e9;
$colorFilter: $colorFilterFg; // Standalone against $colorBodyBg
// States
$colorPausedBg: #ff9900;
@@ -216,10 +214,6 @@ $btnStdH: 24px;
$colorCursorGuide: rgba(white, 0.6);
$shdwCursorGuide: rgba(black, 0.4) 0 0 2px;
$colorLocalControlOvrBg: rgba($colorBodyBg, 0.8);
$colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due to usage of SVG bg in selects
$colorSelectFg: $colorBtnFg;
$colorSelectArw: lighten($colorBtnBg, 20%);
$shdwSelect: rgba(black, 0.5) 0 0.5px 3px;
// Menus
$colorMenuBg: pullForward($colorBodyBg, 15%);
@@ -287,11 +281,6 @@ $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%);
@@ -435,6 +424,10 @@ $createBtnTextTransform: uppercase;
box-shadow: rgba(black, 0.5) 0 0.5px 2px;
}
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect(linear-gradient(lighten($bg, 5%), $bg), $fg, lighten($bg, 20%), rgba(black, 0.5) 0 0.5px 3px);
}
/**************************************************** OVERRIDES */
.c-frame {
&:not(.no-frame) {

View File

@@ -70,6 +70,9 @@ $colorBodyFgEm: #333;
$colorGenBg: #fff;
$colorHeadBg: #eee;
$colorHeadFg: $colorBodyFg;
$colorStatusBarBg: #000;
$colorStatusBarFg: #999;
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #00c0f6;
@@ -98,8 +101,6 @@ $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;
@@ -114,9 +115,6 @@ $colorInfo: #2294a2;
$colorInfoFg: #fff;
$colorOk: #33cc33;
$colorOkFg: #fff;
$colorFilterBg: #a29fe2;
$colorFilterFg: #fff;
$colorFilter: $colorFilterBg; // Standalone against $colorBodyBg
// States
$colorPausedBg: #ff9900;
@@ -212,10 +210,6 @@ $btnStdH: 24px;
$colorCursorGuide: rgba(black, 0.6);
$shdwCursorGuide: rgba(white, 0.4) 0 0 2px;
$colorLocalControlOvrBg: rgba($colorBodyFg, 0.8);
$colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due to usage of SVG bg in selects
$colorSelectFg: $colorBtnFg;
$colorSelectArw: lighten($colorBtnBg, 20%);
$shdwSelect: none;
// Menus
$colorMenuBg: pushBack($colorBodyBg, 10%);
@@ -283,11 +277,6 @@ $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%);
@@ -429,3 +418,7 @@ $createBtnTextTransform: uppercase;
@mixin themedButton($c: $colorBtnBg) {
background: $c;
}
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect($bg, $fg, lighten($bg, 20%), none);
}

View File

@@ -93,7 +93,7 @@ $mobileMenuIconD: 24px; // Used
$mobileTreeItemH: 35px; // Used
/************************** VISUAL */
$controlDisabledOpacity: 0.5;
$controlDisabledOpacity: 0.3;
/************************** UI ELEMENTS */
/*************** Progress Bar */
@@ -141,8 +141,6 @@ $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';

View File

@@ -75,17 +75,11 @@ button {
}
}
/********* Icon Buttons and Links */
/********* Icon Buttons */
.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();
@@ -279,10 +273,7 @@ input[type=number]::-webkit-outer-spin-button {
// SELECTS
select {
@include appearanceNone();
background-color: $colorSelectBg;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3e%3cpath fill='%23#{svgColorFromHex($colorSelectArw)}' d='M5 5l5-5H0z'/%3e%3c/svg%3e");
color: $colorSelectFg;
box-shadow: $shdwSelect;
@include themedSelect();
background-repeat: no-repeat, no-repeat;
background-position: right .4em top 80%, 0 0;
border: none;
@@ -603,15 +594,15 @@ select {
margin-right: $m;
}
.c-separator {
@include cToolbarSeparator();
}
.c-toolbar {
> * + * {
margin-left: 2px;
}
&__button {
}
&__separator {
@include cToolbarSeparator();
}

View File

@@ -202,11 +202,6 @@ body.desktop .has-local-controls {
}
}
::placeholder {
opacity: 0.5;
font-style: italic;
}
/******************************************************** STATES */
@mixin spinner($b: 5px, $c: $colorKey) {
animation-name: rotation-centered;

View File

@@ -30,10 +30,10 @@
}
@font-face {
// Use https://icomoon.io/app with icomoon-project-Open-MCT-Symbols-12px.json to generate font files
// Use https://icomoon.io/app with icomoon-project-openmct-symbols-12px.json to generate font files
font-family: 'symbolsfont-12px';
src: url('./fonts/Open-MCT-Symbols-12px.woff') format('woff'),
url('./fonts/Open-MCT-Symbols-12px.ttf') format('truetype');
src: url('./fonts/openmct-symbols-12px.woff') format('woff'),
url('./fonts/openmct-symbols-12px.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@@ -77,8 +77,6 @@
.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); }
@@ -166,8 +164,6 @@
/************************** 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'); }

View File

@@ -161,7 +161,8 @@ mct-plot {
height: auto;
}
&.gl-plot-y-label {
&.gl-plot-y-label,
&.l-plot-y-label {
$x: -50%;
$r: -90deg;
transform-origin: 50% 0;
@@ -171,12 +172,6 @@ mct-plot {
left: 0;
top: 50%;
white-space: nowrap;
select {
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3e%3cpath fill='%23#{svgColorFromHex($colorSelectArw)}' d='M0 5l5 5V0L0 5z'/%3e%3c/svg%3e");
background-position: left .4em top 50%, 0 0;
padding: 1px $interiorMargin 1px 20px;
}
}
}

View File

@@ -782,6 +782,133 @@ mct-indicators mct-include {
display: contents;
}
/*
// MOVED TO INDICATORS.VUE
.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;
top: 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;
bottom: 100%;
@include triangle('up', $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;
}
}
// 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;

View File

@@ -585,11 +585,6 @@
}
}
@function svgColorFromHex($hexColor) {
// Remove initial # in color value
@return str-slice(inspect($hexColor), 2, str-length(inspect($hexColor)));
}
@mixin test($c: deeppink, $a: 0.3) {
background: rgba($c, $a) !important;
background-color: rgba($c, $a) !important;

View File

@@ -61,7 +61,7 @@
}
@mixin indicatorStatusColors($c) {
&:before, .c-indicator__count {
&:before, .count {
color: $c;
}
}
@@ -159,16 +159,3 @@ 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;
}
}

View File

@@ -76,43 +76,23 @@ 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;

View File

@@ -1,8 +1,8 @@
{
"metadata": {
"name": "Open MCT Symbols 16px",
"name": "Open MCT Symbols",
"lastOpened": 0,
"created": 1561482854927
"created": 1541830438012
},
"iconSets": [
{
@@ -317,29 +317,13 @@
"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,
@@ -347,7 +331,7 @@
"name": "icon-arrows-up-down",
"prevSize": 32,
"code": 59905,
"tempChar": ""
"tempChar": ""
},
{
"order": 68,
@@ -355,7 +339,7 @@
"name": "icon-bullet",
"prevSize": 32,
"code": 59906,
"tempChar": ""
"tempChar": ""
},
{
"order": 150,
@@ -363,7 +347,7 @@
"prevSize": 32,
"code": 59907,
"name": "icon-calendar",
"tempChar": ""
"tempChar": ""
},
{
"order": 45,
@@ -371,7 +355,7 @@
"name": "icon-chain-links",
"prevSize": 32,
"code": 59908,
"tempChar": ""
"tempChar": ""
},
{
"order": 73,
@@ -379,7 +363,7 @@
"name": "icon-download",
"prevSize": 32,
"code": 59909,
"tempChar": ""
"tempChar": ""
},
{
"order": 39,
@@ -387,7 +371,7 @@
"name": "icon-duplicate",
"prevSize": 32,
"code": 59910,
"tempChar": ""
"tempChar": ""
},
{
"order": 50,
@@ -395,7 +379,7 @@
"name": "icon-folder-new",
"prevSize": 32,
"code": 59911,
"tempChar": ""
"tempChar": ""
},
{
"order": 138,
@@ -403,7 +387,7 @@
"name": "icon-fullscreen-collapse",
"prevSize": 32,
"code": 59912,
"tempChar": ""
"tempChar": ""
},
{
"order": 139,
@@ -411,7 +395,7 @@
"name": "icon-fullscreen-expand",
"prevSize": 32,
"code": 59913,
"tempChar": ""
"tempChar": ""
},
{
"order": 122,
@@ -419,7 +403,7 @@
"name": "icon-layers",
"prevSize": 32,
"code": 59914,
"tempChar": ""
"tempChar": ""
},
{
"order": 151,
@@ -427,7 +411,7 @@
"name": "icon-line-horz",
"prevSize": 32,
"code": 59915,
"tempChar": ""
"tempChar": ""
},
{
"order": 100,
@@ -435,7 +419,7 @@
"name": "icon-magnify",
"prevSize": 32,
"code": 59916,
"tempChar": ""
"tempChar": ""
},
{
"order": 99,
@@ -443,7 +427,7 @@
"name": "icon-magnify-in",
"prevSize": 32,
"code": 59917,
"tempChar": ""
"tempChar": ""
},
{
"order": 101,
@@ -451,7 +435,7 @@
"name": "icon-magnify-out-v2",
"prevSize": 32,
"code": 59918,
"tempChar": ""
"tempChar": ""
},
{
"order": 103,
@@ -459,7 +443,7 @@
"name": "icon-menu",
"prevSize": 32,
"code": 59919,
"tempChar": ""
"tempChar": ""
},
{
"order": 124,
@@ -467,7 +451,7 @@
"name": "icon-move",
"prevSize": 32,
"code": 59920,
"tempChar": ""
"tempChar": ""
},
{
"order": 7,
@@ -475,7 +459,7 @@
"name": "icon-new-window",
"prevSize": 32,
"code": 59921,
"tempChar": ""
"tempChar": ""
},
{
"order": 63,
@@ -483,7 +467,7 @@
"name": "icon-paint-bucket-v2",
"prevSize": 32,
"code": 59922,
"tempChar": ""
"tempChar": ""
},
{
"order": 15,
@@ -491,7 +475,7 @@
"name": "icon-pencil",
"prevSize": 32,
"code": 59923,
"tempChar": ""
"tempChar": ""
},
{
"order": 54,
@@ -499,7 +483,7 @@
"name": "icon-pencil-edit-in-place",
"prevSize": 32,
"code": 59924,
"tempChar": ""
"tempChar": ""
},
{
"order": 40,
@@ -507,7 +491,7 @@
"name": "icon-play",
"prevSize": 32,
"code": 59925,
"tempChar": ""
"tempChar": ""
},
{
"order": 125,
@@ -515,7 +499,7 @@
"name": "icon-pause",
"prevSize": 32,
"code": 59926,
"tempChar": ""
"tempChar": ""
},
{
"order": 119,
@@ -523,7 +507,7 @@
"name": "icon-plot-resource",
"prevSize": 32,
"code": 59927,
"tempChar": ""
"tempChar": ""
},
{
"order": 48,
@@ -531,7 +515,7 @@
"name": "icon-pointer-left",
"prevSize": 32,
"code": 59928,
"tempChar": ""
"tempChar": ""
},
{
"order": 47,
@@ -539,7 +523,7 @@
"name": "icon-pointer-right",
"prevSize": 32,
"code": 59929,
"tempChar": ""
"tempChar": ""
},
{
"order": 85,
@@ -547,7 +531,7 @@
"name": "icon-refresh",
"prevSize": 32,
"code": 59930,
"tempChar": ""
"tempChar": ""
},
{
"order": 55,
@@ -555,7 +539,7 @@
"name": "icon-save",
"prevSize": 32,
"code": 59931,
"tempChar": ""
"tempChar": ""
},
{
"order": 56,
@@ -563,7 +547,7 @@
"name": "icon-save-as",
"prevSize": 32,
"code": 59932,
"tempChar": ""
"tempChar": ""
},
{
"order": 58,
@@ -571,7 +555,7 @@
"name": "icon-sine",
"prevSize": 32,
"code": 59933,
"tempChar": ""
"tempChar": ""
},
{
"order": 113,
@@ -579,7 +563,7 @@
"name": "icon-font",
"prevSize": 32,
"code": 59934,
"tempChar": ""
"tempChar": ""
},
{
"order": 41,
@@ -587,7 +571,7 @@
"name": "icon-thumbs-strip",
"prevSize": 32,
"code": 59935,
"tempChar": ""
"tempChar": ""
},
{
"order": 146,
@@ -595,7 +579,7 @@
"name": "icon-two-parts-both",
"prevSize": 32,
"code": 59936,
"tempChar": ""
"tempChar": ""
},
{
"order": 145,
@@ -603,7 +587,7 @@
"name": "icon-two-parts-one-only",
"prevSize": 32,
"code": 59937,
"tempChar": ""
"tempChar": ""
},
{
"order": 82,
@@ -611,7 +595,7 @@
"name": "icon-resync",
"prevSize": 32,
"code": 59938,
"tempChar": ""
"tempChar": ""
},
{
"order": 86,
@@ -619,7 +603,7 @@
"name": "icon-reset",
"prevSize": 32,
"code": 59939,
"tempChar": ""
"tempChar": ""
},
{
"order": 61,
@@ -627,7 +611,7 @@
"name": "icon-x-in-circle",
"prevSize": 32,
"code": 59940,
"tempChar": ""
"tempChar": ""
},
{
"order": 84,
@@ -635,7 +619,7 @@
"name": "icon-brightness",
"prevSize": 32,
"code": 59941,
"tempChar": ""
"tempChar": ""
},
{
"order": 83,
@@ -643,7 +627,7 @@
"name": "icon-contrast",
"prevSize": 32,
"code": 59942,
"tempChar": ""
"tempChar": ""
},
{
"order": 87,
@@ -651,7 +635,7 @@
"name": "icon-expand",
"prevSize": 32,
"code": 59943,
"tempChar": ""
"tempChar": ""
},
{
"order": 89,
@@ -659,7 +643,7 @@
"name": "icon-list-view",
"prevSize": 32,
"code": 59944,
"tempChar": ""
"tempChar": ""
},
{
"order": 133,
@@ -667,7 +651,7 @@
"name": "icon-grid-snap-to",
"prevSize": 32,
"code": 59945,
"tempChar": ""
"tempChar": ""
},
{
"order": 132,
@@ -675,7 +659,7 @@
"name": "icon-grid-snap-no",
"prevSize": 32,
"code": 59946,
"tempChar": ""
"tempChar": ""
},
{
"order": 94,
@@ -683,7 +667,7 @@
"name": "icon-frame-show",
"prevSize": 32,
"code": 59947,
"tempChar": ""
"tempChar": ""
},
{
"order": 95,
@@ -691,7 +675,7 @@
"name": "icon-frame-hide",
"prevSize": 32,
"code": 59948,
"tempChar": ""
"tempChar": ""
},
{
"order": 97,
@@ -699,7 +683,7 @@
"name": "icon-import",
"prevSize": 32,
"code": 59949,
"tempChar": ""
"tempChar": ""
},
{
"order": 96,
@@ -707,7 +691,7 @@
"name": "icon-export",
"prevSize": 32,
"code": 59950,
"tempChar": ""
"tempChar": ""
},
{
"order": 114,
@@ -715,7 +699,7 @@
"name": "icon-font-size",
"prevSize": 32,
"code": 59951,
"tempChar": ""
"tempChar": ""
},
{
"order": 144,
@@ -723,7 +707,7 @@
"name": "icon-activity",
"prevSize": 32,
"code": 60160,
"tempChar": ""
"tempChar": ""
},
{
"order": 104,
@@ -731,7 +715,7 @@
"name": "icon-activity-mode",
"prevSize": 32,
"code": 60161,
"tempChar": ""
"tempChar": ""
},
{
"order": 137,
@@ -739,7 +723,7 @@
"name": "icon-autoflow-tabular",
"prevSize": 32,
"code": 60162,
"tempChar": ""
"tempChar": ""
},
{
"order": 115,
@@ -747,7 +731,7 @@
"name": "icon-clock",
"prevSize": 32,
"code": 60163,
"tempChar": ""
"tempChar": ""
},
{
"order": 2,
@@ -755,7 +739,7 @@
"name": "icon-database",
"prevSize": 32,
"code": 60164,
"tempChar": ""
"tempChar": ""
},
{
"order": 3,
@@ -763,7 +747,7 @@
"name": "icon-database-query",
"prevSize": 32,
"code": 60165,
"tempChar": ""
"tempChar": ""
},
{
"order": 67,
@@ -771,7 +755,7 @@
"name": "icon-dataset",
"prevSize": 32,
"code": 60166,
"tempChar": ""
"tempChar": ""
},
{
"order": 59,
@@ -779,7 +763,7 @@
"name": "icon-datatable",
"prevSize": 32,
"code": 60167,
"tempChar": ""
"tempChar": ""
},
{
"order": 136,
@@ -787,7 +771,7 @@
"name": "icon-dictionary",
"prevSize": 32,
"code": 60168,
"tempChar": ""
"tempChar": ""
},
{
"order": 51,
@@ -795,7 +779,7 @@
"name": "icon-folder",
"prevSize": 32,
"code": 60169,
"tempChar": ""
"tempChar": ""
},
{
"order": 147,
@@ -803,7 +787,7 @@
"name": "icon-image",
"prevSize": 32,
"code": 60170,
"tempChar": ""
"tempChar": ""
},
{
"order": 4,
@@ -811,7 +795,7 @@
"name": "icon-layout",
"prevSize": 32,
"code": 60171,
"tempChar": ""
"tempChar": ""
},
{
"order": 24,
@@ -819,7 +803,7 @@
"name": "icon-object",
"prevSize": 32,
"code": 60172,
"tempChar": ""
"tempChar": ""
},
{
"order": 52,
@@ -827,7 +811,7 @@
"name": "icon-object-unknown",
"prevSize": 32,
"code": 60173,
"tempChar": ""
"tempChar": ""
},
{
"order": 105,
@@ -835,7 +819,7 @@
"name": "icon-packet",
"prevSize": 32,
"code": 60174,
"tempChar": ""
"tempChar": ""
},
{
"order": 126,
@@ -843,7 +827,7 @@
"name": "icon-page",
"prevSize": 32,
"code": 60175,
"tempChar": ""
"tempChar": ""
},
{
"order": 130,
@@ -851,7 +835,7 @@
"name": "icon-plot-overlay",
"prevSize": 32,
"code": 60176,
"tempChar": ""
"tempChar": ""
},
{
"order": 80,
@@ -859,7 +843,7 @@
"name": "icon-plot-stacked",
"prevSize": 32,
"code": 60177,
"tempChar": ""
"tempChar": ""
},
{
"order": 134,
@@ -867,7 +851,7 @@
"name": "icon-session",
"prevSize": 32,
"code": 60178,
"tempChar": ""
"tempChar": ""
},
{
"order": 109,
@@ -875,7 +859,7 @@
"name": "icon-tabular",
"prevSize": 32,
"code": 60179,
"tempChar": ""
"tempChar": ""
},
{
"order": 107,
@@ -883,7 +867,7 @@
"name": "icon-tabular-lad",
"prevSize": 32,
"code": 60180,
"tempChar": ""
"tempChar": ""
},
{
"order": 106,
@@ -891,7 +875,7 @@
"name": "icon-tabular-lad-set",
"prevSize": 32,
"code": 60181,
"tempChar": ""
"tempChar": ""
},
{
"order": 70,
@@ -899,7 +883,7 @@
"name": "icon-tabular-realtime",
"prevSize": 32,
"code": 60182,
"tempChar": ""
"tempChar": ""
},
{
"order": 60,
@@ -907,7 +891,7 @@
"name": "icon-tabular-scrolling",
"prevSize": 32,
"code": 60183,
"tempChar": ""
"tempChar": ""
},
{
"order": 131,
@@ -915,7 +899,7 @@
"name": "icon-telemetry",
"prevSize": 32,
"code": 60184,
"tempChar": ""
"tempChar": ""
},
{
"order": 108,
@@ -923,7 +907,7 @@
"name": "icon-timeline",
"prevSize": 32,
"code": 60185,
"tempChar": ""
"tempChar": ""
},
{
"order": 81,
@@ -931,7 +915,7 @@
"name": "icon-timer",
"prevSize": 32,
"code": 60186,
"tempChar": ""
"tempChar": ""
},
{
"order": 69,
@@ -939,7 +923,7 @@
"name": "icon-topic",
"prevSize": 32,
"code": 60187,
"tempChar": ""
"tempChar": ""
},
{
"order": 79,
@@ -947,7 +931,7 @@
"name": "icon-box-with-dashed-lines-v2",
"prevSize": 32,
"code": 60188,
"tempChar": ""
"tempChar": ""
},
{
"order": 90,
@@ -955,7 +939,7 @@
"name": "icon-summary-widget",
"prevSize": 32,
"code": 60189,
"tempChar": ""
"tempChar": ""
},
{
"order": 92,
@@ -963,7 +947,7 @@
"name": "icon-notebook",
"prevSize": 32,
"code": 60190,
"tempChar": ""
"tempChar": ""
},
{
"order": 118,
@@ -971,7 +955,7 @@
"name": "icon-tabs-view",
"prevSize": 32,
"code": 60191,
"tempChar": ""
"tempChar": ""
},
{
"order": 117,
@@ -979,7 +963,7 @@
"name": "icon-flexible-layout",
"prevSize": 32,
"code": 60192,
"tempChar": ""
"tempChar": ""
},
{
"order": 152,
@@ -987,7 +971,7 @@
"name": "icon-generator-sine",
"prevSize": 32,
"code": 60193,
"tempChar": ""
"tempChar": ""
},
{
"order": 153,
@@ -995,7 +979,7 @@
"name": "icon-generator-event",
"prevSize": 32,
"code": 60194,
"tempChar": ""
"tempChar": ""
},
{
"order": 160,
@@ -1003,7 +987,7 @@
"name": "icon-gauge",
"prevSize": 32,
"code": 60195,
"tempChar": ""
"tempChar": ""
}
],
"id": 0,
@@ -1618,46 +1602,6 @@
]
}
},
{
"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-16px.ttf Normal file → Executable file

Binary file not shown.

BIN
src/styles-new/fonts/Open-MCT-Symbols-16px.woff Normal file → Executable file

Binary file not shown.

View File

@@ -1,35 +1,19 @@
{
"metadata": {
"name": "Open MCT Symbols 12px",
"name": "openmct-symbols-12px",
"lastOpened": 0,
"created": 1561483556329
"created": 1527031065005
},
"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,
@@ -37,7 +21,7 @@
"name": "icon12-grippy",
"prevSize": 12,
"code": 59697,
"tempChar": ""
"tempChar": ""
},
{
"order": 10,
@@ -45,7 +29,7 @@
"name": "icon12-list-view",
"prevSize": 12,
"code": 921666,
"tempChar": ""
"tempChar": ""
},
{
"order": 6,
@@ -53,14 +37,14 @@
"prevSize": 12,
"code": 921865,
"name": "icon12-folder",
"tempChar": ""
"tempChar": ""
}
],
"id": 0,
"metadata": {
"name": "Open MCT Symbols 12px",
"name": "openmct-symbols-12px",
"importSize": {
"width": 384,
"width": 279,
"height": 384
},
"designer": "Charles Hacskaylo"
@@ -68,28 +52,6 @@
"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": [
@@ -98,11 +60,26 @@
"M597.333 768h-170.667v256h170.667v-256z",
"M256 426.667h-256v170.667h256v-170.667z"
],
"attrs": [],
"attrs": [
{},
{},
{},
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 0,
"tags": [
"icon12-crosshair"
]
],
"colorPermutations": {
"1161751": [
{},
{},
{},
{}
]
}
},
{
"id": 8,
@@ -118,12 +95,39 @@
"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,
@@ -132,11 +136,24 @@
"M0 426.667h1024v170.667h-1024v-170.667z",
"M0 853.333h1024v170.667h-1024v-170.667z"
],
"attrs": [],
"attrs": [
{},
{},
{}
],
"isMulticolor": false,
"isMulticolor2": false,
"grid": 0,
"tags": [
"icon12-list-view"
]
],
"colorPermutations": {
"1161751": [
{},
{},
{}
]
}
},
{
"id": 3,
@@ -145,14 +162,40 @@
"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": [],
"colorThemes": [
[
[
0,
0,
0,
1
],
[
0,
161,
75,
1
]
]
],
"colorThemeIdx": 0
}
],
@@ -163,9 +206,9 @@
"showQuickUse2": true,
"showSVGs": true,
"fontPref": {
"prefix": "openmct-symbols-",
"prefix": "icon-",
"metadata": {
"fontFamily": "Open-MCT-Symbols-12px",
"fontFamily": "openmct-symbols-12px",
"majorVersion": 1,
"minorVersion": 0
},
@@ -174,12 +217,7 @@
"baseline": 6.25,
"whitespace": 50
},
"embed": false,
"noie8": true,
"ie7": false,
"showMetadata": false,
"includeMetadata": false,
"showMetrics": true
"embed": false
},
"imagePref": {
"prefix": "icon-",

Binary file not shown.

Binary file not shown.

View File

@@ -25,8 +25,8 @@
// Do not include anything that renders to CSS!
@import "constants";
@import "constants-mobile.scss";
//@import "constants-espresso"; // TEMP
@import "constants-snow"; // TEMP
@import "constants-espresso"; // TEMP
//@import "constants-snow"; // TEMP
//@import "constants-maelstrom";
@import "mixins";
@import "animations";

View File

@@ -0,0 +1,22 @@
<template>
<div class="c-indicator no-collapse icon-clock c-current-datetime">
<span class="label">{{ currentDateTime }} UTC</span>
</div>
</template>
<script>
import moment from 'moment';
export default {
data() {
return {
currentDateTime: moment.utc().format('LTS')
}
},
mounted: function() {
setInterval(()=>{
this.currentDateTime = moment.utc().format('YYYY/MM/DD HH:mm:ss')
},100)
}
}
</script>

View File

@@ -44,8 +44,7 @@
class="c-so-view__object-view"
ref="objectView"
:object="domainObject"
:show-edit-view="showEditView"
:object-path="objectPath">
:show-edit-view="showEditView">
</object-view>
</div>
</template>
@@ -124,12 +123,7 @@
.c-click-icon,
.c-button {
// Shrink buttons a bit when they appear in a frame
align-items: baseline;
font-size: 0.85em;
padding: 3px 5px;
&:before {
font-size: 0.8em;
}
font-size: 0.8em;
}
}
</style>

View File

@@ -20,7 +20,7 @@
align-items: center;
flex: 1 1 auto;
overflow: hidden;
padding: $interiorMarginSm 1px;
padding: $interiorMarginSm;
white-space: nowrap;
&__name {

View File

@@ -9,8 +9,7 @@ export default {
props: {
view: String,
object: Object,
showEditView: Boolean,
objectPath: Array
showEditView: Boolean
},
destroyed() {
this.clear();
@@ -62,8 +61,6 @@ export default {
if (this.composition) {
this.composition._destroy();
}
this.openmct.objectViews.off('clearData', this.clearData);
},
invokeEditModeHandler(editMode) {
this.currentView.onEditModeChange(editMode);
@@ -92,19 +89,17 @@ export default {
return;
}
let objectPath = this.currentObjectPath || this.objectPath;
if (provider.edit && this.showEditView) {
if (this.openmct.editor.isEditing()) {
this.currentView = provider.edit(this.currentObject, true, objectPath);
this.currentView = provider.edit(this.currentObject);
} else {
this.currentView = provider.view(this.currentObject, false, objectPath);
this.currentView = provider.view(this.currentObject, false);
}
this.openmct.editor.on('isEditing', this.toggleEditView);
this.releaseEditModeHandler = () => this.openmct.editor.off('isEditing', this.toggleEditView);
} else {
this.currentView = provider.view(this.currentObject, this.openmct.editor.isEditing(), objectPath);
this.currentView = provider.view(this.currentObject, this.openmct.editor.isEditing());
if (this.currentView.onEditModeChange) {
this.openmct.editor.on('isEditing', this.invokeEditModeHandler);
@@ -117,10 +112,8 @@ export default {
this.removeSelectable = openmct.selection.selectable(
this.$el, this.getSelectionContext(), true);
}
this.openmct.objectViews.on('clearData', this.clearData);
},
show(object, viewKey, immediatelySelect, currentObjectPath) {
show(object, viewKey, immediatelySelect) {
if (this.unlisten) {
this.unlisten();
}
@@ -135,11 +128,6 @@ export default {
}
this.currentObject = object;
if (currentObjectPath) {
this.currentObjectPath = currentObjectPath;
}
this.unlisten = this.openmct.objects.observe(this.currentObject, '*', (mutatedObject) => {
this.currentObject = mutatedObject;
});
@@ -199,22 +187,6 @@ 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();
}
}
}
}
}

View File

@@ -1,78 +0,0 @@
<template>
<label class="c-toggle-switch">
<input type="checkbox"
:id="id"
:checked="checked"
@change="onUserSelect($event)"/>
<span class="c-toggle-switch__slider"></span>
</label>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-toggle-switch {
$d: 12px;
$m: 2px;
$br: $d/1.5;
cursor: pointer;
overflow: hidden;
display: inline;
vertical-align: middle;
&__slider {
background: $colorBtnBg; // TODO: make discrete theme constants for these colors
border-radius: $br;
//box-shadow: inset rgba($colorBtnFg, 0.4) 0 0 0 1px;
display: inline-block;
height: $d + ($m*2);
position: relative;
transform: translateY(2px); // TODO: get this to work without this kind of hack!
width: $d*2 + $m*2;
&:before {
// Knob
background: $colorBtnFg; // TODO: make discrete theme constants for these colors
border-radius: floor($br * 0.8);
box-shadow: rgba(black, 0.4) 0 0 2px;
content: '';
display: block;
position: absolute;
height: $d; width: $d;
top: $m; left: $m; right: auto;
transition: transform 100ms ease-in-out;
}
}
input {
opacity: 0;
width: 0;
height: 0;
&:checked {
+ .c-toggle-switch__slider {
background: $colorKey; // TODO: make discrete theme constants for these colors
&:before {
transform: translateX(100%);
}
}
}
}
}
</style>
<script>
export default {
inject: ['openmct'],
props: {
id: String,
checked: Boolean
},
methods: {
onUserSelect(event) {
this.$emit('change', event.target.checked);
}
}
}
</script>

View File

@@ -106,10 +106,8 @@
display: contents;
}
&__row + &__row,
&__section + &__section {
[class*="__label"],
[class*="__value"] {
&__row + &__row {
> [class*="__"] {
// Row borders, effected via border-top on child elements of the row
border-top: 1px solid $colorInspectorSectionHeaderBg;
}

View File

@@ -25,6 +25,10 @@ import _ from 'lodash';
},
methods: {
updateSelection(selection) {
if (_.isEqual(this.selection, selection)) {
return;
}
this.selection = selection;
if (this.selectedViews) {
@@ -34,6 +38,10 @@ 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');

View File

@@ -19,11 +19,28 @@
</div>
<div class="l-browse-bar__end">
<view-switcher
:currentView="currentView"
:views="views"
@setView="setView">
</view-switcher>
<div class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
v-if="views.length > 1">
<button class="c-button--menu"
:class="currentView.cssClass"
title="Switch view type"
@click.stop="toggleViewMenu">
<span class="c-button__label">
{{ currentView.name }}
</span>
</button>
<div class="c-menu" v-show="showViewMenu">
<ul>
<li v-for="(view, index) in views"
@click="setView(view)"
:key="index"
:class="view.cssClass"
:title="view.name">
{{ view.name }}
</li>
</ul>
</div>
</div>
<!-- Action buttons -->
<div class="l-browse-bar__actions">
<button v-if="notebookEnabled"
@@ -60,15 +77,14 @@
<script>
import NotebookSnapshot from '../utils/notebook-snapshot';
import ViewSwitcher from './ViewSwitcher.vue';
const PLACEHOLDER_OBJECT = {};
export default {
inject: ['openmct'],
components: {
ViewSwitcher
},
methods: {
toggleViewMenu() {
this.showViewMenu = !this.showViewMenu;
},
toggleSaveMenu() {
this.showSaveMenu = !this.showSaveMenu;
},

View File

@@ -2,14 +2,10 @@
<div class="l-shell" :class="{
'is-editing': isEditing
}">
<div class="l-shell__head" :class="{
'l-shell__head--expanded': headExpanded,
'l-shell__head--minify-indicators': !headExpanded
}">
<div class="l-shell__head">
<CreateButton class="l-shell__create-button"></CreateButton>
<indicators class="l-shell__head-section l-shell__indicators">
</indicators>
<notification-banner></notification-banner>
<indicators class="l-shell__head-section l-shell__indicators"></indicators>
<notification-banner></notification-banner> <!-- TODO: MAKE SURE THIS PLACEMENT WORKS PROPERLY -->
<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"
@@ -21,8 +17,8 @@
</button>
</div>
<app-logo></app-logo>
<button class="l-shell__head__collapse-button c-button"
@click="toggleShellHead"></button>
<!--button class="l-shell__head__collapse-button c-button"
@click="toggleShellHead"></button-->
</div>
<multipane class="l-shell__main"
type="horizontal">
@@ -66,6 +62,14 @@
flex-flow: column nowrap;
overflow: hidden;
/* &__status {
min-width: 95%;
margin-right: 1%;
background: $colorStatusBarBg;
color: $colorStatusBarFg;
padding: $interiorMarginSm;
}*/
&__pane-tree {
width: 40%;
@@ -159,7 +163,7 @@
}
&__head {
align-items: stretch;
align-items: center;
background: $colorHeadBg;
justify-content: space-between;
padding: $interiorMargin $interiorMargin + 2;
@@ -168,43 +172,19 @@
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;
}
[class*='__collapse-button']:before {
content: $glyph-icon-arrow-down;
font-size: 1.1em;
}
&-section {
// Subdivides elements across the head
@include ellipsize();
border-right: 1px solid $colorInteriorBorder;
display: flex;
flex: 0 1 auto;
padding: 0 $interiorMargin;
padding-right: $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,
@@ -215,14 +195,8 @@
&__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;
}
[class*='indicator-clock'] { order: 99; }
}
/******************************* MAIN AREA */
@@ -366,18 +340,11 @@
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,
headExpanded
hasToolbar: false
}
},
computed: {
@@ -386,18 +353,6 @@
}
},
methods: {
toggleShellHead() {
this.headExpanded = !this.headExpanded;
window.localStorage.setItem(
'openmct-shell-head',
JSON.stringify(
{
expanded: this.headExpanded
}
)
);
},
fullScreenToggle() {
if (this.fullScreen) {
this.fullScreen = false;
@@ -420,6 +375,9 @@
}
this.hasToolbar = structure.length > 0;
},
toggleShellHead() {
return true;
}
}
}

View File

@@ -1,55 +0,0 @@
<template>
<div class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
v-if="views.length > 1">
<button class="c-button--menu"
:class="currentView.cssClass"
title="Switch view type"
@click.stop="toggleViewMenu">
<span class="c-button__label">
{{ currentView.name }}
</span>
</button>
<div class="c-menu" v-show="showViewMenu">
<ul>
<li v-for="(view, index) in views"
@click="setView(view)"
:key="index"
:class="view.cssClass"
:title="view.name">
{{ view.name }}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: [
'currentView',
'views'
],
data() {
return {
showViewMenu: false
}
},
methods: {
setView(view) {
this.$emit('setView', view);
},
toggleViewMenu() {
this.showViewMenu = !this.showViewMenu;
},
hideViewMenu() {
this.showViewMenu = false;
}
},
mounted() {
document.addEventListener('click', this.hideViewMenu);
},
destroyed() {
document.removeEventListener('click', this.hideViewMenu);
}
}
</script>

View File

@@ -81,10 +81,6 @@
padding: $interiorMargin - $aPad;
transition: background 150ms ease;
> * + * {
margin-left: $interiorMarginSm;
}
&:hover {
background: $colorItemTreeHoverBg;
.c-tree__item__type-icon:before {
@@ -120,6 +116,10 @@
}
}
&__view-control {
margin-right: $interiorMarginSm;
}
// Object labels in trees
&__label {
// <a> tag that holds type icon and name.

View File

@@ -22,20 +22,70 @@
<style lang="scss">
@import "~styles/sass-base";
.c-indicator {
@include cControl();
@include cClickIconButtonLayout();
button { text-transform: uppercase; }
.l-indicators {
display: flex;
align-items: center;
}
background: none !important;
border-radius: $controlCr;
overflow: visible;
position: relative;
.c-indicator {
@include cClickIconButtonLayout();
&--clickable {
@include cClickIconButton();
@include hasMenu();
}
$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;*/
}
&.no-minify {
// For items that cannot be minified
.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;
@@ -50,78 +100,24 @@
}
}
&:not(.no-minify) {
&:not(.no-collapse) {
&:before {
margin-right: 0 !important;
}
}
}
.c-indicator__label {
// Label element. Appears as a hover bubble element when Indicators are minified;
// Appears as an inline element when not.
display: inline-block;
transition:none;
white-space: nowrap;
a,
button,
s-button,
.c-button {
// Make <a> in label look like buttons
transition: $transIn;
background: transparent;
border: 1px solid rgba($colorIndicatorMenuFg, 0.5);
border-radius: $controlCr;
box-sizing: border-box;
color: inherit;
font-size: inherit;
height: auto;
line-height: normal;
padding: 0 2px;
&:hover {
background: rgba($colorIndicatorMenuFg, 0.1);
border-color: rgba($colorIndicatorMenuFg, 0.75);
color: $colorIndicatorMenuFgHov;
}
}
[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;
}
}
}
.c-indicator__count {
display: none; // Only displays when Indicator is minified, see below
}
[class*='minify-indicators'] {
// All styles for minified Indicators should go in here
.c-indicator:not(.no-minify) {
@include hover() {
background: $colorIndicatorBgHov;
.c-indicator__label {
box-shadow: $colorIndicatorMenuBgShdw;
transform: scale(1.0);
transition: transform 100ms ease-out 100ms;
}
}
.c-indicator__label {
transition: transform 250ms ease-in 200ms;
background: $colorIndicatorMenuBg;
color: $colorIndicatorMenuFg;
border-radius: $controlCr;
.label {
transition: all 250ms ease-in 100ms;
background: $hbg;
border-radius: $br;
font-size: .6rem;
left: 0;
top: 130%;
padding: $interiorMargin $interiorMargin;
top: 140%;
opacity: 0;
padding: $interiorMarginSm $interiorMargin;
position: absolute;
transform-origin: 10px 0;
transform-origin: 10px 100%;
transform: scale(0.0);
overflow: visible;
white-space: nowrap;
z-index: 50;
&:before {
@@ -130,14 +126,13 @@
display: block;
position: absolute;
bottom: 100%;
@include triangle('up', $size: 4px, $ratio: 1, $color: $colorIndicatorMenuBg);
@include triangle('up', $size: 4px, $ratio: 1, $color: $hbg);
}
}
}
.c-indicator__count {
display: inline-block;
margin-left: $interiorMarginSm;
}
&.float-right {
float: right;
}
}
@@ -156,6 +151,12 @@
mounted() {
this.openmct.indicators.indicatorObjects.forEach((indicator) => {
// So that we can consistently position indicator elements,
// guarantee that they are wrapped in an element we control
// CH: fuck that...
// var wrapperNode = document.createElement('span');
// wrapperNode.className = 'u-contents';
// wrapperNode.appendChild(indicator.element);
this.$el.appendChild(indicator.element);
});
}

View File

@@ -57,19 +57,20 @@
.c-message-banner {
$closeBtnSize: 7px;
$m: 1px;
border-radius: $controlCr;
@include statusBannerColors($colorStatusDefault, $colorStatusFg);
cursor: pointer;
display: flex;
align-items: center;
left: 50%;
top: 50%;
max-width: 50%;
max-height: 25px;
padding: $interiorMarginSm $interiorMargin $interiorMarginSm $interiorMarginLg;
padding: $interiorMargin $interiorMargin $interiorMargin $interiorMarginLg;
position: absolute;
transform: translate(-50%, -50%);
transform: translateX(-50%);
bottom: $m;
z-index: 2;
> * + * {

View File

@@ -18,47 +18,10 @@
<span class="c-tree__item__label">Loading...</span>
</div>
</li>
<template v-if="children.length">
<template v-if="children.length > page_threshold">
<li v-show="!showSearchComponent"
@click="toggleSearchComponent"
class="c-tree__item-h"
style="font-size: 0.5em;">
<div class="c-tree__item icon-magnify">
</div>
</li>
<li v-show="showSearchComponent"
class="c-tree__item-h"
style="font-size: 0.7em">
<div class="c-tree__item">
<a class="c-tree__item__label c-object-label">
<search
:value="searchValue"
@input="searchChildren"
@clear="searchChildren"
style="min-width: 80%;">
</search>
<div style="padding: 2px; margin-left: 10%;"
class="icon-x"
@click="toggleSearchComponent">
</div>
</a>
</div>
</li>
</template>
<div :style="style"
@scroll="scrollPage"
ref="scrollParent">
<tree-item v-for="child in filteredAndPagedChildren"
:key="child.id"
:node="child">
</tree-item>
</div>
</template>
<tree-item v-for="child in children"
:key="child.id"
:node="child">
</tree-item>
</ul>
</li>
</template>
@@ -66,9 +29,6 @@
<script>
import viewControl from '../components/viewControl.vue';
import ObjectLabel from '../components/ObjectLabel.vue';
import Search from '../components/search.vue';
const PAGE_THRESHOLD = 50;
export default {
name: 'tree-item',
@@ -84,13 +44,7 @@
loaded: false,
isNavigated: this.navigateToPath === this.openmct.router.currentLocation.path,
children: [],
expanded: false,
page: 1,
page_threshold: PAGE_THRESHOLD,
searchValue: '',
filteredChildren: [],
scrollTop: 0,
showSearchComponent: false
expanded: false
}
},
computed: {
@@ -101,44 +55,6 @@
}
let parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
return parentKeyString !== this.node.object.location;
},
filteredAndPagedChildren() {
if (this.searchValue) {
this.filteredChildren = this.children.filter((child) => {
let searchLowCase = this.searchValue.toLowerCase(),
nameLowerCase = child.object.name.toLowerCase();
return nameLowerCase.includes(searchLowCase);
})
} else {
this.filteredChildren = this.children;
}
if (this.filteredChildren.length > this.page_threshold) {
let maxIndex = this.page * this.page_threshold,
minIndex = maxIndex - this.page_threshold;
return this.filteredChildren.slice(minIndex, maxIndex);
} else {
return this.filteredChildren;
}
},
lastPage() {
return Math.floor(this.filteredChildren.length / this.page_threshold);
},
style() {
let numChildren = this.filteredChildren.length;
if (!this.$refs.scrollParent || numChildren === 0) {
return {};
}
if ((numChildren * 20) > this.$refs.scrollParent.offsetHeight) {
return {
"overflow-y": 'scroll',
"max-height": (this.page_threshold * 10) + 'px'
}
}
}
},
mounted() {
@@ -181,11 +97,6 @@
this.composition.load().then(this.finishLoading);
this.isLoading = true;
}
if (!isExpanded) {
this.page = 1;
this.showSearchComponent = false;
}
}
},
methods: {
@@ -215,53 +126,11 @@
} else if (oldPath === this.navigateToPath) {
this.isNavigated = false;
}
},
nextPage() {
if (this.page < this.lastPage) {
this.page += 1;
}
},
previousPage() {
if (this.page >= 1) {
this.page -= 1;
}
},
searchChildren(input) {
this.searchValue = input;
this.page = 1;
},
scrollPage(event) {
let offsetHeight = event.target.offsetHeight,
scrollTop = event.target.scrollTop,
changePage = true;
window.clearTimeout(this.scrollLoading);
if (scrollTop > this.scrollTop && scrollTop > offsetHeight) {
this.scrollLoading = window.setTimeout(() => {
if (this.page < this.lastPage) {
this.nextPage();
event.target.scrollTop = 1;
}
}, 250);
} else if (this.scrollTop <= this.scrollTop && scrollTop <= 0) {
this.scrollLoading = window.setTimeout(() => {
if (this.page > 1) {
this.previousPage();
event.target.scrollTop = offsetHeight - 1;
}
}, 250);
}
this.scrollTop = scrollTop;
},
toggleSearchComponent() {
this.showSearchComponent = !this.showSearchComponent;
}
},
components: {
viewControl,
ObjectLabel,
Search
ObjectLabel
}
}
</script>

View File

@@ -33,11 +33,6 @@
</div>
<div class="l-browse-bar__end">
<div class="l-browse-bar__actions">
<view-switcher
:views="views"
:currentView="currentView"
@setView="setView">
</view-switcher>
<button v-if="notebookEnabled"
class="l-browse-bar__actions__edit c-button icon-notebook"
title="New Notebook entry"
@@ -85,52 +80,20 @@
<script>
import ContextMenuDropDown from '../../ui/components/contextMenuDropDown.vue';
import ViewSwitcher from '../../ui/layout/ViewSwitcher.vue';
import NotebookSnapshot from '../utils/notebook-snapshot';
export default {
components: {
ContextMenuDropDown,
ViewSwitcher
ContextMenuDropDown
},
inject: [
'openmct',
'objectPath'
],
computed: {
views() {
return this
.openmct
.objectViews
.get(this.domainObject);
},
currentView() {
return this.views.filter(v => v.key === this.viewKey)[0] || {};
}
},
methods: {
snapshot() {
let element = document.getElementsByClassName("l-preview-window__object-view")[0];
this.notebookSnapshot.capture(this.domainObject, element);
},
clear() {
if (this.view) {
this.view.destroy();
this.$refs.objectView.innerHTML = '';
}
delete this.view;
delete this.viewContainer;
},
setView(view) {
this.clear();
this.viewKey = view.key;
this.viewContainer = document.createElement('div');
this.viewContainer.classList.add('c-object-view','u-contents');
this.$refs.objectView.append(this.viewContainer);
this.view = this.currentView.view(this.domainObject, false, this.objectPath);
this.view.show(this.viewContainer, false);
}
},
data() {
@@ -140,13 +103,13 @@
return {
domainObject: domainObject,
type: type,
notebookEnabled: false,
viewKey: undefined
notebookEnabled: false
};
},
mounted() {
let view = this.openmct.objectViews.get(this.domainObject)[0];
this.setView(view);
let viewProvider = this.openmct.objectViews.get(this.domainObject)[0];
this.view = viewProvider.view(this.domainObject);
this.view.show(this.$refs.objectView, false);
if (this.openmct.types.get('notebook')) {
this.notebookSnapshot = new NotebookSnapshot(this.openmct);

View File

@@ -28,7 +28,6 @@ export default class PreviewAction {
* Metadata
*/
this.name = 'Preview';
this.key = 'preview';
this.description = 'Preview in large dialog';
this.cssClass = 'icon-eye-open';

Some files were not shown because too many files have changed in this diff Show More