[Imagery] Click on image to get a large view (#3770)

* [Imagery] Click on image to get a large view #3582
* Created new viewLargeAction.
* Changes in view registry to add parent element property inside view object.
* Separate class for views and added missing changes for LadTableSet.
* Renamed callBack to onItemClicked.

Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
Nikhil 2021-07-29 09:19:07 -07:00 committed by GitHub
parent ca66898e51
commit 071a13b219
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 930 additions and 659 deletions

View File

@ -1,4 +1,4 @@
import Vue from 'Vue'; import Vue from 'vue';
import HelloWorld from './HelloWorld.vue'; import HelloWorld from './HelloWorld.vue';
function SimpleVuePlugin() { function SimpleVuePlugin() {

View File

@ -262,7 +262,7 @@ define([
// Plugins that are installed by default // Plugins that are installed by default
this.install(this.plugins.Plot()); this.install(this.plugins.Plot());
this.install(this.plugins.TelemetryTable()); this.install(this.plugins.TelemetryTable.default());
this.install(PreviewPlugin.default()); this.install(PreviewPlugin.default());
this.install(LegacyIndicatorsPlugin()); this.install(LegacyIndicatorsPlugin());
this.install(LicensesPlugin.default()); this.install(LicensesPlugin.default());
@ -283,6 +283,7 @@ define([
this.install(this.plugins.NotificationIndicator()); this.install(this.plugins.NotificationIndicator());
this.install(this.plugins.NewFolderAction()); this.install(this.plugins.NewFolderAction());
this.install(this.plugins.ViewDatumAction()); this.install(this.plugins.ViewDatumAction());
this.install(this.plugins.ViewLargeAction());
this.install(this.plugins.ObjectInterceptors()); this.install(this.plugins.ObjectInterceptors());
this.install(this.plugins.NonEditableFolder()); this.install(this.plugins.NonEditableFolder());
} }

View File

@ -46,8 +46,6 @@ class ActionCollection extends EventEmitter {
this._observeObjectPath(); this._observeObjectPath();
this.openmct.editor.on('isEditing', this._updateActions); this.openmct.editor.on('isEditing', this._updateActions);
} }
this._initializeActions();
} }
disable(actionKeys) { disable(actionKeys) {
@ -156,19 +154,10 @@ class ActionCollection extends EventEmitter {
}); });
} }
_initializeActions() {
Object.keys(this.applicableActions).forEach(key => {
this.applicableActions[key].callBack = () => {
return this.applicableActions[key].invoke(this.objectPath, this.view);
};
});
}
_updateActions() { _updateActions() {
let newApplicableActions = this.openmct.actions._applicableActions(this.objectPath, this.view); let newApplicableActions = this.openmct.actions._applicableActions(this.objectPath, this.view);
this.applicableActions = this._mergeOldAndNewActions(this.applicableActions, newApplicableActions); this.applicableActions = this._mergeOldAndNewActions(this.applicableActions, newApplicableActions);
this._initializeActions();
this._update(); this._update();
} }

View File

