Compare commits

...

10 Commits

Author SHA1 Message Date
David Tsay
c46f10de74 add timer plugin 2021-01-11 11:40:11 -08:00
Charles Hacskaylo
6f51de85db Fix for changed approach to 'type' object (#3636) 2021-01-08 15:27:00 -08:00
Jamie V
f202ae19cb [Search] Index domain object type and provide query lite (index only) option (#3416)
* WIP

* Reverting some files

* reverting

* using type from model, instead of passing in separately

* reverting to remove query lite from search aggregator, as it is no longer necessary

* removing erroneous properties from legacy search results

* removed unnecessary parameters for type since it is included in the model and we have acces too that

* missed one

* removed empty space

* removed unneccessary code

Co-authored-by: Deep Tailor <deep.j.tailor@nasa.gov>
2021-01-08 14:16:01 -08:00
Deep Tailor
668bd75025 Revert "[Navigation Tree] Whole tree item clickable (#3632)" (#3635)
This reverts commit e6e07cf959.
2021-01-08 12:57:39 -08:00
Jamie V
e6e07cf959 [Navigation Tree] Whole tree item clickable (#3632)
* passing click and context click on tree item down to object label, making the whole tree item interactive

* removed unnecessary code
2021-01-08 11:55:43 -08:00
Jamie V
2f8431905f [Navigation Tree] Fixes initial load navigation request breaks if children haven't loaded in yet (#3630)
* changed logic so people cant navigate up tree til initial load has happened, thus ensuring ancestors have been populated for the first time
2021-01-08 09:38:09 -08:00
Nikhil
23aba14dfe [Notebook] Do not persist notebook objects in notebook Local Storage (#3295)
* [Notebook] Do not persist domain objects on notebooks or snapshots #3291
Co-authored-by: Deep Tailor <deep.j.tailor@nasa.gov>
2021-01-06 15:30:57 -08:00
Nikhil
b0fa955914 [openmct-YAMCS] TelemetryTableRow refactor createNormalizedDatum to include extra datum #3613 (#3614) 2021-01-06 11:38:45 -08:00
Deep Tailor
98207a3e0d Context click should add a class to tree item (#3619)
* add ability to pass onDestroy callback to menu api show

* fix lint issues

* remove fdescribe

* rename event and variables to contextClickActive

* rename variable to active

* Sanding and polishing CSS related to context-click visual feedback

- Changed CSS `border` approach to `box-shadow` to avoid jumping;
- Removed unwired code and CSS styles for Folder grid and list views;

Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: charlesh88 <charlesh88@gmail.com>
2021-01-04 12:57:18 -08:00
Shefali Joshi
26b81345f2 Various Conditionals bug fixes (#3611)
* Don't apply styles on destroy as destroy should not have any side effects

* Don't show undefined if trigger for condition is not available yet

* Force recalculation of condition result if telemetry is removed

Co-authored-by: Deep Tailor <deep.j.tailor@nasa.gov>
2021-01-04 10:02:43 -08:00
21 changed files with 175 additions and 77 deletions

View File

@@ -32,7 +32,8 @@
function indexItem(id, model) {
indexedItems.push({
id: id,
name: model.name.toLowerCase()
name: model.name.toLowerCase(),
type: model.type
});
}

View File

@@ -125,13 +125,12 @@ define([
* @param topic the topicService.
*/
GenericSearchProvider.prototype.indexOnMutation = function (topic) {
var mutationTopic = topic('mutation'),
provider = this;
let mutationTopic = topic('mutation');
mutationTopic.listen(function (mutatedObject) {
var editor = mutatedObject.getCapability('editor');
mutationTopic.listen(mutatedObject => {
let editor = mutatedObject.getCapability('editor');
if (!editor || !editor.inEditContext()) {
provider.index(
this.index(
mutatedObject.getId(),
mutatedObject.getModel()
);
@@ -262,6 +261,7 @@ define([
return {
id: hit.item.id,
model: hit.item.model,
type: hit.item.type,
score: hit.matchCount
};
});

View File

@@ -41,7 +41,8 @@
indexedItems.push({
id: id,
vector: vector,
model: model
model: model,
type: model.type
});
}

View File

@@ -38,7 +38,7 @@ class MenuAPI {
this._showObjectMenu = this._showObjectMenu.bind(this);
}
showMenu(x, y, actions) {
showMenu(x, y, actions, onDestroy) {
if (this.menuComponent) {
this.menuComponent.dismiss();
}
@@ -46,7 +46,8 @@ class MenuAPI {
let options = {
x,
y,
actions
actions,
onDestroy
};
this.menuComponent = new Menu(options);

View File

@@ -31,6 +31,7 @@ describe ('The Menu API', () => {
let x;
let y;
let result;
let onDestroy;
beforeEach(() => {
openmct = createOpenMct();
@@ -73,7 +74,9 @@ describe ('The Menu API', () => {
let vueComponent;
beforeEach(() => {
menuAPI.showMenu(x, y, actionsArray);
onDestroy = jasmine.createSpy('onDestroy');
menuAPI.showMenu(x, y, actionsArray, onDestroy);
vueComponent = menuAPI.menuComponent.component;
menuComponent = document.querySelector(".c-menu");
@@ -120,6 +123,12 @@ describe ('The Menu API', () => {
expect(vueComponent.$destroy).toHaveBeenCalled();
});
it("invokes the onDestroy callback if passed in", () => {
document.body.click();
expect(onDestroy).toHaveBeenCalled();
});
});
});
});

View File

@@ -75,7 +75,8 @@ export default class Condition extends EventEmitter {
return;
}
if (this.isTelemetryUsed(datum.id)) {
// if all the criteria in this condition have no telemetry, we want to force the condition result to evaluate
if (this.hasNoTelemetry() || this.isTelemetryUsed(datum.id)) {
this.criteria.forEach(criterion => {
if (this.isAnyOrAllTelemetry(criterion)) {
@@ -93,6 +94,12 @@ export default class Condition extends EventEmitter {
return (criterion.telemetry && (criterion.telemetry === 'all' || criterion.telemetry === 'any'));
}
hasNoTelemetry() {
return this.criteria.every((criterion) => {
return !this.isAnyOrAllTelemetry(criterion) && criterion.telemetry === '';
});
}
isTelemetryUsed(id) {
return this.criteria.some(criterion => {
return this.isAnyOrAllTelemetry(criterion) || criterion.telemetryObjectIdAsString === id;
@@ -250,10 +257,17 @@ export default class Condition extends EventEmitter {
}
getTriggerDescription() {
return {
conjunction: TRIGGER_CONJUNCTION[this.trigger],
prefix: `${TRIGGER_LABEL[this.trigger]}: `
};
if (this.trigger) {
return {
conjunction: TRIGGER_CONJUNCTION[this.trigger],
prefix: `${TRIGGER_LABEL[this.trigger]}: `
};
} else {
return {
conjunction: '',
prefix: ''
};
}
}
requestLADConditionResult() {

View File

@@ -79,6 +79,17 @@ export default class ConditionManager extends EventEmitter {
delete this.subscriptions[id];
delete this.telemetryObjects[id];
this.removeConditionTelemetryObjects();
//force re-computation of condition set result as we might be in a state where
// there is no telemetry datum coming in for a while or at all.
let latestTimestamp = getLatestTimestamp(
{},
{},
this.timeSystems,
this.openmct.time.timeSystem()
);
this.updateConditionResults({id: id});
this.updateCurrentCondition(latestTimestamp);
}
initialize() {
@@ -336,14 +347,17 @@ export default class ConditionManager extends EventEmitter {
let timestamp = {};
timestamp[timeSystemKey] = normalizedDatum[timeSystemKey];
this.updateConditionResults(normalizedDatum);
this.updateCurrentCondition(timestamp);
}
updateConditionResults(normalizedDatum) {
//We want to stop when the first condition evaluates to true.
this.conditions.some((condition) => {
condition.updateResult(normalizedDatum);
return condition.result === true;
});
this.updateCurrentCondition(timestamp);
}
updateCurrentCondition(timestamp) {

View File

@@ -86,6 +86,7 @@ export default class StyleRuleManager extends EventEmitter {
updateObjectStyleConfig(styleConfiguration) {
if (!styleConfiguration || !styleConfiguration.conditionSetIdentifier) {
this.initialize(styleConfiguration || {});
this.applyStaticStyle();
this.destroy();
} else {
let isNewConditionSet = !this.conditionSetIdentifier
@@ -158,7 +159,6 @@ export default class StyleRuleManager extends EventEmitter {
}
destroy() {
this.applyStaticStyle();
if (this.stopProvidingTelemetry) {
this.stopProvidingTelemetry();
delete this.stopProvidingTelemetry;

View File

@@ -1,7 +1,9 @@
<template>
<tr
class="c-list-item"
:class="{ 'is-alias': item.isAlias === true }"
:class="{
'is-alias': item.isAlias === true
}"
@click="navigate"
>
<td class="c-list-item__name">

View File

@@ -225,14 +225,12 @@ export default {
},
createNotebookStorageObject() {
const notebookMeta = {
name: this.internalDomainObject.name,
identifier: this.internalDomainObject.identifier
};
const page = this.getSelectedPage();
const section = this.getSelectedSection();
return {
domainObject: this.internalDomainObject,
notebookMeta,
section,
page
@@ -442,10 +440,10 @@ export default {
async updateDefaultNotebook(notebookStorage) {
const defaultNotebookObject = await this.getDefaultNotebookObject();
if (!defaultNotebookObject) {
setDefaultNotebook(this.openmct, notebookStorage);
setDefaultNotebook(this.openmct, notebookStorage, this.internalDomainObject);
} else if (objectUtils.makeKeyString(defaultNotebookObject.identifier) !== objectUtils.makeKeyString(notebookStorage.notebookMeta.identifier)) {
this.removeDefaultClass(defaultNotebookObject);
setDefaultNotebook(this.openmct, notebookStorage);
setDefaultNotebook(this.openmct, notebookStorage, this.internalDomainObject);
}
if (this.defaultSectionId && this.defaultSectionId.length === 0 || this.defaultSectionId !== notebookStorage.section.id) {

View File

@@ -44,38 +44,46 @@ export default {
},
data() {
return {
notebookSnapshot: null,
notebookSnapshot: undefined,
notebookTypes: []
};
},
mounted() {
validateNotebookStorageObject();
this.getDefaultNotebookObject();
this.notebookSnapshot = new Snapshot(this.openmct);
this.setDefaultNotebookStatus();
},
methods: {
showMenu(event) {
const notebookTypes = [];
async getDefaultNotebookObject() {
const defaultNotebook = getDefaultNotebook();
const defaultNotebookObject = defaultNotebook && await this.openmct.objects.get(defaultNotebook.notebookMeta.identifier);
return defaultNotebookObject;
},
async showMenu(event) {
const notebookTypes = [];
const elementBoundingClientRect = this.$el.getBoundingClientRect();
const x = elementBoundingClientRect.x;
const y = elementBoundingClientRect.y + elementBoundingClientRect.height;
if (defaultNotebook) {
const domainObject = defaultNotebook.domainObject;
const defaultNotebookObject = await this.getDefaultNotebookObject();
if (defaultNotebookObject) {
const name = defaultNotebookObject.name;
if (domainObject.location) {
const defaultPath = `${domainObject.name} - ${defaultNotebook.section.name} - ${defaultNotebook.page.name}`;
const defaultNotebook = getDefaultNotebook();
const sectionName = defaultNotebook.section.name;
const pageName = defaultNotebook.page.name;
const defaultPath = `${name} - ${sectionName} - ${pageName}`;
notebookTypes.push({
cssClass: 'icon-notebook',
name: `Save to Notebook ${defaultPath}`,
callBack: () => {
return this.snapshot(NOTEBOOK_DEFAULT);
}
});
}
notebookTypes.push({
cssClass: 'icon-notebook',
name: `Save to Notebook ${defaultPath}`,
callBack: () => {
return this.snapshot(NOTEBOOK_DEFAULT);
}
});
}
notebookTypes.push({

View File

@@ -23,13 +23,6 @@ import * as NotebookEntries from './notebook-entries';
import { createOpenMct, resetApplicationState } from 'utils/testing';
const notebookStorage = {
domainObject: {
name: 'notebook',
identifier: {
namespace: '',
key: 'test-notebook'
}
},
notebookMeta: {
name: 'notebook',
identifier: {

View File

@@ -1,13 +1,12 @@
import objectUtils from 'objectUtils';
const NOTEBOOK_LOCAL_STORAGE = 'notebook-storage';
let currentNotebookObject = null;
let currentNotebookObjectIdentifier = null;
let unlisten = null;
function defaultNotebookObjectChanged(newDomainObject) {
if (newDomainObject.location !== null) {
currentNotebookObject = newDomainObject;
const notebookStorage = getDefaultNotebook();
notebookStorage.domainObject = newDomainObject;
saveDefaultNotebook(notebookStorage);
currentNotebookObjectIdentifier = newDomainObject.identifier;
return;
}
@@ -20,10 +19,9 @@ function defaultNotebookObjectChanged(newDomainObject) {
clearDefaultNotebook();
}
function observeDefaultNotebookObject(openmct, notebookStorage) {
const domainObject = notebookStorage.domainObject;
if (currentNotebookObject
&& currentNotebookObject.identifier.key === domainObject.identifier.key) {
function observeDefaultNotebookObject(openmct, notebookMeta, domainObject) {
if (currentNotebookObjectIdentifier
&& objectUtils.makeKeyString(currentNotebookObjectIdentifier) === objectUtils.makeKeyString(notebookMeta.identifier)) {
return;
}
@@ -32,7 +30,7 @@ function observeDefaultNotebookObject(openmct, notebookStorage) {
unlisten = null;
}
unlisten = openmct.objects.observe(notebookStorage.domainObject, '*', defaultNotebookObjectChanged);
unlisten = openmct.objects.observe(domainObject, '*', defaultNotebookObjectChanged);
}
function saveDefaultNotebook(notebookStorage) {
@@ -40,7 +38,7 @@ function saveDefaultNotebook(notebookStorage) {
}
export function clearDefaultNotebook() {
currentNotebookObject = null;
currentNotebookObjectIdentifier = null;
window.localStorage.setItem(NOTEBOOK_LOCAL_STORAGE, null);
}
@@ -50,8 +48,8 @@ export function getDefaultNotebook() {
return JSON.parse(notebookStorage);
}
export function setDefaultNotebook(openmct, notebookStorage) {
observeDefaultNotebookObject(openmct, notebookStorage);
export function setDefaultNotebook(openmct, notebookStorage, domainObject) {
observeDefaultNotebookObject(openmct, notebookStorage.notebookMeta, domainObject);
saveDefaultNotebook(notebookStorage);
}

View File

@@ -23,14 +23,15 @@
import * as NotebookStorage from './notebook-storage';
import { createOpenMct, resetApplicationState } from 'utils/testing';
const domainObject = {
name: 'notebook',
identifier: {
namespace: '',
key: 'test-notebook'
}
};
const notebookStorage = {
domainObject: {
name: 'notebook',
identifier: {
namespace: '',
key: 'test-notebook'
}
},
notebookMeta: {
name: 'notebook',
identifier: {
@@ -82,7 +83,7 @@ describe('Notebook Storage:', () => {
});
it('has correct notebookstorage on setDefaultNotebook', () => {
NotebookStorage.setDefaultNotebook(openmct, notebookStorage);
NotebookStorage.setDefaultNotebook(openmct, notebookStorage, domainObject);
const defaultNotebook = NotebookStorage.getDefaultNotebook();
expect(JSON.stringify(defaultNotebook)).toBe(JSON.stringify(notebookStorage));
@@ -98,7 +99,7 @@ describe('Notebook Storage:', () => {
sectionTitle: 'Section'
};
NotebookStorage.setDefaultNotebook(openmct, notebookStorage);
NotebookStorage.setDefaultNotebook(openmct, notebookStorage, domainObject);
NotebookStorage.setDefaultNotebookSection(section);
const defaultNotebook = NotebookStorage.getDefaultNotebook();
@@ -115,7 +116,7 @@ describe('Notebook Storage:', () => {
pageTitle: 'Page'
};
NotebookStorage.setDefaultNotebook(openmct, notebookStorage);
NotebookStorage.setDefaultNotebook(openmct, notebookStorage, domainObject);
NotebookStorage.setDefaultNotebookPage(page);
const defaultNotebook = NotebookStorage.getDefaultNotebook();

View File

@@ -100,11 +100,13 @@ define([], function () {
* @param {*} metadataValues
*/
function createNormalizedDatum(datum, columns) {
return Object.values(columns).reduce((normalizedDatum, column) => {
normalizedDatum[column.getKey()] = column.getRawValue(datum);
const normalizedDatum = JSON.parse(JSON.stringify(datum));
return normalizedDatum;
}, {});
Object.values(columns).forEach(column => {
normalizedDatum[column.getKey()] = column.getRawValue(datum);
});
return normalizedDatum;
}
return TelemetryTableRow;

View File

@@ -0,0 +1,29 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import TimerViewProvider from './TimerViewProvider';
export default function TimerPlugin() {
return function install(openmct) {
openmct.objectViews.addProvider(new TimerViewProvider(openmct));
};
}

View File

@@ -95,6 +95,10 @@
color: $colorItemTreeSelectedFg;
}
}
&.is-context-clicked {
box-shadow: inset $colorItemTreeSelectedBg 0 0 0 1px;
}
}
}

View File

@@ -65,7 +65,7 @@
v-for="(ancestor, index) in focusedAncestors"
:key="ancestor.id"
:node="ancestor"
:show-up="index < focusedAncestors.length - 1"
:show-up="index < focusedAncestors.length - 1 && initialLoad"
:show-down="false"
:left-offset="index * 10 + 'px'"
@resetTree="beginNavigationRequest('handleReset', ancestor)"
@@ -156,6 +156,7 @@ export default {
data() {
return {
root: undefined,
initialLoad: false,
isLoading: false,
mainTreeHeight: undefined,
searchLoading: false,
@@ -499,6 +500,11 @@ export default {
this.ancestors = ancestors;
this.childItems = children;
// track when FIRST full load of tree happens
if (!this.initialLoad) {
this.initialLoad = true;
}
// any new items added or removed handled here
this.composition.on('add', this.addChild);
this.composition.on('remove', this.removeChild);

View File

@@ -11,7 +11,8 @@
class="c-tree__item"
:class="{
'is-alias': isAlias,
'is-navigated-object': navigated
'is-navigated-object': navigated,
'is-context-clicked': contextClickActive
}"
>
<view-control
@@ -26,6 +27,7 @@
:object-path="node.objectPath"
:navigate-to-path="navigationPath"
:style="{ paddingLeft: leftOffset }"
@context-click-active="setContextClickActive"
/>
<view-control
v-model="expanded"
@@ -91,7 +93,8 @@ export default {
return {
hasComposition: false,
navigated: this.isNavigated(),
expanded: false
expanded: false,
contextClickActive: false
};
},
computed: {
@@ -142,6 +145,9 @@ export default {
},
resetTreeHere() {
this.$emit('resetTree', this.node);
},
setContextClickActive(active) {
this.contextClickActive = active;
}
}
};

View File

@@ -8,6 +8,11 @@ export default {
}
}
},
data() {
return {
contextClickActive: false
};
},
mounted() {
//TODO: touch support
this.$el.addEventListener('contextmenu', this.showContextMenu);
@@ -35,7 +40,13 @@ export default {
let actions = actionsCollection.getVisibleActions();
let sortedActions = this.openmct.actions._groupAndSortActions(actions);
this.openmct.menus.showMenu(event.clientX, event.clientY, sortedActions);
this.openmct.menus.showMenu(event.clientX, event.clientY, sortedActions, this.onContextMenuDestroyed);
this.contextClickActive = true;
this.$emit('context-click-active', true);
},
onContextMenuDestroyed() {
this.contextClickActive = false;
this.$emit('context-click-active', false);
}
}
};

View File

@@ -5,7 +5,7 @@
class="l-browse-bar__object-name--w c-object-label"
>
<div class="c-object-label__type-icon"
:class="type.cssClass"
:class="type.definition.cssClass"
></div>
<span class="l-browse-bar__object-name c-object-label__name">
{{ domainObject.name }}