Wrap Existing OpenMCT ObjectViews #8034
Replies: 2 comments 1 reply
-
Hi @ikirk This is a tricky problem as we didn't design our plugins in the beginning with the idea of being extendable. There may be a way to do this though with your own view, something like below: Banner Views: export default function createBannerComponent(openmct) {
return {
createTopBanner(domainObject) {
const div = document.createElement('div');
div.style.padding = '10px';
div.style.background = '#f5f5f5';
// Get the telemetry metadata and formatter
const metadata = openmct.telemetry.getMetadata(domainObject);
const valueMetadata = metadata.valuesForHints(['range'])[0];
const formatter = openmct.telemetry.getValueFormatter(valueMetadata);
// Example of using openmct APIs with proper formatting
const unsubscribe = openmct.telemetry.subscribe(domainObject, (datum) => {
const formattedValue = formatter.format(datum[valueMetadata.key]);
div.textContent = `Latest Value: ${formattedValue}`;
});
return {
element: div,
destroy: () => unsubscribe()
};
},
createBottomBanner(domainObject) {
const div = document.createElement('div');
div.style.padding = '10px';
div.style.background = '#f5f5f5';
div.textContent = `Name: ${domainObject.name}`;
return {
element: div,
destroy: () => {}
};
}
};
} Custom View: import createBannerComponent from './BannerComponent';
export default function CustomPlotViewProvider(openmct) {
const bannerComponent = createBannerComponent(openmct);
return {
key: 'custom-plot-view',
name: 'Custom Plot',
cssClass: 'icon-telemetry',
canView(domainObject, objectPath) {
return openmct.telemetry.hasNumericTelemetry(domainObject);
},
view: function (domainObject, objectPath) {
let originalView = null;
let topBanner = null;
let bottomBanner = null;
return {
show: function (element, isEditing, viewOptions) {
element.innerHTML = `
<div style="display: flex; flex-direction: column; height: 100%;">
<div class="top-banner"></div>
<div style="flex: 1;"></div>
<div class="bottom-banner"></div>
</div>
`;
// Create and add banners
topBanner = bannerComponent.createTopBanner(domainObject);
bottomBanner = bannerComponent.createBottomBanner(domainObject);
element.querySelector('.top-banner').appendChild(topBanner.element);
element.querySelector('.bottom-banner').appendChild(bottomBanner.element);
// Get and show the original plot view
const plotViewProvider = openmct.objectViews.getByProviderKey('plot-single');
if (plotViewProvider) {
originalView = plotViewProvider.view(domainObject, objectPath);
originalView.show(
element.querySelector('div[style*="flex: 1"]'),
isEditing,
viewOptions
);
}
},
destroy: function () {
if (topBanner) {
topBanner.destroy();
}
if (bottomBanner) {
bottomBanner.destroy();
}
if (originalView) {
originalView.destroy();
}
}
};
}
};
} This isn't fully fleshed out, but this should get you started in the right direction. Hope this helps! |
Beta Was this translation helpful? Give feedback.
-
Hey @ikirk ! So, using the ViewRegistry ( As for a more Vue focused solution for what I originally provided, I've created this plugin as an example: https://github.com/jvigliotta/openmct-additions/tree/master/ViewWrapExamplePlugin Here are the files as well:
export default function plugin() {
return function install(openmct) {
openmct.objectViews.addProvider(new ViewWrapExampleViewProvider(openmct));
};
}
import ViewWrapExampleView from './ViewWrapExampleView.js';
export default class ViewWrapExampleViewProvider {
constructor(openmct) {
this.openmct = openmct;
this.key = 'view-wrap-example-view';
this.name = 'View Wrap Example';
this.cssClass = 'icon-telemetry';
}
canView(domainObject) {
return this.openmct.telemetry.hasNumericTelemetry(domainObject);
}
view(domainObject, objectPath) {
return new ViewWrapExampleView(this.openmct, domainObject, objectPath);
}
}
import mount from 'utils/mount';
import ViewWrapExample from './ViewWrapExample.vue';
export default class ViewWrapExampleView {
constructor(openmct, domainObject, objectPath) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.component = null;
this._destroy = null;
}
show(element, isEditing, viewOptions) {
const { vNode, destroy } = mount(
{
el: element,
components: {
ViewWrapExample
},
provide: {
openmct: this.openmct,
isEditing,
viewOptions
},
data: () => {
return {
domainObject: this.domainObject,
objectPath: this.objectPath
};
},
template:
'<view-wrap-example :domain-object="domainObject" :object-path="objectPath"></view-wrap-example>'
},
{
app: this.openmct.app,
element
}
);
this.component = vNode.componentInstance;
this._destroy = destroy;
}
destroy() {
if (this._destroy) {
this._destroy();
}
this.component = null;
}
}
<template>
<div style="display: flex; flex-direction: column; height: 100%">
<div class="banner top-banner" style="padding: 10px; background: #f5f5f5">
<span>{{ formattedValue }}</span>
</div>
<div ref="plotContainer" style="flex: 1"></div>
<div class="banner bottom-banner" style="padding: 10px; background: #f5f5f5">
<span>{{ domainObject.name }}</span>
</div>
</div>
</template>
<script>
export default {
name: 'ViewWrapExample',
inject: ['openmct', 'isEditing', 'viewOptions'],
props: {
domainObject: {
type: Object,
required: true
},
objectPath: {
type: Array,
required: true
}
},
data() {
return {
formattedValue: 'Loading...',
originalView: null
};
},
created() {
const metadata = this.openmct.telemetry.getMetadata(this.domainObject);
const valueMetadata = metadata.valuesForHints(['range'])[0];
const formatter = this.openmct.telemetry.getValueFormatter(valueMetadata);
this.unsubscribe = this.openmct.telemetry.subscribe(this.domainObject, (datum) => {
this.formattedValue = formatter.format(datum[valueMetadata.key]);
});
},
mounted() {
this.showPlotView();
},
beforeUnmount() {
if (this.originalView) {
this.originalView.destroy();
}
if (this.unsubscribe) {
this.unsubscribe();
}
},
methods: {
showPlotView() {
// Get and show the original plot view
const objectViewProvider = this.openmct.objectViews.getByProviderKey('plot-single');
if (objectViewProvider) {
this.originalView = objectViewProvider.view(this.domainObject, this.objectPath);
this.originalView.show(this.$refs.plotContainer, this.isEditing, this.viewOptions);
}
}
}
};
</script> |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
For my application I need to wrap existing ObjectViews and their components to include some more information in a banner on the top and bottom of the object view when telemetry is displayed. I have decided to start with the PlotView, which is displayed by default for Telemetry-providing domain objects. Rather than re-implementing the existing PlotView, I would like to import the existing PlotView as a component and add the banners that I need above and below an instantiation of that component in the template. However, because I am consuming OpenMCT as an npm module, there doesn't seem to be a clean way to import the PlotView into my component. Is there a supported way to do this? Am I approaching it from the wrong direction? I'm new to OpenMCT and have been using openmct-hello as a guide.
Beta Was this translation helpful? Give feedback.
All reactions