@ -34,7 +34,7 @@ class ActionsAPI extends EventEmitter {
this._groupOrder = ['windowing', 'undefined', 'view', 'action', 'json']; this._groupOrder = ['windowing', 'undefined', 'view', 'action', 'json'];
this.register = this.register.bind(this); this.register = this.register.bind(this);
this.get = this.get.bind(this); this.getActionsCollection = this.getActionsCollection.bind(this);
this._applicableActions = this._applicableActions.bind(this); this._applicableActions = this._applicableActions.bind(this);
this._updateCachedActionCollections = this._updateCachedActionCollections.bind(this); this._updateCachedActionCollections = this._updateCachedActionCollections.bind(this);
} }
@ -43,12 +43,14 @@ class ActionsAPI extends EventEmitter {
this._allActions[actionDefinition.key] = actionDefinition; this._allActions[actionDefinition.key] = actionDefinition;
} }
get(objectPath, view) { getAction(key) {
if (view) { return this._allActions[key];
}
getActionsCollection(objectPath, view) {
if (view) {
return this._getCachedActionCollection(objectPath, view) || this._newActionCollection(objectPath, view, true); return this._getCachedActionCollection(objectPath, view) || this._newActionCollection(objectPath, view, true);
} else { } else {
return this._newActionCollection(objectPath, view, true); return this._newActionCollection(objectPath, view, true);
} }
} }
@ -57,15 +59,6 @@ class ActionsAPI extends EventEmitter {
this._groupOrder = groupArray; this._groupOrder = groupArray;
} }
_get(objectPath, view) {
let actionCollection = this._newActionCollection(objectPath, view);
this._actionCollections.set(view, actionCollection);
actionCollection.on('destroy', this._updateCachedActionCollections);
return actionCollection;
}
_getCachedActionCollection(objectPath, view) { _getCachedActionCollection(objectPath, view) {
let cachedActionCollection = this._actionCollections.get(view); let cachedActionCollection = this._actionCollections.get(view);
@ -75,7 +68,17 @@ class ActionsAPI extends EventEmitter {
_newActionCollection(objectPath, view, skipEnvironmentObservers) { _newActionCollection(objectPath, view, skipEnvironmentObservers) {
let applicableActions = this._applicableActions(objectPath, view); let applicableActions = this._applicableActions(objectPath, view);
return new ActionCollection(applicableActions, objectPath, view, this._openmct, skipEnvironmentObservers); const actionCollection = new ActionCollection(applicableActions, objectPath, view, this._openmct, skipEnvironmentObservers);
if (view) {
this._cacheActionCollection(view, actionCollection);
}
return actionCollection;
}
_cacheActionCollection(view, actionCollection) {
this._actionCollections.set(view, actionCollection);
actionCollection.on('destroy', this._updateCachedActionCollections);
} }
_updateCachedActionCollections(key) { _updateCachedActionCollections(key) {

View File

@ -106,7 +106,7 @@ describe('The Actions API', () => {
it("adds action to ActionsAPI", () => { it("adds action to ActionsAPI", () => {
actionsAPI.register(mockAction); actionsAPI.register(mockAction);
let actionCollection = actionsAPI.get(mockObjectPath, mockViewContext1); let actionCollection = actionsAPI.getActionsCollection(mockObjectPath, mockViewContext1);
let action = actionCollection.getActionsObject()[mockAction.key]; let action = actionCollection.getActionsObject()[mockAction.key];
expect(action.key).toEqual(mockAction.key); expect(action.key).toEqual(mockAction.key);
@ -121,21 +121,21 @@ describe('The Actions API', () => {
}); });
it("returns an ActionCollection when invoked with an objectPath only", () => { it("returns an ActionCollection when invoked with an objectPath only", () => {
let actionCollection = actionsAPI.get(mockObjectPath); let actionCollection = actionsAPI.getActionsCollection(mockObjectPath);
let instanceOfActionCollection = actionCollection instanceof ActionCollection; let instanceOfActionCollection = actionCollection instanceof ActionCollection;
expect(instanceOfActionCollection).toBeTrue(); expect(instanceOfActionCollection).toBeTrue();
}); });
it("returns an ActionCollection when invoked with an objectPath and view", () => { it("returns an ActionCollection when invoked with an objectPath and view", () => {
let actionCollection = actionsAPI.get(mockObjectPath, mockViewContext1); let actionCollection = actionsAPI.getActionsCollection(mockObjectPath, mockViewContext1);
let instanceOfActionCollection = actionCollection instanceof ActionCollection; let instanceOfActionCollection = actionCollection instanceof ActionCollection;
expect(instanceOfActionCollection).toBeTrue(); expect(instanceOfActionCollection).toBeTrue();
}); });
it("returns relevant actions when invoked with objectPath only", () => { it("returns relevant actions when invoked with objectPath only", () => {
let actionCollection = actionsAPI.get(mockObjectPath); let actionCollection = actionsAPI.getActionsCollection(mockObjectPath);
let action = actionCollection.getActionsObject()[mockObjectPathAction.key]; let action = actionCollection.getActionsObject()[mockObjectPathAction.key];
expect(action.key).toEqual(mockObjectPathAction.key); expect(action.key).toEqual(mockObjectPathAction.key);
@ -143,7 +143,7 @@ describe('The Actions API', () => {
}); });
it("returns relevant actions when invoked with objectPath and view", () => { it("returns relevant actions when invoked with objectPath and view", () => {
let actionCollection = actionsAPI.get(mockObjectPath, mockViewContext1); let actionCollection = actionsAPI.getActionsCollection(mockObjectPath, mockViewContext1);
let action = actionCollection.getActionsObject()[mockAction.key]; let action = actionCollection.getActionsObject()[mockAction.key];
expect(action.key).toEqual(mockAction.key); expect(action.key).toEqual(mockAction.key);

View File

@ -37,7 +37,7 @@ import Menu, { MENU_PLACEMENT } from './menu.js';
* @property {Boolean} isDisabled adds disable class if true * @property {Boolean} isDisabled adds disable class if true
* @property {String} name Menu item text * @property {String} name Menu item text
* @property {String} description Menu item description * @property {String} description Menu item description
* @property {Function} callBack callback function: invoked when item is clicked * @property {Function} onItemClicked callback function: invoked when item is clicked
*/ */
/** /**
@ -66,12 +66,27 @@ class MenuAPI {
* @param {Array.<Action>|Array.<Array.<Action>>} actions collection of actions{@link Action} or collection of groups of actions {@link Action} * @param {Array.<Action>|Array.<Array.<Action>>} actions collection of actions{@link Action} or collection of groups of actions {@link Action}
* @param {MenuOptions} [menuOptions] [Optional] The {@link MenuOptions} options for Menu * @param {MenuOptions} [menuOptions] [Optional] The {@link MenuOptions} options for Menu
*/ */
showMenu(x, y, actions, menuOptions) { showMenu(x, y, items, menuOptions) {
this._createMenuComponent(x, y, actions, menuOptions); this._createMenuComponent(x, y, items, menuOptions);
this.menuComponent.showMenu(); this.menuComponent.showMenu();
} }
actionsToMenuItems(actions, objectPath, view) {
return actions.map(action => {
const isActionGroup = Array.isArray(action);
if (isActionGroup) {
action = this.actionsToMenuItems(action, objectPath, view);
} else {
action.onItemClicked = () => {
action.invoke(objectPath, view);
};
}
return action;
});
}
/** /**
* Show popup menu with description of item on hover * Show popup menu with description of item on hover
* @param {number} x x-coordinates for popup * @param {number} x x-coordinates for popup

View File

@ -57,7 +57,7 @@ describe ('The Menu API', () => {
name: 'Test Action 1', name: 'Test Action 1',
cssClass: 'icon-clock', cssClass: 'icon-clock',
description: 'This is a test action', description: 'This is a test action',
callBack: () => { onItemClicked: () => {
result = 'Test Action 1 Invoked'; result = 'Test Action 1 Invoked';
} }
}, },
@ -66,7 +66,7 @@ describe ('The Menu API', () => {
name: 'Test Action 2', name: 'Test Action 2',
cssClass: 'icon-clock', cssClass: 'icon-clock',
description: 'This is a test action', description: 'This is a test action',
callBack: () => { onItemClicked: () => {
result = 'Test Action 2 Invoked'; result = 'Test Action 2 Invoked';
} }
} }

View File

@ -11,7 +11,7 @@
:key="action.name" :key="action.name"
:class="[action.cssClass, action.isDisabled ? 'disabled' : '']" :class="[action.cssClass, action.isDisabled ? 'disabled' : '']"
:title="action.description" :title="action.description"
@click="action.callBack" @click="action.onItemClicked"
> >
{{ action.name }} {{ action.name }}
</li> </li>
@ -36,7 +36,7 @@
:key="action.name" :key="action.name"
:class="action.cssClass" :class="action.cssClass"
:title="action.description" :title="action.description"
@click="action.callBack" @click="action.onItemClicked"
> >
{{ action.name }} {{ action.name }}
</li> </li>

View File

@ -13,7 +13,7 @@
:key="action.name" :key="action.name"
:class="[action.cssClass, action.isDisabled ? 'disabled' : '']" :class="[action.cssClass, action.isDisabled ? 'disabled' : '']"
:title="action.description" :title="action.description"
@click="action.callBack" @click="action.onItemClicked"
@mouseover="toggleItemDescription(action)" @mouseover="toggleItemDescription(action)"
@mouseleave="toggleItemDescription()" @mouseleave="toggleItemDescription()"
> >
@ -42,7 +42,7 @@
:key="action.name" :key="action.name"
:class="action.cssClass" :class="action.cssClass"
:title="action.description" :title="action.description"
@click="action.callBack" @click="action.onItemClicked"
@mouseover="toggleItemDescription(action)" @mouseover="toggleItemDescription(action)"
@mouseleave="toggleItemDescription()" @mouseleave="toggleItemDescription()"
> >

View File

@ -71,12 +71,12 @@ class Menu extends EventEmitter {
showMenu() { showMenu() {
this.component = new Vue({ this.component = new Vue({
provide: {
options: this.options
},
components: { components: {
MenuComponent MenuComponent
}, },
provide: {
options: this.options
},
template: '<menu-component />' template: '<menu-component />'
}); });
@ -85,12 +85,12 @@ class Menu extends EventEmitter {
showSuperMenu() { showSuperMenu() {
this.component = new Vue({ this.component = new Vue({
provide: {
options: this.options
},
components: { components: {
SuperMenuComponent SuperMenuComponent
}, },
provide: {
options: this.options
},
template: '<super-menu-component />' template: '<super-menu-component />'
}); });

View File

@ -19,8 +19,8 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import LadTableSet from './components/LadTableSet.vue';
import Vue from 'vue'; import LadTableSetView from './LadTableSetView';
export default function LADTableSetViewProvider(openmct) { export default function LADTableSetViewProvider(openmct) {
return { return {
@ -34,32 +34,7 @@ export default function LADTableSetViewProvider(openmct) {
return domainObject.type === 'LadTableSet'; return domainObject.type === 'LadTableSet';
}, },
view: function (domainObject, objectPath) { view: function (domainObject, objectPath) {
let component; return new LadTableSetView(openmct, domainObject, objectPath);
return {
show: function (element) {
component = new Vue({
el: element,
components: {
LadTableSet: LadTableSet
},
provide: {
openmct,
objectPath
},
data() {
return {
domainObject
};
},
template: '<lad-table-set :domain-object="domainObject"></lad-table-set>'
});
},
destroy: function (element) {
component.$destroy();
component = undefined;
}
};
}, },
priority: function () { priority: function () {
return 1; return 1;

View File

@ -0,0 +1,45 @@
import LadTable from './components/LADTable.vue';
import Vue from 'vue';
export default class LADTableView {
constructor(openmct, domainObject, objectPath) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.component = undefined;
}
show(element) {
this.component = new Vue({
el: element,
components: {
LadTable
},
provide: {
openmct: this.openmct,
currentView: this
},
data: () => {
return {
domainObject: this.domainObject,
objectPath: this.objectPath
};
},
template: '<lad-table ref="ladTable" :domain-object="domainObject" :object-path="objectPath"></lad-table>'
});
}
getViewContext() {
if (!this.component) {
return {};
}
return this.component.$refs.ladTable.getViewContext();
}
destroy(element) {
this.component.$destroy();
this.component = undefined;
}
}

View File

@ -19,50 +19,30 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import LadTable from './components/LADTable.vue';
import Vue from 'vue';
export default function LADTableViewProvider(openmct) { import LADTableView from './LADTableView';
return {
key: 'LadTable',
name: 'LAD Table',
cssClass: 'icon-tabular-lad',
canView: function (domainObject) {
return domainObject.type === 'LadTable';
},
canEdit: function (domainObject) {
return domainObject.type === 'LadTable';
},
view: function (domainObject, objectPath) {
let component;
return { export default class LADTableViewProvider {
show: function (element) { constructor(openmct) {
component = new Vue({ this.openmct = openmct;
el: element, this.name = 'LAD Table';
components: { this.key = 'LadTable';
LadTableComponent: LadTable this.cssClass = 'icon-tabular-lad';
},
provide: {
openmct
},
data: () => {
return {
domainObject,
objectPath
};
},
template: '<lad-table-component :domain-object="domainObject" :object-path="objectPath"></lad-table-component>'
});
},
destroy: function (element) {
component.$destroy();
component = undefined;
} }
};
}, canView(domainObject) {
priority: function () { return domainObject.type === 'LadTable';
}
canEdit(domainObject) {
return domainObject.type === 'LadTable';
}
view(domainObject, objectPath) {
return new LADTableView(this.openmct, domainObject, objectPath);
}
priority(domainObject) {
return 1; return 1;
} }
};
} }

View File

@ -0,0 +1,45 @@
import LadTableSet from './components/LadTableSet.vue';
import Vue from 'vue';
export default class LadTableSetView {
constructor(openmct, domainObject, objectPath) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.component = undefined;
}
show(element) {
this.component = new Vue({
el: element,
components: {
LadTableSet
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath,
currentView: this
},
data: () => {
return {
domainObject: this.domainObject
};
},
template: '<lad-table-set ref="ladTableSet" :domain-object="domainObject"></lad-table-set>'
});
}
getViewContext() {
if (!this.component) {
return {};
}
return this.component.$refs.ladTableSet.getViewContext();
}
destroy(element) {
this.component.$destroy();
this.component = undefined;
}
}

View File

@ -50,7 +50,7 @@ const CONTEXT_MENU_ACTIONS = [
]; ];
export default { export default {
inject: ['openmct'], inject: ['openmct', 'currentView'],
props: { props: {
domainObject: { domainObject: {
type: Object, type: Object,
@ -167,25 +167,23 @@ export default {
this.resetValues(); this.resetValues();
this.timestampKey = timeSystem.key; this.timestampKey = timeSystem.key;
}, },
getView() { updateViewContext() {
return { this.$emit('rowContextClick', {
getViewContext: () => {
return {
viewHistoricalData: true, viewHistoricalData: true,
viewDatumAction: true, viewDatumAction: true,
getDatum: () => { getDatum: () => {
return this.datum; return this.datum;
} }
}; });
}
};
}, },
showContextMenu(event) { showContextMenu(event) {
let actionCollection = this.openmct.actions.get(this.objectPath, this.getView()); this.updateViewContext();
let allActions = actionCollection.getActionsObject();
let applicableActions = CONTEXT_MENU_ACTIONS.map(key => allActions[key]);
this.openmct.menus.showMenu(event.x, event.y, applicableActions); const actions = CONTEXT_MENU_ACTIONS.map(key => this.openmct.actions.getAction(key));
const menuItems = this.openmct.menus.actionsToMenuItems(actions, this.objectPath, this.currentView);
if (menuItems.length) {
this.openmct.menus.showMenu(event.x, event.y, menuItems);
}
}, },
resetValues() { resetValues() {
this.value = '---'; this.value = '---';

View File

@ -38,6 +38,7 @@
:domain-object="ladRow.domainObject" :domain-object="ladRow.domainObject"
:path-to-table="objectPath" :path-to-table="objectPath"
:has-units="hasUnits" :has-units="hasUnits"
@rowContextClick="updateViewContext"
/> />
</tbody> </tbody>
</table> </table>
@ -51,7 +52,7 @@ export default {
components: { components: {
LadRow LadRow
}, },
inject: ['openmct'], inject: ['openmct', 'currentView'],
props: { props: {
domainObject: { domainObject: {
type: Object, type: Object,
@ -64,7 +65,8 @@ export default {
}, },
data() { data() {
return { return {
items: [] items: [],
viewContext: {}
}; };
}, },
computed: { computed: {
@ -114,6 +116,12 @@ export default {
let metadataWithUnits = valueMetadatas.filter(metadatum => metadatum.unit); let metadataWithUnits = valueMetadatas.filter(metadatum => metadatum.unit);
return metadataWithUnits.length > 0; return metadataWithUnits.length > 0;
},
updateViewContext(rowContext) {
this.viewContext.row = rowContext;
},
getViewContext() {
return this.viewContext;
} }
} }
}; };

View File

@ -48,6 +48,7 @@
:domain-object="ladRow.domainObject" :domain-object="ladRow.domainObject"
:path-to-table="ladTable.objectPath" :path-to-table="ladTable.objectPath"
:has-units="hasUnits" :has-units="hasUnits"
@rowContextClick="updateViewContext"
/> />
</template> </template>
</tbody> </tbody>
@ -61,7 +62,7 @@ export default {
components: { components: {
LadRow LadRow
}, },
inject: ['openmct', 'objectPath'], inject: ['openmct', 'objectPath', 'currentView'],
props: { props: {
domainObject: { domainObject: {
type: Object, type: Object,
@ -72,7 +73,8 @@ export default {
return { return {
ladTableObjects: [], ladTableObjects: [],
ladTelemetryObjects: {}, ladTelemetryObjects: {},
compositions: [] compositions: [],
viewContext: {}
}; };
}, },
computed: { computed: {
@ -166,6 +168,12 @@ export default {
this.$set(this.ladTelemetryObjects, ladTable.key, telemetryObjects); this.$set(this.ladTelemetryObjects, ladTable.key, telemetryObjects);
}; };
},
updateViewContext(rowContext) {
this.viewContext.row = rowContext;
},
getViewContext() {
return this.viewContext;
} }
} }
}; };

View File

@ -215,7 +215,8 @@ export default {
}, },
isEditing: { isEditing: {
type: Boolean, type: Boolean,
required: true required: true,
default: false
}, },
telemetry: { telemetry: {
type: Array, type: Array,

View File

@ -20,12 +20,49 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
define([ import AlphanumericFormat from './components/AlphanumericFormat.vue';
'./components/AlphanumericFormatView.vue',
'vue'
], function (AlphanumericFormatView, Vue) {
function AlphanumericFormatViewProvider(openmct, options) { import Vue from 'vue';
class AlphanumericFormatView {
constructor(openmct, domainObject, objectPath) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.component = undefined;
}
show(element) {
this.component = new Vue({
el: element,
name: 'AlphanumericFormat',
components: {
AlphanumericFormat
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath,
currentView: this
},
template: '<alphanumeric-format ref="alphanumericFormat"></alphanumeric-format>'
});
}
getViewContext() {
if (this.component) {
return {};
}
return this.component.$refs.alphanumericFormat.getViewContext();
}
destroy() {
this.component.$destroy();
this.component = undefined;
}
}
export default function AlphanumericFormatViewProvider(openmct, options) {
function isTelemetryObject(selectionPath) { function isTelemetryObject(selectionPath) {
let selectedObject = selectionPath[0].context.item; let selectedObject = selectionPath[0].context.item;
let parentObject = selectionPath[1].context.item; let parentObject = selectionPath[1].context.item;
@ -51,40 +88,10 @@ define([
return selection.every(isTelemetryObject); return selection.every(isTelemetryObject);
}, },
view: function (domainObject, objectPath) { view: function (domainObject, objectPath) {
let component; return new AlphanumericFormatView(openmct, domainObject, objectPath);
return {
show: function (element) {
component = new Vue({
el: element,
components: {
AlphanumericFormatView: AlphanumericFormatView.default
},
provide: {
openmct,
objectPath
},
template: '<alphanumeric-format-view ref="alphanumericFormatView"></alphanumeric-format-view>'
});
},
getViewContext() {
if (component) {
return component.$refs.alphanumericFormatView.getViewContext();
} else {
return {};
}
},
destroy: function () {
component.$destroy();
component = undefined;
}
};
}, },
priority: function () { priority: function () {
return 1; return 1;
} }
}; };
} }
return AlphanumericFormatViewProvider;
});

View File

@ -14,7 +14,7 @@ export default class CopyToClipboardAction {
invoke(objectPath, view = {}) { invoke(objectPath, view = {}) {
const viewContext = view.getViewContext && view.getViewContext(); const viewContext = view.getViewContext && view.getViewContext();
const formattedValue = viewContext.formattedValueForCopy(); const formattedValue = viewContext.row.formattedValueForCopy();
clipboard.updateClipboard(formattedValue) clipboard.updateClipboard(formattedValue)
.then(() => { .then(() => {
@ -26,9 +26,13 @@ export default class CopyToClipboardAction {
} }
appliesTo(objectPath, view = {}) { appliesTo(objectPath, view = {}) {
let viewContext = view.getViewContext && view.getViewContext(); const viewContext = view.getViewContext && view.getViewContext();
const row = viewContext && viewContext.row;
if (!row) {
return false;
}
return viewContext && viewContext.formattedValueForCopy return row.formattedValueForCopy
&& typeof viewContext.formattedValueForCopy === 'function'; && typeof row.formattedValueForCopy === 'function';
} }
} }

View File

@ -52,7 +52,8 @@
<script> <script>
export default { export default {
inject: ['openmct'], name: 'AlphanumericFormat',
inject: ['openmct', 'objectPath'],
data() { data() {
return { return {
isEditing: this.openmct.editor.isEditing(), isEditing: this.openmct.editor.isEditing(),

View File

@ -56,6 +56,7 @@
:index="index" :index="index"
:multi-select="selectedLayoutItems.length > 1" :multi-select="selectedLayoutItems.length > 1"
:is-editing="isEditing" :is-editing="isEditing"
@contextClick="updateViewContext"
@move="move" @move="move"
@endMove="endMove" @endMove="endMove"
@endLineResize="endLineResize" @endLineResize="endLineResize"
@ -140,7 +141,7 @@ function getItemDefinition(itemType, ...options) {
export default { export default {
components: components, components: components,
inject: ['openmct', 'options', 'objectPath'], inject: ['openmct', 'objectPath', 'options', 'objectUtils', 'currentView'],
props: { props: {
domainObject: { domainObject: {
type: Object, type: Object,
@ -155,7 +156,8 @@ export default {
return { return {
initSelectIndex: undefined, initSelectIndex: undefined,
selection: [], selection: [],
showGrid: true showGrid: true,
viewContext: {}
}; };
}, },
computed: { computed: {
@ -819,6 +821,12 @@ export default {
}, },
toggleGrid() { toggleGrid() {
this.showGrid = !this.showGrid; this.showGrid = !this.showGrid;
},
updateViewContext(viewContext) {
this.viewContext.row = viewContext;
},
getViewContext() {
return this.viewContext;
} }
} }
}; };

View File

@ -102,7 +102,7 @@ export default {
LayoutFrame LayoutFrame
}, },
mixins: [conditionalStylesMixin], mixins: [conditionalStylesMixin],
inject: ['openmct', 'objectPath'], inject: ['openmct', 'objectPath', 'currentView'],
props: { props: {
item: { item: {
type: Object, type: Object,
@ -294,16 +294,6 @@ export default {
this.requestHistoricalData(this.domainObject); this.requestHistoricalData(this.domainObject);
} }
}, },
getView() {
return {
getViewContext: () => {
return {
viewHistoricalData: true,
formattedValueForCopy: this.formattedValueForCopy
};
}
};
},
setObject(domainObject) { setObject(domainObject) {
this.domainObject = domainObject; this.domainObject = domainObject;
this.mutablePromise = undefined; this.mutablePromise = undefined;
@ -338,30 +328,38 @@ export default {
this.$emit('formatChanged', this.item, format); this.$emit('formatChanged', this.item, format);
}, },
updateViewContext() {
this.$emit('contextClick', {
viewHistoricalData: true,
formattedValueForCopy: this.formattedValueForCopy
});
},
async getContextMenuActions() { async getContextMenuActions() {
const defaultNotebook = getDefaultNotebook(); const defaultNotebook = getDefaultNotebook();
const domainObject = defaultNotebook && await this.openmct.objects.get(defaultNotebook.notebookMeta.identifier); const domainObject = defaultNotebook && await this.openmct.objects.get(defaultNotebook.notebookMeta.identifier);
const actionCollection = this.openmct.actions.get(this.currentObjectPath, this.getView());
const actionsObject = actionCollection.getActionsObject();
let copyToNotebookAction = actionsObject.copyToNotebook;
let defaultNotebookName;
if (defaultNotebook) { if (defaultNotebook) {
const defaultPath = domainObject && `${domainObject.name} - ${defaultNotebook.section.name} - ${defaultNotebook.page.name}`; const defaultPath = domainObject && `${domainObject.name} - ${defaultNotebook.section.name} - ${defaultNotebook.page.name}`;
copyToNotebookAction.name = `Copy to Notebook ${defaultPath}`; defaultNotebookName = `Copy to Notebook ${defaultPath}`;
} else {
actionsObject.copyToNotebook = undefined;
delete actionsObject.copyToNotebook;
} }
return CONTEXT_MENU_ACTIONS.map(actionKey => { return CONTEXT_MENU_ACTIONS
return actionsObject[actionKey]; .map(actionKey => {
}).filter(action => action !== undefined); const action = this.openmct.actions.getAction(actionKey);
if (action.key === 'copyToNotebook') {
action.name = defaultNotebookName;
}
return action;
})
.filter(action => action.name !== undefined);
}, },
async showContextMenu(event) { async showContextMenu(event) {
this.updateViewContext();
const contextMenuActions = await this.getContextMenuActions(); const contextMenuActions = await this.getContextMenuActions();
const menuItems = this.openmct.menus.actionsToMenuItems(contextMenuActions, this.currentObjectPath, this.currentView);
this.openmct.menus.showMenu(event.x, event.y, contextMenuActions); this.openmct.menus.showMenu(event.x, event.y, menuItems);
}, },
setStatus(status) { setStatus(status) {
this.status = status; this.status = status;

View File

@ -20,13 +20,81 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import Layout from './components/DisplayLayout.vue';
import Vue from 'vue';
import objectUtils from 'objectUtils';
import DisplayLayoutType from './DisplayLayoutType.js';
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js';
import AlphaNumericFormatViewProvider from './AlphanumericFormatViewProvider.js'; import AlphaNumericFormatViewProvider from './AlphanumericFormatViewProvider.js';
import CopyToClipboardAction from './actions/CopyToClipboardAction'; import CopyToClipboardAction from './actions/CopyToClipboardAction';
import DisplayLayout from './components/DisplayLayout.vue';
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js';
import DisplayLayoutType from './DisplayLayoutType.js';
import objectUtils from 'objectUtils';
import Vue from 'vue';
class DisplayLayoutView {
constructor(openmct, domainObject, objectPath, options) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.options = options;
this.component = undefined;
}
show(container, isEditing) {
this.component = new Vue({
el: container,
components: {
DisplayLayout
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath,
options: this.options,
objectUtils,
currentView: this
},
data: () => {
return {
domainObject: this.domainObject,
isEditing
};
},
template: '<display-layout ref="displayLayout" :domain-object="domainObject" :is-editing="isEditing"></display-layout>'
});
}
getViewContext() {
if (!this.component) {
return {};
}
return this.component.$refs.displayLayout.getViewContext();
}
getSelectionContext() {
return {
item: this.domainObject,
supportsMultiSelect: true,
addElement: this.component && this.component.$refs.displayLayout.addElement,
removeItem: this.component && this.component.$refs.displayLayout.removeItem,
orderItem: this.component && this.component.$refs.displayLayout.orderItem,
duplicateItem: this.component && this.component.$refs.displayLayout.duplicateItem,
switchViewType: this.component && this.component.$refs.displayLayout.switchViewType,
mergeMultipleTelemetryViews: this.component && this.component.$refs.displayLayout.mergeMultipleTelemetryViews,
mergeMultipleOverlayPlots: this.component && this.component.$refs.displayLayout.mergeMultipleOverlayPlots,
toggleGrid: this.component && this.component.$refs.displayLayout.toggleGrid
};
}
onEditModeChange(isEditing) {
this.component.isEditing = isEditing;
}
destroy() {
this.component.$destroy();
this.component = undefined;
}
}
export default function DisplayLayoutPlugin(options) { export default function DisplayLayoutPlugin(options) {
return function (openmct) { return function (openmct) {
@ -41,51 +109,7 @@ export default function DisplayLayoutPlugin(options) {
return domainObject.type === 'layout'; return domainObject.type === 'layout';
}, },
view: function (domainObject, objectPath) { view: function (domainObject, objectPath) {
let component; return new DisplayLayoutView(openmct, domainObject, objectPath, options);
return {
show(container) {
component = new Vue({
el: container,
components: {
Layout
},
provide: {
openmct,
objectUtils,
options,
objectPath
},
data() {
return {
domainObject: domainObject,
isEditing: openmct.editor.isEditing()
};
},
template: '<layout ref="displayLayout" :domain-object="domainObject" :is-editing="isEditing"></layout>'
});
},
getSelectionContext() {
return {
item: domainObject,
supportsMultiSelect: true,
addElement: component && component.$refs.displayLayout.addElement,
removeItem: component && component.$refs.displayLayout.removeItem,
orderItem: component && component.$refs.displayLayout.orderItem,
duplicateItem: component && component.$refs.displayLayout.duplicateItem,
switchViewType: component && component.$refs.displayLayout.switchViewType,
mergeMultipleTelemetryViews: component && component.$refs.displayLayout.mergeMultipleTelemetryViews,
mergeMultipleOverlayPlots: component && component.$refs.displayLayout.mergeMultipleOverlayPlots,
toggleGrid: component && component.$refs.displayLayout.toggleGrid
};
},
onEditModeChange: function (isEditing) {
component.isEditing = isEditing;
},
destroy() {
component.$destroy();
}
};
}, },
priority() { priority() {
return 100; return 100;

View File

@ -0,0 +1,37 @@
import ImageryViewLayout from './components/ImageryViewLayout.vue';
import Vue from 'vue';
export default class ImageryView {
constructor(openmct, domainObject, objectPath) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.component = undefined;
}
show(element) {
this.component = new Vue({
el: element,
components: {
ImageryViewLayout
},
provide: {
openmct: this.openmct,
domainObject: this.domainObject,
objectPath: this.objectPath,
currentView: this
},
template: '<imagery-view-layout ref="ImageryLayout"></imagery-view-layout>'
});
}
destroy() {
this.component.$destroy();
this.component = undefined;
}
_getInstance() {
return this.component;
}
}

View File

@ -19,9 +19,7 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import ImageryView from './ImageryView';
import ImageryViewLayout from './components/ImageryViewLayout.vue';
import Vue from 'vue';
export default function ImageryViewProvider(openmct) { export default function ImageryViewProvider(openmct) {
const type = 'example.imagery'; const type = 'example.imagery';
@ -42,31 +40,8 @@ export default function ImageryViewProvider(openmct) {
canView: function (domainObject) { canView: function (domainObject) {
return hasImageTelemetry(domainObject); return hasImageTelemetry(domainObject);
}, },
view: function (domainObject) { view: function (domainObject, objectPath) {
let component; return new ImageryView(openmct, domainObject, objectPath);
return {
show: function (element) {
component = new Vue({
el: element,
components: {
ImageryViewLayout
},
provide: {
openmct,
domainObject
},
template: '<imagery-view-layout ref="ImageryLayout"></imagery-view-layout>'
});
},
destroy: function () {
component.$destroy();
component = undefined;
},
_getInstance: function () {
return component;
}
};
} }
}; };
} }

View File

@ -58,6 +58,7 @@
<div ref="imageBG" <div ref="imageBG"
class="c-imagery__main-image__bg" class="c-imagery__main-image__bg"
:class="{'paused unnsynced': isPaused,'stale':false }" :class="{'paused unnsynced': isPaused,'stale':false }"
@click="expand"
> >
<div class="image-wrapper" <div class="image-wrapper"
:style="{ :style="{
@ -170,8 +171,9 @@
<script> <script>
import _ from 'lodash'; import _ from 'lodash';
import moment from 'moment'; import moment from 'moment';
import Compass from './Compass/Compass.vue';
import RelatedTelemetry from './RelatedTelemetry/RelatedTelemetry'; import RelatedTelemetry from './RelatedTelemetry/RelatedTelemetry';
import Compass from './Compass/Compass.vue';
const DEFAULT_DURATION_FORMATTER = 'duration'; const DEFAULT_DURATION_FORMATTER = 'duration';
const REFRESH_CSS_MS = 500; const REFRESH_CSS_MS = 500;
@ -195,7 +197,7 @@ export default {
components: { components: {
Compass Compass
}, },
inject: ['openmct', 'domainObject'], inject: ['openmct', 'domainObject', 'objectPath', 'currentView'],
data() { data() {
let timeSystem = this.openmct.time.timeSystem(); let timeSystem = this.openmct.time.timeSystem();
@ -468,6 +470,16 @@ export default {
} }
}, },
methods: { methods: {
expand() {
const actionCollection = this.openmct.actions.getActionsCollection(this.objectPath, this.currentView);
const visibleActions = actionCollection.getVisibleActions();
const viewLargeAction = visibleActions
&& visibleActions.find(action => action.key === 'large.view');
if (viewLargeAction && viewLargeAction.appliesTo(this.objectPath, this.currentView)) {
viewLargeAction.onItemClicked();
}
},
async initializeRelatedTelemetry() { async initializeRelatedTelemetry() {
this.relatedTelemetry = new RelatedTelemetry( this.relatedTelemetry = new RelatedTelemetry(
this.openmct, this.openmct,

View File

@ -25,16 +25,20 @@ export default class CopyToNotebookAction {
}); });
} }
invoke(objectPath, view = {}) { invoke(objectPath, view) {
let viewContext = view.getViewContext && view.getViewContext(); const formattedValueForCopy = view.getViewContext().row.formattedValueForCopy;
this.copyToNotebook(viewContext.formattedValueForCopy()); this.copyToNotebook(formattedValueForCopy());
} }
appliesTo(objectPath, view = {}) { appliesTo(objectPath, view = {}) {
let viewContext = view.getViewContext && view.getViewContext(); const viewContext = view.getViewContext && view.getViewContext();
const row = viewContext && viewContext.row;
if (!row) {
return;
}
return viewContext && viewContext.formattedValueForCopy return row.formattedValueForCopy
&& typeof viewContext.formattedValueForCopy === 'function'; && typeof row.formattedValueForCopy === 'function';
} }
} }

View File

@ -80,7 +80,7 @@ export default {
notebookTypes.push({ notebookTypes.push({
cssClass: 'icon-notebook', cssClass: 'icon-notebook',
name: `Save to Notebook ${defaultPath}`, name: `Save to Notebook ${defaultPath}`,
callBack: () => { onItemClicked: () => {
return this.snapshot(NOTEBOOK_DEFAULT); return this.snapshot(NOTEBOOK_DEFAULT);
} }
}); });
@ -89,7 +89,7 @@ export default {
notebookTypes.push({ notebookTypes.push({
cssClass: 'icon-camera', cssClass: 'icon-camera',
name: 'Save to Notebook Snapshots', name: 'Save to Notebook Snapshots',
callBack: () => { onItemClicked: () => {
return this.snapshot(NOTEBOOK_SNAPSHOT); return this.snapshot(NOTEBOOK_SNAPSHOT);
} }
}); });

View File

@ -63,6 +63,7 @@ define([
'./defaultRootName/plugin', './defaultRootName/plugin',
'./plan/plugin', './plan/plugin',
'./viewDatumAction/plugin', './viewDatumAction/plugin',
'./viewLargeAction/plugin',
'./interceptors/plugin', './interceptors/plugin',
'./performanceIndicator/plugin', './performanceIndicator/plugin',
'./CouchDBSearchFolder/plugin', './CouchDBSearchFolder/plugin',
@ -110,6 +111,7 @@ define([
DefaultRootName, DefaultRootName,
PlanLayout, PlanLayout,
ViewDatumAction, ViewDatumAction,
ViewLargeAction,
ObjectInterceptors, ObjectInterceptors,
PerformanceIndicator, PerformanceIndicator,
CouchDBSearchFolder, CouchDBSearchFolder,
@ -211,6 +213,7 @@ define([
plugins.DefaultRootName = DefaultRootName.default; plugins.DefaultRootName = DefaultRootName.default;
plugins.PlanLayout = PlanLayout.default; plugins.PlanLayout = PlanLayout.default;
plugins.ViewDatumAction = ViewDatumAction.default; plugins.ViewDatumAction = ViewDatumAction.default;
plugins.ViewLargeAction = ViewLargeAction.default;
plugins.ObjectInterceptors = ObjectInterceptors.default; plugins.ObjectInterceptors = ObjectInterceptors.default;
plugins.PerformanceIndicator = PerformanceIndicator.default; plugins.PerformanceIndicator = PerformanceIndicator.default;
plugins.CouchDBSearchFolder = CouchDBSearchFolder.default; plugins.CouchDBSearchFolder = CouchDBSearchFolder.default;

View File

@ -0,0 +1,67 @@
import TableComponent from './components/table.vue';
import TelemetryTable from './TelemetryTable';
import Vue from 'vue';
export default class TelemetryTableView {
constructor(openmct, domainObject, objectPath) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.component = undefined;
this.table = new TelemetryTable(domainObject, openmct);
}
getViewContext() {
if (!this.component) {
return {};
}
return this.component.$refs.tableComponent.getViewContext();
}
onEditModeChange(editMode) {
this.component.isEditing = editMode;
}
onClearData() {
this.table.clearData();
}
getTable() {
return this.table;
}
destroy(element) {
this.component.$destroy();
this.component = undefined;
}
show(element, editMode) {
this.component = new Vue({
el: element,
components: {
TableComponent
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath,
table: this.table,
currentView: this
},
data() {
return {
isEditing: editMode,
marking: {
disableMultiSelect: false,
enable: true,
rowName: '',
rowNamePlural: '',
useAlternateControlBar: false
}
};
},
template: '<table-component ref="tableComponent" :is-editing="isEditing" :marking="marking"></table-component>'
});
}
}

View File

@ -20,16 +20,9 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
define([ import TelemetryTableView from './TelemetryTableView';
'./components/table.vue',
'./TelemetryTable', export default function TelemetryTableViewProvider(openmct) {
'vue'
], function (
TableComponent,
TelemetryTable,
Vue
) {
function TelemetryTableViewProvider(openmct) {
function hasTelemetry(domainObject) { function hasTelemetry(domainObject) {
if (!Object.prototype.hasOwnProperty.call(domainObject, 'telemetry')) { if (!Object.prototype.hasOwnProperty.call(domainObject, 'telemetry')) {
return false; return false;
@ -52,67 +45,10 @@ define([
return domainObject.type === 'table'; return domainObject.type === 'table';
}, },
view(domainObject, objectPath) { view(domainObject, objectPath) {
let table = new TelemetryTable(domainObject, openmct); return new TelemetryTableView(openmct, domainObject, objectPath);
let component;
let markingProp = {
enable: true,
useAlternateControlBar: false,
rowName: '',
rowNamePlural: ''
};
const view = {
show: function (element, editMode) {
component = new Vue({
el: element,
components: {
TableComponent: TableComponent.default
},
provide: {
openmct,
table,
objectPath
},
data() {
return {
isEditing: editMode,
markingProp,
view
};
},
template: '<table-component ref="tableComponent" :isEditing="isEditing" :marking="markingProp" :view="view"/>'
});
},
onEditModeChange(editMode) {
component.isEditing = editMode;
},
onClearData() {
table.clearData();
},
getViewContext() {
if (component) {
return component.$refs.tableComponent.getViewContext();
} else {
return {
type: 'telemetry-table'
};
}
},
destroy: function (element) {
component.$destroy();
component = undefined;
},
_getTable: function () {
return table;
}
};
return view;
}, },
priority() { priority() {
return 1; return 1;
} }
}; };
} }
return TelemetryTableViewProvider;
});

View File

@ -20,83 +20,89 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
let exportCSV = { const exportCSV = {
name: 'Export Table Data', name: 'Export Table Data',
key: 'export-csv-all', key: 'export-csv-all',
description: "Export this view's data", description: "Export this view's data",
cssClass: 'icon-download labeled', cssClass: 'icon-download labeled',
invoke: (objectPath, viewProvider) => { invoke: (objectPath, view) => {
viewProvider.getViewContext().exportAllDataAsCSV(); view.getViewContext().exportAllDataAsCSV();
}, },
group: 'view' group: 'view'
}; };
let exportMarkedDataAsCSV = {
const exportMarkedDataAsCSV = {
name: 'Export Marked Rows', name: 'Export Marked Rows',
key: 'export-csv-marked', key: 'export-csv-marked',
description: "Export marked rows as CSV", description: "Export marked rows as CSV",
cssClass: 'icon-download labeled', cssClass: 'icon-download labeled',
invoke: (objectPath, viewProvider) => { invoke: (objectPath, view) => {
viewProvider.getViewContext().exportMarkedDataAsCSV(); view.getViewContext().exportMarkedDataAsCSV();
}, },
group: 'view' group: 'view'
}; };
let unmarkAllRows = {
const unmarkAllRows = {
name: 'Unmark All Rows', name: 'Unmark All Rows',
key: 'unmark-all-rows', key: 'unmark-all-rows',
description: 'Unmark all rows', description: 'Unmark all rows',
cssClass: 'icon-x labeled', cssClass: 'icon-x labeled',
invoke: (objectPath, viewProvider) => { invoke: (objectPath, view) => {
viewProvider.getViewContext().unmarkAllRows(); view.getViewContext().unmarkAllRows();
},
showInStatusBar: true,
group: 'view'
};
let pause = {
name: 'Pause',
key: 'pause-data',
description: 'Pause real-time data flow',
cssClass: 'icon-pause',
invoke: (objectPath, viewProvider) => {
viewProvider.getViewContext().togglePauseByButton();
},
showInStatusBar: true,
group: 'view'
};
let play = {
name: 'Play',
key: 'play-data',
description: 'Continue real-time data flow',
cssClass: 'c-button pause-play is-paused',
invoke: (objectPath, viewProvider) => {
viewProvider.getViewContext().togglePauseByButton();
},
showInStatusBar: true,
group: 'view'
};
let expandColumns = {
name: 'Expand Columns',
key: 'expand-columns',
description: "Increase column widths to fit currently available data.",
cssClass: 'icon-arrows-right-left labeled',
invoke: (objectPath, viewProvider) => {
viewProvider.getViewContext().expandColumns();
},
showInStatusBar: true,
group: 'view'
};
let autosizeColumns = {
name: 'Autosize Columns',
key: 'autosize-columns',
description: "Automatically size columns to fit the table into the available space.",
cssClass: 'icon-expand labeled',
invoke: (objectPath, viewProvider) => {
viewProvider.getViewContext().autosizeColumns();
}, },
showInStatusBar: true, showInStatusBar: true,
group: 'view' group: 'view'
}; };
let viewActions = [ const pause = {
name: 'Pause',
key: 'pause-data',
description: 'Pause real-time data flow',
cssClass: 'icon-pause',
invoke: (objectPath, view) => {
view.getViewContext().togglePauseByButton();
},
showInStatusBar: true,
group: 'view'
};
const play = {
name: 'Play',
key: 'play-data',
description: 'Continue real-time data flow',
cssClass: 'c-button pause-play is-paused',
invoke: (objectPath, view) => {
view.getViewContext().togglePauseByButton();
},
showInStatusBar: true,
group: 'view'
};
const expandColumns = {
name: 'Expand Columns',
key: 'expand-columns',
description: "Increase column widths to fit currently available data.",
cssClass: 'icon-arrows-right-left labeled',
invoke: (objectPath, view) => {
view.getViewContext().expandColumns();
},
showInStatusBar: true,
group: 'view'
};
const autosizeColumns = {
name: 'Autosize Columns',
key: 'autosize-columns',
description: "Automatically size columns to fit the table into the available space.",
cssClass: 'icon-expand labeled',
invoke: (objectPath, view) => {
view.getViewContext().autosizeColumns();
},
showInStatusBar: true,
group: 'view'
};
const viewActions = [
exportCSV, exportCSV,
exportMarkedDataAsCSV, exportMarkedDataAsCSV,
unmarkAllRows, unmarkAllRows,
@ -107,16 +113,13 @@ let viewActions = [
]; ];
viewActions.forEach(action => { viewActions.forEach(action => {
action.appliesTo = (objectPath, viewProvider = {}) => { action.appliesTo = (objectPath, view = {}) => {
let viewContext = viewProvider.getViewContext && viewProvider.getViewContext(); const viewContext = view.getViewContext && view.getViewContext();
if (!viewContext) {
if (viewContext) { return false;
let type = viewContext.type;
return type === 'telemetry-table';
} }
return false; return viewContext.type === 'telemetry-table';
}; };
}); });

View File

@ -49,7 +49,7 @@ export default {
components: { components: {
TableCell TableCell
}, },
inject: ['openmct'], inject: ['openmct', 'currentView'],
props: { props: {
headers: { headers: {
type: Object, type: Object,
@ -97,16 +97,7 @@ export default {
selectable[columnKeys] = this.row.columns[columnKeys].selectable; selectable[columnKeys] = this.row.columns[columnKeys].selectable;
return selectable; return selectable;
}, {}), }, {})
actionsViewContext: {
getViewContext: () => {
return {
viewHistoricalData: true,
viewDatumAction: true,
getDatum: this.getDatum
};
}
}
}; };
}, },
computed: { computed: {
@ -187,19 +178,20 @@ export default {
showContextMenu: function (event) { showContextMenu: function (event) {
event.preventDefault(); event.preventDefault();
this.updateViewContext();
this.markRow(event); this.markRow(event);
this.row.getContextualDomainObject(this.openmct, this.row.objectKeyString).then(domainObject => { const actions = this.row.getContextMenuActions().map(key => this.openmct.actions.getAction(key));
let contextualObjectPath = this.objectPath.slice(); const menuItems = this.openmct.menus.actionsToMenuItems(actions, this.objectPath, this.currentView);
contextualObjectPath.unshift(domainObject); if (menuItems.length) {
this.openmct.menus.showMenu(event.x, event.y, menuItems);
let actionsCollection = this.openmct.actions.get(contextualObjectPath, this.actionsViewContext);
let allActions = actionsCollection.getActionsObject();
let applicableActions = this.row.getContextMenuActions().map(key => allActions[key]);
if (applicableActions.length) {
this.openmct.menus.showMenu(event.x, event.y, applicableActions);
} }
},
updateViewContext() {
this.$emit('rowContextClick', {
viewHistoricalData: true,
viewDatumAction: true,
getDatum: this.getDatum
}); });
} }
} }

View File

@ -233,6 +233,7 @@
@mark="markRow" @mark="markRow"
@unmark="unmarkRow" @unmark="unmarkRow"
@markMultipleConcurrent="markMultipleConcurrentRows" @markMultipleConcurrent="markMultipleConcurrentRows"
@rowContextClick="updateViewContext"
/> />
</tbody> </tbody>
</table> </table>
@ -263,6 +264,7 @@
:column-widths="configuredColumnWidths" :column-widths="configuredColumnWidths"
:row="sizingRowData" :row="sizingRowData"
:object-path="objectPath" :object-path="objectPath"
@rowContextClick="updateViewContext"
/> />
</table> </table>
<table-footer-indicator <table-footer-indicator
@ -298,12 +300,25 @@ export default {
ToggleSwitch, ToggleSwitch,
SizingRow SizingRow
}, },
inject: ['table', 'openmct', 'objectPath'], inject: ['openmct', 'objectPath', 'table', 'currentView'],
props: { props: {
isEditing: { isEditing: {
type: Boolean, type: Boolean,
default: false default: false
}, },
marking: {
type: Object,
required: true,
default() {
return {
enable: false,
disableMultiSelect: false,
useAlternateControlBar: false,
rowName: '',
rowNamePlural: ''
};
}
},
allowExport: { allowExport: {
type: Boolean, type: Boolean,
default: true default: true
@ -316,28 +331,9 @@ export default {
type: Boolean, type: Boolean,
default: true default: true
}, },
marking: {
type: Object,
default() {
return {
enable: false,
disableMultiSelect: false,
useAlternateControlBar: false,
rowName: '',
rowNamePlural: ""
};
}
},
enableLegacyToolbar: { enableLegacyToolbar: {
type: Boolean, type: Boolean,
default: false default: false
},
view: {
type: Object,
required: false,
default() {
return {};
}
} }
}, },
data() { data() {
@ -373,7 +369,8 @@ export default {
isShowingMarkedRowsOnly: false, isShowingMarkedRowsOnly: false,
enableRegexSearch: {}, enableRegexSearch: {},
hideHeaders: configuration.hideHeaders, hideHeaders: configuration.hideHeaders,
totalNumberOfRows: 0 totalNumberOfRows: 0,
rowContext: {}
}; };
}, },
computed: { computed: {
@ -461,8 +458,10 @@ export default {
this.scroll = _.throttle(this.scroll, 100); this.scroll = _.throttle(this.scroll, 100);
if (!this.marking.useAlternateControlBar && !this.enableLegacyToolbar) { if (!this.marking.useAlternateControlBar && !this.enableLegacyToolbar) {
this.viewActionsCollection = this.openmct.actions.get(this.objectPath, this.view); this.$nextTick(() => {
this.viewActionsCollection = this.openmct.actions.getActionsCollection(this.objectPath, this.currentView);
this.initializeViewActions(); this.initializeViewActions();
});
} }
this.table.on('object-added', this.addObject); this.table.on('object-added', this.addObject);
@ -996,7 +995,8 @@ export default {
unmarkAllRows: this.unmarkAllRows, unmarkAllRows: this.unmarkAllRows,
togglePauseByButton: this.togglePauseByButton, togglePauseByButton: this.togglePauseByButton,
expandColumns: this.recalculateColumnWidths, expandColumns: this.recalculateColumnWidths,
autosizeColumns: this.autosizeColumns autosizeColumns: this.autosizeColumns,
row: this.rowContext
}; };
}, },
initializeViewActions() { initializeViewActions() {
@ -1027,6 +1027,9 @@ export default {
this.setHeight(); this.setHeight();
this.calculateTableSize(); this.calculateTableSize();
this.clearRowsAndRerender(); this.clearRowsAndRerender();
},
updateViewContext(rowContext) {
this.rowContext = rowContext;
} }
} }
}; };

View File

@ -19,19 +19,12 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import TelemetryTableViewProvider from './TelemetryTableViewProvider';
import TableConfigurationViewProvider from './TableConfigurationViewProvider';
import TelemetryTableType from './TelemetryTableType';
import TelemetryTableViewActions from './ViewActions';
define([ export default function plugin() {
'./TelemetryTableViewProvider',
'./TableConfigurationViewProvider',
'./TelemetryTableType',
'./ViewActions'
], function (
TelemetryTableViewProvider,
TableConfigurationViewProvider,
TelemetryTableType,
TelemetryTableViewActions
) {
return function plugin() {
return function install(openmct) { return function install(openmct) {
openmct.objectViews.addProvider(new TelemetryTableViewProvider(openmct)); openmct.objectViews.addProvider(new TelemetryTableViewProvider(openmct));
openmct.inspectorViews.addProvider(new TableConfigurationViewProvider(openmct)); openmct.inspectorViews.addProvider(new TableConfigurationViewProvider(openmct));
@ -44,9 +37,8 @@ define([
} }
}); });
TelemetryTableViewActions.default.forEach(action => { TelemetryTableViewActions.forEach(action => {
openmct.actions.register(action); openmct.actions.register(action);
}); });
}; };
}; }
});

View File

@ -203,7 +203,7 @@ describe("the plugin", () => {
tableView = tableViewProvider.view(testTelemetryObject, [testTelemetryObject]); tableView = tableViewProvider.view(testTelemetryObject, [testTelemetryObject]);
tableView.show(child, true); tableView.show(child, true);
tableInstance = tableView._getTable(); tableInstance = tableView.getTable();
return telemetryPromise.then(() => Vue.nextTick()); return telemetryPromise.then(() => Vue.nextTick());
}); });

View File

@ -151,7 +151,7 @@ export default {
cssClass: 'icon-history', cssClass: 'icon-history',
name, name,
description, description,
callBack: () => this.selectTimespan(timespan) onItemClicked: () => this.selectTimespan(timespan)
}; };
}); });
@ -160,7 +160,7 @@ export default {
description: 'Past timeframes, ordered by latest first', description: 'Past timeframes, ordered by latest first',
isDisabled: true, isDisabled: true,
name: 'Past timeframes, ordered by latest first', name: 'Past timeframes, ordered by latest first',
callBack: () => {} onItemClicked: () => {}
}); });
return history; return history;
@ -171,7 +171,7 @@ export default {
cssClass: 'icon-clock', cssClass: 'icon-clock',
name: preset.label, name: preset.label,
description: preset.label, description: preset.label,
callBack: () => this.selectPresetBounds(preset.bounds) onItemClicked: () => this.selectPresetBounds(preset.bounds)
}; };
}); });
}, },

View File

@ -104,7 +104,7 @@ export default {
name: 'Fixed Timespan', name: 'Fixed Timespan',
description: 'Query and explore data that falls between two fixed datetimes.', description: 'Query and explore data that falls between two fixed datetimes.',
cssClass: 'icon-tabular', cssClass: 'icon-tabular',
callBack: () => this.setOption(key) onItemClicked: () => this.setOption(key)
}; };
} else { } else {
const key = clock.key; const key = clock.key;
@ -115,7 +115,7 @@ export default {
description: "Monitor streaming data in real-time. The Time " description: "Monitor streaming data in real-time. The Time "
+ "Conductor and displays will automatically advance themselves based on this clock. " + clock.description, + "Conductor and displays will automatically advance themselves based on this clock. " + clock.description,
cssClass: clock.cssClass || 'icon-clock', cssClass: clock.cssClass || 'icon-clock',
callBack: () => this.setOption(key) onItemClicked: () => this.setOption(key)
}; };
} }
}, },

View File

@ -70,7 +70,7 @@ export default {
.filter(menuOption => menuOption.clock === (clock && clock.key)) .filter(menuOption => menuOption.clock === (clock && clock.key))
.map(menuOption => { .map(menuOption => {
const timeSystem = JSON.parse(JSON.stringify(this.openmct.time.timeSystems.get(menuOption.timeSystem))); const timeSystem = JSON.parse(JSON.stringify(this.openmct.time.timeSystems.get(menuOption.timeSystem)));
timeSystem.callBack = () => this.setTimeSystemFromView(timeSystem); timeSystem.onItemClicked = () => this.setTimeSystemFromView(timeSystem);
return timeSystem; return timeSystem;
}); });

View File

@ -34,15 +34,16 @@ export default class ViewDatumAction {
} }
invoke(objectPath, view) { invoke(objectPath, view) {
let viewContext = view.getViewContext && view.getViewContext(); let viewContext = view.getViewContext && view.getViewContext();
let attributes = viewContext.getDatum && viewContext.getDatum(); const row = viewContext.row;
let attributes = row.getDatum && row.getDatum();
let component = new Vue ({ let component = new Vue ({
components: {
MetadataListView
},
provide: { provide: {
name: this.name, name: this.name,
attributes attributes
}, },
components: {
MetadataListView
},
template: '<MetadataListView />' template: '<MetadataListView />'
}); });
@ -57,9 +58,13 @@ export default class ViewDatumAction {
} }
appliesTo(objectPath, view = {}) { appliesTo(objectPath, view = {}) {
let viewContext = (view.getViewContext && view.getViewContext()) || {}; let viewContext = (view.getViewContext && view.getViewContext()) || {};
let datum = viewContext.getDatum; const row = viewContext.row;
let enabled = viewContext.viewDatumAction; if (!row) {
return false;
}
let datum = row.getDatum;
let enabled = row.viewDatumAction;
if (enabled && datum) { if (enabled && datum) {
return true; return true;
} }

View File

@ -57,10 +57,12 @@ describe("the plugin", () => {
mockView = { mockView = {
getViewContext: () => { getViewContext: () => {
return { return {
row: {
viewDatumAction: true, viewDatumAction: true,
getDatum: () => { getDatum: () => {
return mockDatum; return mockDatum;
} }
}
}; };
} }
}; };

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 ViewLargeAction from './viewLargeAction.js';
export default function plugin() {
return function install(openmct) {
openmct.actions.register(new ViewLargeAction(openmct));
};
}

View File

@ -0,0 +1,115 @@
/*****************************************************************************
* 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 PreviewHeader from '@/ui/preview/preview-header.vue';
import Vue from 'vue';
export default class ViewLargeAction {
constructor(openmct) {
this.openmct = openmct;
this.cssClass = 'icon-items-expand';
this.description = 'View Large';
this.group = 'windowing';
this.key = 'large.view';
this.name = 'Large View';
this.priority = 1;
this.showInStatusBar = true;
}
invoke(objectPath, view) {
const parentElement = view.parentElement;
let childElement = parentElement && parentElement.firstChild;
if (!childElement) {
const message = "ViewLargeAction: missing element";
this.openmct.notifications.error(message);
throw new Error(message);
}
this._expand(objectPath, childElement, view);
}
appliesTo(objectPath, view = {}) {
const parentElement = view.parentElement;
const element = parentElement && parentElement.firstChild;
const viewLargeAction = element && !element.classList.contains('js-main-container')
&& !this._isNavigatedObject(objectPath);
return viewLargeAction;
}
_expand(objectPath, childElement, view) {
const parentElement = childElement.parentElement;
this.overlay = this.openmct.overlays.overlay({
element: this._getOverlayElement(objectPath, childElement, view),
size: 'large',
onDestroy() {
parentElement.append(childElement);
}
});
}
_getOverlayElement(objectPath, childElement, view) {
const fragment = new DocumentFragment();
const header = this._getPreviewHeader(objectPath, view);
fragment.append(header);
const wrapper = document.createElement('div');
wrapper.classList.add('l-preview-window__object-view');
wrapper.append(childElement);
fragment.append(wrapper);
return fragment;
}
_getPreviewHeader(objectPath, view) {
const domainObject = objectPath[0];
const actionCollection = this.openmct.actions.getActionsCollection(objectPath, view);
const preview = new Vue({
components: {
PreviewHeader
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath
},
data() {
return {
domainObject,
actionCollection
};
},
template: '<PreviewHeader :actionCollection="actionCollection" :domainObject="domainObject" :hideViewSwitcher="true" :showNotebookMenuSwitcher="true"></PreviewHeader>'
});
return preview.$mount().$el;
}
_isNavigatedObject(objectPath) {
let targetObject = objectPath[0];
let navigatedObject = this.openmct.router.path[0];
return this.openmct.objects.areIdsEqual(targetObject.identifier, navigatedObject.identifier);
}
}

View File

@ -56,26 +56,19 @@
'has-complex-content': complexContent 'has-complex-content': complexContent
}" }"
> >
<div class="c-so-view__frame-controls__btns"> <div v-if="statusBarItems.length > 0"
class="c-so-view__frame-controls__btns"
>
<button <button
v-for="(item, index) in statusBarItems" v-for="(item, index) in statusBarItems"
:key="index" :key="index"
class="c-icon-button" class="c-icon-button"
:class="item.cssClass" :class="item.cssClass"
:title="item.name" :title="item.name"
@click="item.callBack" @click="item.onItemClicked"
> >
<span class="c-icon-button__label">{{ item.name }}</span> <span class="c-icon-button__label">{{ item.name }}</span>
</button> </button>
<button
class="c-icon-button icon-items-expand"
title="View Large"
@click="expand"
>
<span class="c-icon-button__label">View Large</span>
</button>
</div> </div>
<button <button
class="c-icon-button icon-3-dots c-so-view__frame-controls__more" class="c-icon-button icon-3-dots c-so-view__frame-controls__more"
@ -87,7 +80,7 @@
<object-view <object-view
ref="objectView" ref="objectView"
class="c-so-view__object-view" class="c-so-view__object-view js-object-view"
:show-edit-view="showEditView" :show-edit-view="showEditView"
:object-path="objectPath" :object-path="objectPath"
:layout-font-size="layoutFontSize" :layout-font-size="layoutFontSize"
@ -99,8 +92,6 @@
<script> <script>
import ObjectView from './ObjectView.vue'; import ObjectView from './ObjectView.vue';
import PreviewHeader from '@/ui/preview/preview-header.vue';
import Vue from 'vue';
const SIMPLE_CONTENT_TYPES = [ const SIMPLE_CONTENT_TYPES = [
'clock', 'clock',
@ -160,7 +151,8 @@ export default {
mounted() { mounted() {
this.status = this.openmct.status.get(this.domainObject.identifier); this.status = this.openmct.status.get(this.domainObject.identifier);
this.removeStatusListener = this.openmct.status.observe(this.domainObject.identifier, this.setStatus); this.removeStatusListener = this.openmct.status.observe(this.domainObject.identifier, this.setStatus);
this.$refs.objectView.show(this.domainObject, undefined, false, this.objectPath); const provider = this.openmct.objectViews.get(this.domainObject, this.objectPath)[0];
this.$refs.objectView.show(this.domainObject, provider.key, false, this.objectPath);
}, },
beforeDestroy() { beforeDestroy() {
this.removeStatusListener(); this.removeStatusListener();
@ -170,52 +162,6 @@ export default {
} }
}, },
methods: { methods: {
expand() {
let objectView = this.$refs.objectView;
let parentElement = objectView.$el;
let childElement = parentElement.children[0];
this.openmct.overlays.overlay({
element: this.getOverlayElement(childElement),
size: 'large',
onDestroy() {
parentElement.append(childElement);
}
});
},
getOverlayElement(childElement) {
const fragment = new DocumentFragment();
const header = this.getPreviewHeader();
const wrapper = document.createElement('div');
wrapper.classList.add('l-preview-window__object-view');
wrapper.append(childElement);
fragment.append(header);
fragment.append(wrapper);
return fragment;
},
getPreviewHeader() {
const domainObject = this.objectPath[0];
const actionCollection = this.actionCollection;
const preview = new Vue({
components: {
PreviewHeader
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath
},
data() {
return {
domainObject,
actionCollection
};
},
template: '<PreviewHeader :actionCollection="actionCollection" :domainObject="domainObject" :hideViewSwitcher="true" :showNotebookMenuSwitcher="true"></PreviewHeader>'
});
return preview.$mount().$el;
},
getSelectionContext() { getSelectionContext() {
return this.$refs.objectView.getSelectionContext(); return this.$refs.objectView.getSelectionContext();
}, },
@ -233,12 +179,14 @@ export default {
delete this.actionCollection; delete this.actionCollection;
}, },
updateActionItems(actionItems) { updateActionItems(actionItems) {
this.statusBarItems = this.actionCollection.getStatusBarActions(); const statusBarItems = this.actionCollection.getStatusBarActions();
this.statusBarItems = this.openmct.menus.actionsToMenuItems(statusBarItems, this.actionCollection.objectPath, this.actionCollection.view);
this.menuActionItems = this.actionCollection.getVisibleActions(); this.menuActionItems = this.actionCollection.getVisibleActions();
}, },
showMenuItems(event) { showMenuItems(event) {
let sortedActions = this.openmct.actions._groupAndSortActions(this.menuActionItems); const sortedActions = this.openmct.actions._groupAndSortActions(this.menuActionItems);
this.openmct.menus.showMenu(event.x, event.y, sortedActions); const menuItems = this.openmct.menus.actionsToMenuItems(sortedActions, this.actionCollection.objectPath, this.actionCollection.view);
this.openmct.menus.showMenu(event.x, event.y, menuItems);
}, },
setStatus(status) { setStatus(status) {
this.status = status; this.status = status;

View File

@ -209,7 +209,6 @@ export default {
} }
} }
this.getActionCollection();
this.currentView.show(this.viewContainer, this.openmct.editor.isEditing()); this.currentView.show(this.viewContainer, this.openmct.editor.isEditing());
if (immediatelySelect) { if (immediatelySelect) {
@ -218,13 +217,17 @@ export default {
} }
this.openmct.objectViews.on('clearData', this.clearData); this.openmct.objectViews.on('clearData', this.clearData);
this.$nextTick(() => {
this.getActionCollection();
});
}, },
getActionCollection() { getActionCollection() {
if (this.actionCollection) { if (this.actionCollection) {
this.actionCollection.destroy(); this.actionCollection.destroy();
} }
this.actionCollection = this.openmct.actions._get(this.currentObjectPath || this.objectPath, this.currentView); this.actionCollection = this.openmct.actions.getActionsCollection(this.currentObjectPath || this.objectPath, this.currentView);
this.$emit('change-action-collection', this.actionCollection); this.$emit('change-action-collection', this.actionCollection);
}, },
show(object, viewKey, immediatelySelect, currentObjectPath) { show(object, viewKey, immediatelySelect, currentObjectPath) {
@ -318,7 +321,6 @@ export default {
return viewKey; return viewKey;
}, },
getViewProvider() { getViewProvider() {
let provider = this.openmct.objectViews.getByProviderKey(this.getViewKey()); let provider = this.openmct.objectViews.getByProviderKey(this.getViewKey());
if (!provider) { if (!provider) {

View File

@ -63,7 +63,7 @@ export default {
cssClass: font.cssClass || '', cssClass: font.cssClass || '',
name: font.name, name: font.name,
description: font.name, description: font.name,
callBack: () => this.setFont(font.value) onItemClicked: () => this.setFont(font.value)
}; };
}); });
}, },
@ -73,7 +73,7 @@ export default {
cssClass: fontSize.cssClass || '', cssClass: fontSize.cssClass || '',
name: fontSize.name, name: fontSize.name,
description: fontSize.name, description: fontSize.name,
callBack: () => this.setFontSize(fontSize.value) onItemClicked: () => this.setFontSize(fontSize.value)
}; };
}); });
} }

View File

@ -32,7 +32,7 @@
</div> </div>
<div class="l-browse-bar__end"> <div class="l-browse-bar__end">
<view-switcher <ViewSwitcher
v-if="!isEditing" v-if="!isEditing"
:current-view="currentView" :current-view="currentView"
:views="views" :views="views"
@ -49,7 +49,7 @@
:key="index" :key="index"
class="c-button" class="c-button"
:class="item.cssClass" :class="item.cssClass"
@click="item.callBack" @click="item.onItemClicked"
> >
</button> </button>
@ -172,9 +172,7 @@ export default {
key: p.key, key: p.key,
cssClass: p.cssClass, cssClass: p.cssClass,
name: p.name, name: p.name,
callBack: () => { onItemClicked: () => this.setView({key: p.key})
return this.setView({key: p.key});
}
}; };
}); });
}, },
@ -339,12 +337,14 @@ export default {
this.openmct.router.navigate(this.parentUrl); this.openmct.router.navigate(this.parentUrl);
}, },
updateActionItems(actionItems) { updateActionItems(actionItems) {
this.statusBarItems = this.actionCollection.getStatusBarActions(); const statusBarItems = this.actionCollection.getStatusBarActions();
this.statusBarItems = this.openmct.menus.actionsToMenuItems(statusBarItems, this.actionCollection.objectPath, this.actionCollection.view);
this.menuActionItems = this.actionCollection.getVisibleActions(); this.menuActionItems = this.actionCollection.getVisibleActions();
}, },
showMenuItems(event) { showMenuItems(event) {
let sortedActions = this.openmct.actions._groupAndSortActions(this.menuActionItems); const sortedActions = this.openmct.actions._groupAndSortActions(this.menuActionItems);
this.openmct.menus.showMenu(event.x, event.y, sortedActions); const menuItems = this.openmct.menus.actionsToMenuItems(sortedActions, this.actionCollection.objectPath, this.actionCollection.view);
this.openmct.menus.showMenu(event.x, event.y, menuItems);
}, },
unlistenToActionCollection() { unlistenToActionCollection() {
this.actionCollection.off('update', this.updateActionItems); this.actionCollection.off('update', this.updateActionItems);

View File

@ -28,7 +28,7 @@ export default {
cssClass: menuItem.cssClass, cssClass: menuItem.cssClass,
name: menuItem.name, name: menuItem.name,
description: menuItem.description, description: menuItem.description,
callBack: () => this.create(key) onItemClicked: () => this.create(key)
}; };
items.push(menuItemTemplate); items.push(menuItemTemplate);

View File

@ -90,7 +90,7 @@
/> />
<object-view <object-view
ref="browseObject" ref="browseObject"
class="l-shell__main-container" class="l-shell__main-container js-main-container"
data-selectable data-selectable
:show-edit-view="true" :show-edit-view="true"
@change-action-collection="setActionCollection" @change-action-collection="setActionCollection"

View File

@ -36,7 +36,7 @@ export default {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
let actionsCollection = this.openmct.actions.get(this.objectPath); let actionsCollection = this.openmct.actions.getActionsCollection(this.objectPath);
let actions = actionsCollection.getVisibleActions(); let actions = actionsCollection.getVisibleActions();
let sortedActions = this.openmct.actions._groupAndSortActions(actions); let sortedActions = this.openmct.actions._groupAndSortActions(actions);
@ -44,7 +44,8 @@ export default {
onDestroy: this.onContextMenuDestroyed onDestroy: this.onContextMenuDestroyed
}; };
this.openmct.menus.showMenu(event.clientX, event.clientY, sortedActions, menuOptions); const menuItems = this.openmct.menus.actionsToMenuItems(sortedActions, actionsCollection.objectPath, actionsCollection.view);
this.openmct.menus.showMenu(event.clientX, event.clientY, menuItems, menuOptions);
this.contextClickActive = true; this.contextClickActive = true;
this.$emit('context-click-active', true); this.$emit('context-click-active', true);
}, },

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
<template> <template>
<div class="l-preview-window"> <div class="l-preview-window js-preview-window">
<PreviewHeader <PreviewHeader
:current-view="currentView" :current-view="currentView"
:action-collection="actionCollection" :action-collection="actionCollection"
@ -116,7 +116,7 @@ export default {
this.actionCollection.destroy(); this.actionCollection.destroy();
} }
this.actionCollection = this.openmct.actions._get(this.objectPath, this.view); this.actionCollection = this.openmct.actions.getActionsCollection(this.objectPath, this.view);
}, },
initObjectStyles() { initObjectStyles() {
if (!this.styleRuleManager) { if (!this.styleRuleManager) {

View File

@ -75,8 +75,13 @@ export default class PreviewAction {
PreviewAction.isVisible = true; PreviewAction.isVisible = true;
} }
appliesTo(objectPath) { appliesTo(objectPath, view = {}) {
return !PreviewAction.isVisible && !this._isNavigatedObject(objectPath); const parentElement = view.parentElement;
const isObjectView = parentElement && parentElement.classList.contains('js-object-view');
return !PreviewAction.isVisible
&& !this._isNavigatedObject(objectPath)
&& !isObjectView;
} }
_isNavigatedObject(objectPath) { _isNavigatedObject(objectPath) {
@ -85,6 +90,7 @@ export default class PreviewAction {
return this._openmct.objects.areIdsEqual(targetObject.identifier, navigatedObject.identifier); return this._openmct.objects.areIdsEqual(targetObject.identifier, navigatedObject.identifier);
} }
_preventPreview(objectPath) { _preventPreview(objectPath) {
const noPreviewTypes = ['folder']; const noPreviewTypes = ['folder'];

View File

@ -36,10 +36,9 @@ export default class ViewHistoricalDataAction extends PreviewAction {
appliesTo(objectPath, view = {}) { appliesTo(objectPath, view = {}) {
let viewContext = view.getViewContext && view.getViewContext(); let viewContext = view.getViewContext && view.getViewContext();
if (objectPath.length && viewContext && viewContext.viewHistoricalData) { return objectPath.length
return true; && viewContext
} else { && viewContext.row
return false; && viewContext.row.viewHistoricalData;
}
} }
} }

View File

@ -24,7 +24,7 @@
:key="index" :key="index"
class="c-button" class="c-button"
:class="item.cssClass" :class="item.cssClass"
@click="item.callBack" @click="item.onItemClicked"
> >
</button> </button>
<button <button
@ -42,7 +42,8 @@ import ViewSwitcher from '../../ui/layout/ViewSwitcher.vue';
const HIDDEN_ACTIONS = [ const HIDDEN_ACTIONS = [
'remove', 'remove',
'move', 'move',
'preview' 'preview',
'large.view'
]; ];
export default { export default {
@ -114,6 +115,19 @@ export default {
} }
}, },
methods: { methods: {
filterHiddenItems(menuItems) {
const items = [];
menuItems.forEach(menuItem => {
const isGroup = Array.isArray(menuItem);
if (isGroup) {
items.push(this.filterHiddenItems(menuItem));
} else if (!HIDDEN_ACTIONS.includes(menuItem.key)) {
items.push(menuItem);
}
});
return items;
},
setView(view) { setView(view) {
this.$emit('setView', view); this.$emit('setView', view);
}, },
@ -122,12 +136,16 @@ export default {
delete this.actionCollection; delete this.actionCollection;
}, },
updateActionItems() { updateActionItems() {
this.statusBarItems = this.actionCollection.getStatusBarActions(); const statusBarItems = this.actionCollection.getStatusBarActions();
const menuItems = this.openmct.menus.actionsToMenuItems(statusBarItems, this.actionCollection.objectPath, this.actionCollection.view);
this.statusBarItems = this.filterHiddenItems(menuItems);
this.menuActionItems = this.actionCollection.getVisibleActions(); this.menuActionItems = this.actionCollection.getVisibleActions();
}, },
showMenuItems(event) { showMenuItems(event) {
let sortedActions = this.openmct.actions._groupAndSortActions(this.menuActionItems); let sortedActions = this.openmct.actions._groupAndSortActions(this.menuActionItems);
this.openmct.menus.showMenu(event.x, event.y, sortedActions); const menuItems = this.openmct.menus.actionsToMenuItems(sortedActions, this.actionCollection.objectPath, this.actionCollection.view);
const visibleMenuItems = this.filterHiddenItems(menuItems);
this.openmct.menus.showMenu(event.x, event.y, visibleMenuItems);
} }
} }
}; };

View File

@ -86,6 +86,18 @@ define(['EventEmitter'], function (EventEmitter) {
console.warn("Provider already defined for key '%s'. Provider keys must be unique.", key); console.warn("Provider already defined for key '%s'. Provider keys must be unique.", key);
} }
const wrappedView = provider.view.bind(provider);
provider.view = (domainObject, objectPath) => {
const viewObject = wrappedView(domainObject, objectPath);
const wrappedShow = viewObject.show.bind(viewObject);
viewObject.show = (element, isEditing) => {
viewObject.parentElement = element.parentElement;
wrappedShow(element, isEditing);
};
return viewObject;
};
this.providers[key] = provider; this.providers[key] = provider;
}; };