Context-Menu for Tables (#2424)

* add context menu capability to table rows, add view switcher to preview

* add an option to limit context menu actions to the ones requested, and modify preview action to also include a view historical data action

* extend preview action into view historical data action

* add context menu to LAD Table

* add keys to context menu actions, allow tables to conditionally attach context menu handler

* working switch y axis label

* New vertical select element for Y axis configuration in plots

- CSS for vertically rotated selects for Y axis label selection;
- New theme constants;
- Removed themedSelect theme mixins;
- New SASS svgColorFromHex function;

* use keys in lad table context menu options

* show historical view context menu on alpha-numerics

* make reviewer requested changes

* pass contextual object path from object view down etc

* made reviewer requested changes: removed options object, pass in object path instead

* remove redundant function from LADRow.vue
This commit is contained in:
Deep Tailor
2019-07-26 16:09:59 -07:00
committed by Andrew Henry
parent 768d99d928
commit 97230bb21f
35 changed files with 346 additions and 94 deletions

View File

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

@ -49,6 +49,9 @@ 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
@ -72,12 +75,21 @@ class ContextMenuAPI {
/**
* @private
*/
_showContextMenuForObjectPath(objectPath, x, y) {
_showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded) {
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);
return action.appliesTo(objectPath) && !action.hideInDefaultMenu;
}
});
if (this._activeContextMenu) {

View File

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

View File

@ -1,3 +1,4 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
@ -21,7 +22,7 @@
*****************************************************************************/
<template>
<tr>
<tr @contextmenu.prevent="showContextMenu">
<td>{{name}}</td>
<td>{{timestamp}}</td>
<td :class="valueClass">
@ -35,15 +36,25 @@
</style>
<script>
const CONTEXT_MENU_ACTIONS = [
'viewHistoricalData',
'remove'
];
export default {
inject: ['openmct'],
inject: ['openmct', 'objectPath'],
props: ['domainObject'],
data() {
let currentObjectPath = this.objectPath.slice();
currentObjectPath.unshift(this.domainObject);
return {
name: this.domainObject.name,
timestamp: '---',
value: '---',
valueClass: ''
valueClass: '',
currentObjectPath
}
},
methods: {
@ -73,11 +84,15 @@ 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'],
inject: ['openmct', 'domainObject', 'objectPath'],
components: {
LadRow
},

View File

@ -46,13 +46,14 @@ define([
return selection.every(isTelemetryObject);
},
view: function (selection) {
view: function (domainObject, isEditing, objectPath) {
let component;
return {
show: function (element) {
component = new Vue({
provide: {
openmct
openmct,
objectPath
},
components: {
AlphanumericFormatView: AlphanumericFormatView.default

View File

@ -202,7 +202,7 @@
return selectionPath && selectionPath.length > 1 && !singleSelectedLine;
}
},
inject: ['openmct', 'options'],
inject: ['openmct', 'options', 'objectPath'],
props: ['domainObject'],
components: components,
methods: {

View File

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

View File

@ -27,7 +27,8 @@
@endMove="() => $emit('endMove')">
<div class="c-telemetry-view"
:style="styleObject"
v-if="domainObject">
v-if="domainObject"
@contextmenu.prevent="showContextMenu">
<div v-if="showLabel"
class="c-telemetry-view__label">
<div class="c-telemetry-view__label-text">{{ domainObject.name }}</div>
@ -82,7 +83,8 @@
import printj from 'printj'
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
DEFAULT_POSITION = [1, 1];
DEFAULT_POSITION = [1, 1],
CONTEXT_MENU_ACTIONS = ['viewHistoricalData'];
export default {
makeDefinition(openmct, gridSize, domainObject, position) {
@ -103,7 +105,7 @@
size: "13px"
};
},
inject: ['openmct'],
inject: ['openmct', 'objectPath'],
props: {
item: Object,
gridSize: Array,
@ -163,7 +165,8 @@
return {
datum: undefined,
formats: undefined,
domainObject: undefined
domainObject: undefined,
currentObjectPath: undefined
}
},
watch: {
@ -218,12 +221,16 @@
},
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,
@ -235,6 +242,9 @@
},
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

@ -37,7 +37,7 @@ export default function DisplayLayoutPlugin(options) {
canEdit: function (domainObject) {
return domainObject.type === 'layout';
},
view: function (domainObject) {
view: function (domainObject, isEditing, objectPath) {
let component;
return {
show(container) {
@ -49,13 +49,14 @@ export default function DisplayLayoutPlugin(options) {
provide: {
openmct,
objectUtils,
options
options,
objectPath
},
el: container,
data () {
return {
domainObject: domainObject
}
};
}
});
},

View File

@ -23,6 +23,7 @@
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,10 +115,22 @@
width: (tickWidth + 30) + 'px'
}">
<div class="gl-plot-label gl-plot-y-label">
<div class="gl-plot-label gl-plot-y-label" ng-if="!yKeyOptions">
{{ 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"
@ -165,7 +177,7 @@
<div class="gl-plot__local-controls h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover">
<div class="c-button-set c-button-set--strip-h">
<button class="c-button icon-minus"
ng-click="plot.zoom('out', 0.2)"
ng-click="plot.toggleYAxis()"
title="Zoom out">
</button>
<button class="c-button icon-plus"

View File

@ -93,6 +93,8 @@ 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;
@ -103,9 +105,27 @@ 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
};
});
} else {
this.$scope.yKeyOptions = undefined;
}
};
MCTPlotController.prototype.onXAxisChange = function (displayBounds) {
@ -493,5 +513,13 @@ 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

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

@ -68,6 +68,10 @@ define([], function () {
}
return this.cellLimitClasses;
}
getContextMenuActions() {
return [];
}
}
/**

View File

@ -48,7 +48,7 @@ define([
canEdit(domainObject) {
return domainObject.type === 'table';
},
view(domainObject) {
view(domainObject, isEditing, objectPath) {
let table = new TelemetryTable(domainObject, openmct);
let component;
return {
@ -64,7 +64,8 @@ define([
},
provide: {
openmct,
table
table,
objectPath
},
el: element,
template: '<table-component :isEditing="isEditing" :enableMarking="true"></table-component>'

View File

@ -26,7 +26,7 @@
rowClass,
{'is-selected': marked}
]"
@click="markRow">
v-on="listeners">
<component v-for="(title, key) in headers"
:key="key"
:is="componentList[key]"
@ -56,6 +56,7 @@
import TableCell from './table-cell.vue';
export default {
inject: ['openmct', 'objectPath'],
data: function () {
return {
rowTop: (this.rowOffset + this.rowIndex) * this.rowHeight + 'px',
@ -150,6 +151,16 @@ export default {
}], 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
@ -162,6 +173,19 @@ export default {
},
components: {
TableCell
},
computed: {
listeners() {
let listenersObject = {
click: this.markRow
}
if (this.row.getContextMenuActions().length) {
listenersObject.contextmenu = this.showContextMenu;
}
return listenersObject;
}
}
}
</script>

View File

@ -348,7 +348,7 @@ export default {
search,
TelemetryFilterIndicator
},
inject: ['table', 'openmct'],
inject: ['table', 'openmct', 'objectPath'],
props: {
isEditing: {
type: Boolean,

View File

@ -211,6 +211,10 @@ $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%);
@ -425,7 +429,3 @@ $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

@ -215,6 +215,10 @@ $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%);
@ -430,10 +434,6 @@ $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

@ -211,6 +211,10 @@ $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%);
@ -424,7 +428,3 @@ $createBtnTextTransform: uppercase;
@mixin themedButton($c: $colorBtnBg) {
background: $c;
}
@mixin themedSelect($bg: $colorBtnBg, $fg: $colorBtnFg) {
@include cSelect($bg, $fg, lighten($bg, 20%), none);
}

View File

@ -279,7 +279,10 @@ input[type=number]::-webkit-outer-spin-button {
// SELECTS
select {
@include appearanceNone();
@include themedSelect();
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;
background-repeat: no-repeat, no-repeat;
background-position: right .4em top 80%, 0 0;
border: none;

View File

@ -161,8 +161,7 @@ mct-plot {
height: auto;
}
&.gl-plot-y-label,
&.l-plot-y-label {
&.gl-plot-y-label {
$x: -50%;
$r: -90deg;
transform-origin: 50% 0;
@ -172,6 +171,12 @@ 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

@ -585,6 +585,11 @@
}
}
@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

@ -44,7 +44,8 @@
class="c-so-view__object-view"
ref="objectView"
:object="domainObject"
:show-edit-view="showEditView">
:show-edit-view="showEditView"
:object-path="objectPath">
</object-view>
</div>
</template>

View File

@ -9,7 +9,8 @@ export default {
props: {
view: String,
object: Object,
showEditView: Boolean
showEditView: Boolean,
objectPath: Array
},
destroyed() {
this.clear();
@ -91,17 +92,19 @@ 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);
this.currentView = provider.edit(this.currentObject, true, objectPath);
} else {
this.currentView = provider.view(this.currentObject, false);
this.currentView = provider.view(this.currentObject, false, objectPath);
}
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());
this.currentView = provider.view(this.currentObject, this.openmct.editor.isEditing(), objectPath);
if (this.currentView.onEditModeChange) {
this.openmct.editor.on('isEditing', this.invokeEditModeHandler);
@ -117,7 +120,7 @@ export default {
this.openmct.objectViews.on('clearData', this.clearData);
},
show(object, viewKey, immediatelySelect) {
show(object, viewKey, immediatelySelect, currentObjectPath) {
if (this.unlisten) {
this.unlisten();
}
@ -132,6 +135,11 @@ export default {
}
this.currentObject = object;
if (currentObjectPath) {
this.currentObjectPath = currentObjectPath;
}
this.unlisten = this.openmct.objects.observe(this.currentObject, '*', (mutatedObject) => {
this.currentObject = mutatedObject;
});

View File

@ -19,28 +19,11 @@
</div>
<div class="l-browse-bar__end">
<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>
<view-switcher
:currentView="currentView"
:views="views"
@setView="setView">
</view-switcher>
<!-- Action buttons -->
<div class="l-browse-bar__actions">
<button v-if="notebookEnabled"
@ -77,14 +60,15 @@
<script>
import NotebookSnapshot from '../utils/notebook-snapshot';
import ViewSwitcher from './ViewSwitcher.vue';
const PLACEHOLDER_OBJECT = {};
export default {
inject: ['openmct'],
methods: {
toggleViewMenu() {
this.showViewMenu = !this.showViewMenu;
components: {
ViewSwitcher
},
methods: {
toggleSaveMenu() {
this.showSaveMenu = !this.showSaveMenu;
},

View File

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

@ -33,6 +33,11 @@
</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"
@ -80,20 +85,52 @@
<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
ContextMenuDropDown,
ViewSwitcher
},
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() {
@ -103,13 +140,13 @@
return {
domainObject: domainObject,
type: type,
notebookEnabled: false
notebookEnabled: false,
viewKey: undefined
};
},
mounted() {
let viewProvider = this.openmct.objectViews.get(this.domainObject)[0];
this.view = viewProvider.view(this.domainObject);
this.view.show(this.$refs.objectView, false);
let view = this.openmct.objectViews.get(this.domainObject)[0];
this.setView(view);
if (this.openmct.types.get('notebook')) {
this.notebookSnapshot = new NotebookSnapshot(this.openmct);

View File

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

View File

@ -0,0 +1,35 @@
/*****************************************************************************
* 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 PreviewAction from './PreviewAction';
export default class ViewHistoricalDataAction extends PreviewAction {
constructor(openmct) {
super(openmct);
this.name = 'View Historical Data';
this.key = 'viewHistoricalData';
this.description = 'View Historical Data in a Table or Plot';
this.cssClass = 'icon-eye-open';
this.hideInDefaultMenu = true;
}
}

View File

@ -20,9 +20,11 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import PreviewAction from './PreviewAction.js';
import ViewHistoricalDataAction from './ViewHistoricalDataAction';
export default function () {
return function (openmct) {
openmct.contextMenu.registerAction(new PreviewAction(openmct));
}
openmct.contextMenu.registerAction(new ViewHistoricalDataAction(openmct));
};
}

View File

@ -223,11 +223,11 @@ define(['EventEmitter'], function (EventEmitter) {
/**
* Provide a view of this object.
*
* When called by Open MCT, this may include additional arguments
* which are on the path to the object to be viewed; for instance,
* when viewing "A Folder" within "My Items", this method will be
* invoked with "A Folder" (as a domain object) as the first argument,
* and "My Items" as the second argument.
* When called by Open MCT, the following arguments will be passed to it:
* @param {object} domainObject - the domainObject that the view is provided for
* @param {boolean} isEditing - A boolean value indicating wether openmct is in a global edit mode
* @param {array} objectPath - The current contextual object path of the view object
* eg current domainObject is located under MyItems which is under Root
*
* @method view
* @memberof module:openmct.ViewProvider#

View File

@ -8,6 +8,7 @@ define([
let navigateCall = 0;
let browseObject;
let unobserve = undefined;
let currentObjectPath;
openmct.router.route(/^\/browse\/?$/, navigateToFirstChildOfRoot);
@ -26,7 +27,9 @@ define([
});
function viewObject(object, viewProvider) {
openmct.layout.$refs.browseObject.show(object, viewProvider.key, true);
currentObjectPath = openmct.router.path;
openmct.layout.$refs.browseObject.show(object, viewProvider.key, true, currentObjectPath);
openmct.layout.$refs.browseBar.domainObject = object;
openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
}