Migrate to Vue 3 Migration Build (#6767)

* Replacing all instances of the new Vue() component creation pattern
* In Vue 3, components cannot be created on the fly and mounted off-DOM. The suggested fix from Vue is to use createApp, but in the context of Open MCT this means dozens of Vue apps being created and destroyed at any given moment. Instead, we have used a community hack for creating individual components.
* beforeDestroy() -> beforeUnmount()
* destroyed() -> unmounted()
* The addition of deep: true option on Array listeners is now required to detect Array changes
* Open MCT is now mounted on a child div instead of directly on document.body


---------

Co-authored-by: Scott Bell <scott@traclabs.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
Co-authored-by: John Hill <john.c.hill@nasa.gov>
This commit is contained in:
Jesse Mazzella 2023-07-19 11:22:23 -07:00 committed by GitHub
parent 42b545917c
commit 4885c816dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
248 changed files with 2688 additions and 2121 deletions

View File

@ -28,6 +28,8 @@ module.exports = {
}
},
rules: {
'vue/no-v-for-template-key': 'off',
'vue/no-v-for-template-key-on-child': 'error',
'prettier/prettier': 'error',
'you-dont-need-lodash-underscore/omit': 'off',
'you-dont-need-lodash-underscore/throttle': 'off',

View File

@ -67,7 +67,8 @@ const config = {
MCT: path.join(projectRootDir, 'src/MCT'),
testUtils: path.join(projectRootDir, 'src/utils/testUtils.js'),
objectUtils: path.join(projectRootDir, 'src/api/objects/object-utils.js'),
utils: path.join(projectRootDir, 'src/utils')
utils: path.join(projectRootDir, 'src/utils'),
vue: path.join(projectRootDir, 'node_modules/@vue/compat/dist/vue.esm-bundler.js'),
}
},
plugins: [
@ -121,7 +122,15 @@ const config = {
},
{
test: /\.vue$/,
use: 'vue-loader'
loader: 'vue-loader',
options: {
compilerOptions: {
whitespace: 'preserve',
compatConfig: {
MODE: 2
}
}
}
},
{
test: /\.html$/,

View File

@ -25,11 +25,6 @@ module.exports = merge(common, {
'**/.*' // dotfiles and dotfolders
]
},
resolve: {
alias: {
vue: path.join(projectRootDir, 'node_modules/vue/dist/vue.js')
}
},
plugins: [
new webpack.DefinePlugin({
__OPENMCT_ROOT_RELATIVE__: '"dist/"'

View File

@ -13,11 +13,6 @@ const projectRootDir = path.resolve(__dirname, '..');
module.exports = merge(common, {
mode: 'production',
resolve: {
alias: {
vue: path.join(projectRootDir, 'node_modules/vue/dist/vue.min.js')
}
},
plugins: [
new webpack.DefinePlugin({
__OPENMCT_ROOT_RELATIVE__: '""'

View File

@ -41,7 +41,7 @@ test.describe('Form Validation Behavior', () => {
await page.goto('./', { waitUntil: 'domcontentloaded' });
await page.click('button:has-text("Create")');
await page.click(':nth-match(:text("Folder"), 2)');
await page.getByRole('menuitem', { name: ' Folder' }).click();
// Fill in empty string into title and trigger validation with 'Tab'
await page.click('text=Properties Title Notes >> input[type="text"]');

View File

@ -24,7 +24,7 @@ function SimpleVuePlugin() {
container.appendChild(vm.$mount().$el);
},
destroy: function (container) {
vm.$destroy();
//vm.$destroy();
}
};
}

View File

@ -92,7 +92,9 @@
}
</style>
</head>
<body></body>
<body>
<div id="app"></div>
</body>
<script>
const THIRTY_SECONDS = 30 * 1000;
const ONE_MINUTE = THIRTY_SECONDS * 2;

View File

@ -12,6 +12,8 @@
"@types/eventemitter3": "1.2.0",
"@types/jasmine": "4.3.4",
"@types/lodash": "4.14.192",
"@vue/compat": "^3.1.0",
"@vue/compiler-sfc": "^3.1.0",
"babel-loader": "9.1.0",
"babel-plugin-istanbul": "6.1.1",
"codecov": "3.8.3",
@ -22,8 +24,8 @@
"d3-scale": "3.3.0",
"d3-selection": "3.0.0",
"eslint": "8.43.0",
"eslint-plugin-compat": "4.1.4",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-compat": "4.1.4",
"eslint-plugin-playwright": "0.12.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-vue": "9.15.0",
@ -66,11 +68,10 @@
"style-loader": "3.3.3",
"typescript": "5.1.3",
"uuid": "9.0.0",
"vue": "2.6.14",
"vue": "^3.1.0",
"vue-eslint-parser": "9.3.1",
"vue-loader": "15.9.8",
"vue-template-compiler": "2.6.14",
"webpack": "5.88.0",
"vue-loader": "^16.0.0",
"webpack-cli": "5.1.1",
"webpack-dev-server": "4.15.1",
"webpack-merge": "5.9.0"

View File

@ -343,7 +343,17 @@ define([
* @param {HTMLElement} [domElement] the DOM element in which to run
* MCT; if undefined, MCT will be run in the body of the document
*/
MCT.prototype.start = function (domElement = document.body, isHeadlessMode = false) {
MCT.prototype.start = function (
domElement = document.body.firstElementChild,
isHeadlessMode = false
) {
// Create element to mount Layout if it doesn't exist
if (domElement === null) {
domElement = document.createElement('div');
document.body.appendChild(domElement);
}
domElement.id = 'openmct-app';
if (this.types.get('layout') === undefined) {
this.install(
this.plugins.DisplayLayout({
@ -370,25 +380,30 @@ define([
*/
if (!isHeadlessMode) {
const appLayout = new Vue({
const appLayout = Vue.createApp({
components: {
Layout: Layout.default
},
provide: {
openmct: this
openmct: Vue.markRaw(this)
},
template: '<Layout ref="layout"></Layout>'
});
domElement.appendChild(appLayout.$mount().$el);
const component = appLayout.mount(domElement);
component.$nextTick(() => {
this.layout = component.$refs.layout;
this.app = appLayout;
Browse(this);
window.addEventListener('beforeunload', this.destroy);
this.router.start();
this.emit('start');
});
} else {
window.addEventListener('beforeunload', this.destroy);
this.layout = appLayout.$refs.layout;
Browse(this);
this.router.start();
this.emit('start');
}
window.addEventListener('beforeunload', this.destroy);
this.router.start();
this.emit('start');
};
MCT.prototype.startHeadless = function () {

View File

@ -21,6 +21,7 @@
*****************************************************************************/
import objectUtils from '../objects/object-utils';
import CompositionProvider from './CompositionProvider';
import { toRaw } from 'vue';
/**
* @typedef {import('../objects/ObjectAPI').DomainObject} DomainObject
@ -167,7 +168,7 @@ export default class DefaultCompositionProvider extends CompositionProvider {
*/
add(parent, childId) {
if (!this.includes(parent, childId)) {
const composition = structuredClone(parent.composition);
const composition = structuredClone(toRaw(parent.composition));
composition.push(childId);
this.publicAPI.objects.mutate(parent, 'composition', composition);
}

View File

@ -10,8 +10,7 @@ import TextAreaField from './components/controls/TextAreaField.vue';
import TextField from './components/controls/TextField.vue';
import ToggleSwitchField from './components/controls/ToggleSwitchField.vue';
import Vue from 'vue';
import mount from 'utils/mount';
export const DEFAULT_CONTROLS_MAP = {
autocomplete: AutoCompleteField,
checkbox: CheckBoxField,
@ -69,31 +68,40 @@ export default class FormControl {
*/
_getControlViewProvider(control) {
const self = this;
let rowComponent;
let _destroy = null;
return {
show(element, model, onChange) {
rowComponent = new Vue({
el: element,
components: {
FormControlComponent: DEFAULT_CONTROLS_MAP[control]
const { vNode, destroy } = mount(
{
el: element,
components: {
FormControlComponent: DEFAULT_CONTROLS_MAP[control]
},
provide: {
openmct: self.openmct
},
data() {
return {
model,
onChange
};
},
template: `<FormControlComponent :model="model" @onChange="onChange"></FormControlComponent>`
},
provide: {
openmct: self.openmct
},
data() {
return {
model,
onChange
};
},
template: `<FormControlComponent :model="model" @onChange="onChange"></FormControlComponent>`
});
{
element,
app: self.openmct.app
}
);
_destroy = destroy;
return rowComponent;
return vNode;
},
destroy() {
rowComponent.$destroy();
if (_destroy) {
_destroy();
}
}
};
}

View File

@ -23,8 +23,8 @@
import FormController from './FormController';
import FormProperties from './components/FormProperties.vue';
import Vue from 'vue';
import _ from 'lodash';
import mount from 'utils/mount';
export default class FormsAPI {
constructor(openmct) {
@ -156,25 +156,28 @@ export default class FormsAPI {
formCancel = onFormAction(reject);
});
const vm = new Vue({
components: { FormProperties },
provide: {
openmct: self.openmct
const { destroy } = mount(
{
components: { FormProperties },
provide: {
openmct: self.openmct
},
data() {
return {
formStructure,
onChange: onFormPropertyChange,
onCancel: formCancel,
onSave: formSave
};
},
template:
'<FormProperties :model="formStructure" @onChange="onChange" @onCancel="onCancel" @onSave="onSave"></FormProperties>'
},
data() {
return {
formStructure,
onChange: onFormPropertyChange,
onCancel: formCancel,
onSave: formSave
};
},
template:
'<FormProperties :model="formStructure" @onChange="onChange" @onCancel="onCancel" @onSave="onSave"></FormProperties>'
}).$mount();
const formElement = vm.$el;
element.append(formElement);
{
element,
app: self.openmct.app
}
);
function onFormPropertyChange(data) {
if (onChange) {
@ -195,8 +198,7 @@ export default class FormsAPI {
function onFormAction(callback) {
return () => {
formElement.remove();
vm.$destroy();
destroy();
if (callback) {
callback(changes);

View File

@ -141,7 +141,7 @@ export default {
},
methods: {
onChange(data) {
this.$set(this.invalidProperties, data.model.key, data.invalid);
this.invalidProperties[data.model.key] = data.invalid;
this.$emit('onChange', data);
},

View File

@ -26,9 +26,7 @@
{{ row.name }}
</div>
<div class="c-form-row__state-indicator" :class="reqClass"></div>
<div v-if="row.control" class="c-form-row__controls">
<div ref="rowElement"></div>
</div>
<div v-if="row.control" ref="rowElement" class="c-form-row__controls"></div>
</div>
</template>
@ -91,7 +89,7 @@ export default {
this.formControl.show(this.$refs.rowElement, this.row, this.onChange);
},
destroyed() {
unmounted() {
const destroy = this.formControl.destroy;
if (destroy) {
destroy();

View File

@ -166,7 +166,7 @@ export default {
this.options = this.model.options;
}
},
destroyed() {
unmounted() {
document.body.removeEventListener('click', this.handleOutsideClick);
},
methods: {

View File

@ -20,17 +20,17 @@
at runtime from the About dialog for additional information.
-->
<template>
<div class="c-menu" :class="options.menuClass">
<div class="c-menu" :class="options.menuClass" :style="styleObject">
<ul v-if="options.actions.length && options.actions[0].length" role="menu">
<template v-for="(actionGroups, index) in options.actions">
<div :key="index" role="group">
<template v-for="(actionGroups, index) in options.actions" :key="index">
<div role="group">
<li
v-for="action in actionGroups"
:key="action.name"
role="menuitem"
:class="[action.cssClass, action.isDisabled ? 'disabled' : '']"
:title="action.description"
:data-testid="action.testId || false"
:data-testid="action.testId || null"
@click="action.onItemClicked"
>
{{ action.name }}
@ -42,8 +42,8 @@
class="c-menu__section-separator"
></div>
<li v-if="actionGroups.length === 0" :key="index">No actions defined.</li>
</div></template
>
</div>
</template>
</ul>
<ul v-else role="menu">
@ -53,7 +53,7 @@
role="menuitem"
:class="[action.cssClass, action.isDisabled ? 'disabled' : '']"
:title="action.description"
:data-testid="action.testId || false"
:data-testid="action.testId || null"
@click="action.onItemClicked"
>
{{ action.name }}
@ -64,7 +64,9 @@
</template>
<script>
import popupMenuMixin from '../mixins/popupMenuMixin';
export default {
mixins: [popupMenuMixin],
inject: ['options']
};
</script>

View File

@ -20,21 +20,21 @@
at runtime from the About dialog for additional information.
-->
<template>
<div class="c-menu" :class="[options.menuClass, 'c-super-menu']">
<div class="c-menu" :class="[options.menuClass, 'c-super-menu']" :style="styleObject">
<ul
v-if="options.actions.length && options.actions[0].length"
role="menu"
class="c-super-menu__menu"
>
<template v-for="(actionGroups, index) in options.actions">
<div :key="index" role="group">
<template v-for="(actionGroups, index) in options.actions" :key="index">
<div role="group">
<li
v-for="action in actionGroups"
:key="action.name"
role="menuitem"
:class="[action.cssClass, action.isDisabled ? 'disabled' : '']"
:title="action.description"
:data-testid="action.testId || false"
:data-testid="action.testId || null"
@click="action.onItemClicked"
@mouseover="toggleItemDescription(action)"
@mouseleave="toggleItemDescription()"
@ -58,7 +58,8 @@
:key="action.name"
role="menuitem"
:class="action.cssClass"
:data-testid="action.testId || false"
:title="action.description"
:data-testid="action.testId || null"
@click="action.onItemClicked"
@mouseover="toggleItemDescription(action)"
@mouseleave="toggleItemDescription()"
@ -79,9 +80,10 @@
</div>
</div>
</template>
<script>
import popupMenuMixin from '../mixins/popupMenuMixin';
export default {
mixins: [popupMenuMixin],
inject: ['options'],
data: function () {
return {

View File

@ -22,7 +22,8 @@
import EventEmitter from 'EventEmitter';
import MenuComponent from './components/Menu.vue';
import SuperMenuComponent from './components/SuperMenu.vue';
import Vue from 'vue';
import { h } from 'vue';
import mount from 'utils/mount';
export const MENU_PLACEMENT = {
TOP: 'top',
@ -52,137 +53,67 @@ class Menu extends EventEmitter {
dismiss() {
this.emit('destroy');
document.body.removeChild(this.component.$el);
if (this.destroy) {
this.destroy();
this.destroy = null;
}
document.removeEventListener('click', this.dismiss);
this.component.$destroy();
}
show() {
this.component.$mount();
document.body.appendChild(this.component.$el);
let position = this._calculatePopupPosition(this.component.$el);
this.component.$el.style.left = `${position.x}px`;
this.component.$el.style.top = `${position.y}px`;
document.addEventListener('click', this.dismiss);
}
showMenu() {
this.component = new Vue({
components: {
MenuComponent
if (this.destroy) {
return;
}
const { vNode, destroy } = mount({
render() {
return h(MenuComponent);
},
provide: {
options: this.options
},
template: '<menu-component />'
// TODO: Remove this exception upon full migration to Vue 3
// https://v3-migration.vuejs.org/breaking-changes/render-function-api.html#render-function-argument
compatConfig: {
RENDER_FUNCTION: false
}
});
this.el = vNode.el;
this.destroy = destroy;
this.show();
}
showSuperMenu() {
this.component = new Vue({
components: {
SuperMenuComponent
const { vNode, destroy } = mount({
data() {
return {
top: '0px',
left: '0px'
};
},
render() {
return h(SuperMenuComponent);
},
provide: {
options: this.options
},
template: '<super-menu-component />'
// TODO: Remove this exception upon full migration to Vue 3
// https://v3-migration.vuejs.org/breaking-changes/render-function-api.html#render-function-argument
compatConfig: {
RENDER_FUNCTION: false
}
});
this.el = vNode.el;
this.destroy = destroy;
this.show();
}
/**
* @private
*/
_calculatePopupPosition(menuElement) {
let menuDimensions = menuElement.getBoundingClientRect();
if (!this.options.placement) {
this.options.placement = MENU_PLACEMENT.BOTTOM_RIGHT;
}
const menuPosition = this._getMenuPositionBasedOnPlacement(menuDimensions);
return this._preventMenuOverflow(menuPosition, menuDimensions);
}
/**
* @private
*/
_getMenuPositionBasedOnPlacement(menuDimensions) {
let eventPosX = this.options.x;
let eventPosY = this.options.y;
// Adjust popup menu based on placement
switch (this.options.placement) {
case MENU_PLACEMENT.TOP:
eventPosX = this.options.x - Math.floor(menuDimensions.width / 2);
eventPosY = this.options.y - menuDimensions.height;
break;
case MENU_PLACEMENT.BOTTOM:
eventPosX = this.options.x - Math.floor(menuDimensions.width / 2);
break;
case MENU_PLACEMENT.LEFT:
eventPosX = this.options.x - menuDimensions.width;
eventPosY = this.options.y - Math.floor(menuDimensions.height / 2);
break;
case MENU_PLACEMENT.RIGHT:
eventPosY = this.options.y - Math.floor(menuDimensions.height / 2);
break;
case MENU_PLACEMENT.TOP_LEFT:
eventPosX = this.options.x - menuDimensions.width;
eventPosY = this.options.y - menuDimensions.height;
break;
case MENU_PLACEMENT.TOP_RIGHT:
eventPosY = this.options.y - menuDimensions.height;
break;
case MENU_PLACEMENT.BOTTOM_LEFT:
eventPosX = this.options.x - menuDimensions.width;
break;
case MENU_PLACEMENT.BOTTOM_RIGHT:
break;
}
return {
x: eventPosX,
y: eventPosY
};
}
/**
* @private
*/
_preventMenuOverflow(menuPosition, menuDimensions) {
let { x: eventPosX, y: eventPosY } = menuPosition;
let overflowX = eventPosX + menuDimensions.width - document.body.clientWidth;
let overflowY = eventPosY + menuDimensions.height - document.body.clientHeight;
if (overflowX > 0) {
eventPosX = eventPosX - overflowX;
}
if (overflowY > 0) {
eventPosY = eventPosY - overflowY;
}
if (eventPosX < 0) {
eventPosX = 0;
}
if (eventPosY < 0) {
eventPosY = 0;
}
return {
x: eventPosX,
y: eventPosY
};
show() {
document.body.appendChild(this.el);
document.addEventListener('click', this.dismiss);
}
}

View File

@ -0,0 +1,111 @@
import { MENU_PLACEMENT } from '../menu';
export default {
methods: {
/**
* @private
*/
_calculatePopupPosition(menuElement) {
let menuDimensions = menuElement.getBoundingClientRect();
if (!this.options.placement) {
this.options.placement = MENU_PLACEMENT.BOTTOM_RIGHT;
}
const menuPosition = this._getMenuPositionBasedOnPlacement(menuDimensions);
return this._preventMenuOverflow(menuPosition, menuDimensions);
},
/**
* @private
*/
_getMenuPositionBasedOnPlacement(menuDimensions) {
let eventPosX = this.options.x;
let eventPosY = this.options.y;
// Adjust popup menu based on placement
switch (this.options.placement) {
case MENU_PLACEMENT.TOP:
eventPosX = this.options.x - Math.floor(menuDimensions.width / 2);
eventPosY = this.options.y - menuDimensions.height;
break;
case MENU_PLACEMENT.BOTTOM:
eventPosX = this.options.x - Math.floor(menuDimensions.width / 2);
break;
case MENU_PLACEMENT.LEFT:
eventPosX = this.options.x - menuDimensions.width;
eventPosY = this.options.y - Math.floor(menuDimensions.height / 2);
break;
case MENU_PLACEMENT.RIGHT:
eventPosY = this.options.y - Math.floor(menuDimensions.height / 2);
break;
case MENU_PLACEMENT.TOP_LEFT:
eventPosX = this.options.x - menuDimensions.width;
eventPosY = this.options.y - menuDimensions.height;
break;
case MENU_PLACEMENT.TOP_RIGHT:
eventPosY = this.options.y - menuDimensions.height;
break;
case MENU_PLACEMENT.BOTTOM_LEFT:
eventPosX = this.options.x - menuDimensions.width;
break;
case MENU_PLACEMENT.BOTTOM_RIGHT:
break;
}
return {
x: eventPosX,
y: eventPosY
};
},
/**
* @private
*/
_preventMenuOverflow(menuPosition, menuDimensions) {
let { x: eventPosX, y: eventPosY } = menuPosition;
let overflowX = eventPosX + menuDimensions.width - document.body.clientWidth;
let overflowY = eventPosY + menuDimensions.height - document.body.clientHeight;
if (overflowX > 0) {
eventPosX = eventPosX - overflowX;
}
if (overflowY > 0) {
eventPosY = eventPosY - overflowY;
}
if (eventPosX < 0) {
eventPosX = 0;
}
if (eventPosY < 0) {
eventPosY = 0;
}
return {
x: eventPosX,
y: eventPosY
};
}
},
mounted() {
this.$nextTick(() => {
const position = this._calculatePopupPosition(this.$el);
this.top = position.y;
this.left = position.x;
});
},
data() {
return {
top: '0px',
left: '0px'
};
},
computed: {
styleObject() {
return {
top: `${this.top}px`,
left: `${this.left}px`
};
}
}
};

View File

@ -159,6 +159,9 @@ class InMemorySearchProvider {
return pendingQuery.promise;
}
/**
* @private
*/
#localQueryFallBack({ queryId, searchType, query, maxResults }) {
if (searchType === this.searchTypes.OBJECTS) {
return this.localSearchForObjects(queryId, query, maxResults);

View File

@ -96,12 +96,26 @@ class MutableDomainObject {
//Emit events specific to properties affected
let parentPropertiesList = path.split('.');
for (let index = parentPropertiesList.length; index > 0; index--) {
let pathToThisProperty = parentPropertiesList.slice(0, index);
let parentPropertyPath = parentPropertiesList.slice(0, index).join('.');
this._globalEventEmitter.emit(
qualifiedEventName(this, parentPropertyPath),
_.get(this, parentPropertyPath),
_.get(oldModel, parentPropertyPath)
);
const lastPathElement = parentPropertiesList[index - 1];
// Also emit an event for the array whose element has changed so developers do not need to listen to every element of the array.
if (lastPathElement.endsWith(']')) {
const arrayPathElement = lastPathElement.substring(0, lastPathElement.lastIndexOf('['));
pathToThisProperty[index - 1] = arrayPathElement;
const pathToArrayString = pathToThisProperty.join('.');
this._globalEventEmitter.emit(
qualifiedEventName(this, pathToArrayString),
_.get(this, pathToArrayString),
_.get(oldModel, pathToArrayString)
);
}
}
//TODO: Emit events for listeners of child properties when parent changes.

View File

@ -1,10 +1,10 @@
import DialogComponent from './components/DialogComponent.vue';
import Overlay from './Overlay';
import Vue from 'vue';
import mount from 'utils/mount';
class Dialog extends Overlay {
constructor({ iconClass, message, title, hint, timestamp, ...options }) {
let component = new Vue({
const { vNode, destroy } = mount({
components: {
DialogComponent: DialogComponent
},
@ -16,17 +16,17 @@ class Dialog extends Overlay {
timestamp
},
template: '<dialog-component></dialog-component>'
}).$mount();
});
super({
element: component.$el,
element: vNode.el,
size: 'fit',
dismissable: false,
...options
});
this.once('destroy', () => {
component.$destroy();
destroy();
});
}
}

View File

@ -1,6 +1,6 @@
import OverlayComponent from './components/OverlayComponent.vue';
import EventEmitter from 'EventEmitter';
import Vue from 'vue';
import mount from 'utils/mount';
const cssClasses = {
large: 'l-overlay-large',
@ -28,18 +28,25 @@ class Overlay extends EventEmitter {
this.autoHide = autoHide;
this.dismissable = dismissable !== false;
this.component = new Vue({
components: {
OverlayComponent: OverlayComponent
const { destroy } = mount(
{
components: {
OverlayComponent: OverlayComponent
},
provide: {
dismiss: this.notifyAndDismiss.bind(this),
element,
buttons,
dismissable: this.dismissable
},
template: '<overlay-component></overlay-component>'
},
provide: {
dismiss: this.notifyAndDismiss.bind(this),
element,
buttons,
dismissable: this.dismissable
},
template: '<overlay-component></overlay-component>'
});
{
element: this.container
}
);
this.destroy = destroy;
if (onDestroy) {
this.once('destroy', onDestroy);
@ -53,7 +60,7 @@ class Overlay extends EventEmitter {
dismiss() {
this.emit('destroy');
document.body.removeChild(this.container);
this.component.$destroy();
this.destroy();
}
//Ensures that any callers are notified that the overlay is dismissed
@ -67,7 +74,6 @@ class Overlay extends EventEmitter {
**/
show() {
document.body.appendChild(this.container);
this.container.appendChild(this.component.$mount().$el);
}
}

View File

@ -1,9 +1,8 @@
import ProgressDialogComponent from './components/ProgressDialogComponent.vue';
import Overlay from './Overlay';
import Vue from 'vue';
import mount from 'utils/mount';
let component;
class ProgressDialog extends Overlay {
constructor({
progressPerc,
@ -15,7 +14,7 @@ class ProgressDialog extends Overlay {
timestamp,
...options
}) {
component = new Vue({
const { vNode, destroy } = mount({
components: {
ProgressDialogComponent: ProgressDialogComponent
},
@ -35,17 +34,18 @@ class ProgressDialog extends Overlay {
};
},
template: '<progress-dialog-component :model="model"></progress-dialog-component>'
}).$mount();
});
component = vNode.componentInstance;
super({
element: component.$el,
element: vNode.el,
size: 'fit',
dismissable: false,
...options
});
this.once('destroy', () => {
component.$destroy();
destroy();
});
}

View File

@ -22,7 +22,7 @@
import SelectionComponent from './components/SelectionComponent.vue';
import Overlay from './Overlay';
import Vue from 'vue';
import mount from 'utils/mount';
class Selection extends Overlay {
constructor({
@ -34,7 +34,7 @@ class Selection extends Overlay {
currentSelection,
...options
}) {
let component = new Vue({
const { vNode, destroy } = mount({
components: {
SelectionComponent: SelectionComponent
},
@ -47,7 +47,9 @@ class Selection extends Overlay {
currentSelection
},
template: '<selection-component></selection-component>'
}).$mount();
});
const component = vNode.componentInstance;
super({
element: component.$el,
@ -59,7 +61,7 @@ class Selection extends Overlay {
});
this.once('destroy', () => {
component.$destroy();
destroy();
});
}
}

View File

@ -22,7 +22,7 @@
import TooltipComponent from './components/TooltipComponent.vue';
import EventEmitter from 'EventEmitter';
import Vue from 'vue';
import mount from 'utils/mount';
class Tooltip extends EventEmitter {
constructor(
@ -34,9 +34,7 @@ class Tooltip extends EventEmitter {
) {
super();
this.container = document.createElement('div');
this.component = new Vue({
const { vNode, destroy } = mount({
components: {
TooltipComponent: TooltipComponent
},
@ -48,6 +46,9 @@ class Tooltip extends EventEmitter {
template: '<tooltip-component toolTipText="toolTipText"></tooltip-component>'
});
this.component = vNode.componentInstance;
this._destroy = destroy;
this.isActive = null;
}
@ -55,8 +56,7 @@ class Tooltip extends EventEmitter {
if (!this.isActive) {
return;
}
document.body.removeChild(this.container);
this.component.$destroy();
this._destroy();
this.isActive = false;
}
@ -64,8 +64,7 @@ class Tooltip extends EventEmitter {
* @private
**/
show() {
document.body.appendChild(this.container);
this.container.appendChild(this.component.$mount().$el);
document.body.appendChild(this.component.$el);
this.isActive = true;
}
}

View File

@ -1,5 +1,7 @@
.c-tooltip-wrapper {
max-width: 200px;
height: auto;
width: auto;
padding: $interiorMargin;
}

View File

@ -21,13 +21,16 @@
*****************************************************************************/
import EventEmitter from 'EventEmitter';
import { markRaw } from 'vue';
export default class LADTableConfiguration extends EventEmitter {
constructor(domainObject, openmct) {
super();
this.domainObject = domainObject;
this.openmct = openmct;
// Prevent Vue from making this a Proxy, otherwise
// it cannot access any private methods (like #mutate()).
this.openmct = markRaw(openmct);
this.objectMutated = this.objectMutated.bind(this);
this.unlistenFromMutation = openmct.objects.observe(

View File

@ -21,7 +21,7 @@
*****************************************************************************/
import LADTableConfigurationComponent from './components/LADTableConfiguration.vue';
import Vue from 'vue';
import mount from 'utils/mount';
export default function LADTableConfigurationViewProvider(openmct) {
return {
@ -37,28 +37,34 @@ export default function LADTableConfigurationViewProvider(openmct) {
return object?.type === 'LadTable' || object?.type === 'LadTableSet';
},
view(selection) {
let component;
let _destroy = null;
return {
show(element) {
component = new Vue({
el: element,
components: {
LADTableConfiguration: LADTableConfigurationComponent
const { destroy } = mount(
{
el: element,
components: {
LADTableConfiguration: LADTableConfigurationComponent
},
provide: {
openmct
},
template: '<LADTableConfiguration />'
},
provide: {
openmct
},
template: '<LADTableConfiguration />'
});
{
app: openmct.app,
element
}
);
_destroy = destroy;
},
priority() {
return 1;
},
destroy() {
if (component) {
component.$destroy();
component = undefined;
if (_destroy) {
_destroy();
}
}
};

View File

@ -22,38 +22,47 @@
import LadTable from './components/LADTable.vue';
import LADTableConfiguration from './LADTableConfiguration';
import Vue from 'vue';
import mount from 'utils/mount';
export default class LADTableView {
constructor(openmct, domainObject, objectPath) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.component = undefined;
this.component = null;
this._destroy = null;
}
show(element) {
let ladTableConfiguration = new LADTableConfiguration(this.domainObject, this.openmct);
this.component = new Vue({
el: element,
components: {
LadTable
const { vNode, destroy } = mount(
{
el: element,
components: {
LadTable
},
provide: {
openmct: this.openmct,
currentView: this,
ladTableConfiguration
},
data: () => {
return {
domainObject: this.domainObject,
objectPath: this.objectPath
};
},
template:
'<lad-table ref="ladTable" :domain-object="domainObject" :object-path="objectPath"></lad-table>'
},
provide: {
openmct: this.openmct,
currentView: this,
ladTableConfiguration
},
data: () => {
return {
domainObject: this.domainObject,
objectPath: this.objectPath
};
},
template:
'<lad-table ref="ladTable" :domain-object="domainObject" :object-path="objectPath"></lad-table>'
});
{
app: this.openmct.app,
element
}
);
this.component = vNode.componentInstance;
this._destroy = destroy;
}
getViewContext() {
@ -64,8 +73,9 @@ export default class LADTableView {
return this.component.$refs.ladTable.getViewContext();
}
destroy(element) {
this.component.$destroy();
this.component = undefined;
destroy() {
if (this._destroy) {
this._destroy();
}
}
}

View File

@ -22,37 +22,46 @@
import LadTableSet from './components/LadTableSet.vue';
import LADTableConfiguration from './LADTableConfiguration';
import Vue from 'vue';
import mount from 'utils/mount';
export default class LadTableSetView {
constructor(openmct, domainObject, objectPath) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.component = undefined;
this._destroy = null;
this.component = null;
}
show(element) {
let ladTableConfiguration = new LADTableConfiguration(this.domainObject, this.openmct);
this.component = new Vue({
el: element,
components: {
LadTableSet
const { vNode, destroy } = mount(
{
el: element,
components: {
LadTableSet
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath,
currentView: this,
ladTableConfiguration
},
data: () => {
return {
domainObject: this.domainObject
};
},
template: '<lad-table-set ref="ladTableSet" :domain-object="domainObject"></lad-table-set>'
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath,
currentView: this,
ladTableConfiguration
},
data: () => {
return {
domainObject: this.domainObject
};
},
template: '<lad-table-set ref="ladTableSet" :domain-object="domainObject"></lad-table-set>'
});
{
app: this.openmct.app,
element
}
);
this._destroy = destroy;
this.component = vNode.componentInstance;
}
getViewContext() {
@ -63,8 +72,9 @@ export default class LadTableSetView {
return this.component.$refs.ladTableSet.getViewContext();
}
destroy(element) {
this.component.$destroy();
this.component = undefined;
destroy() {
if (this._destroy) {
this._destroy();
}
}
}

View File

@ -190,7 +190,7 @@ export default {
this.previewAction = new PreviewAction(this.openmct);
this.previewAction.on('isVisible', this.togglePreviewState);
},
destroyed() {
unmounted() {
this.openmct.time.off('timeSystem', this.updateTimeSystem);
this.telemetryCollection.off('add', this.setLatestValues);
this.telemetryCollection.off('clear', this.resetValues);

View File

@ -49,7 +49,7 @@
</template>
<script>
import Vue from 'vue';
import Vue, { toRaw } from 'vue';
import LadRow from './LADRow.vue';
import StalenessUtils from '@/utils/staleness';
@ -139,7 +139,7 @@ export default {
);
this.initializeViewActions();
},
destroyed() {
unmounted() {
this.ladTableConfiguration.off('change', this.handleConfigurationChange);
this.composition.off('add', this.addItem);
@ -191,7 +191,7 @@ export default {
reorder(reorderPlan) {
const oldItems = this.items.slice();
reorderPlan.forEach((reorderEvent) => {
this.$set(this.items, reorderEvent.newIndex, oldItems[reorderEvent.oldIndex]);
this.items[reorderEvent.newIndex] = oldItems[reorderEvent.oldIndex];
});
},
metadataHasUnits(valueMetadatas) {
@ -230,7 +230,7 @@ export default {
};
},
toggleFixedLayout() {
const config = structuredClone(this.configuration);
const config = structuredClone(toRaw(this.configuration));
config.isFixedLayout = !this.configuration.isFixedLayout;
this.ladTableConfiguration.updateConfiguration(config);

View File

@ -87,7 +87,7 @@ export default {
this.composition.load();
},
destroyed() {
unmounted() {
this.ladTableConfiguration.destroy();
this.openmct.editor.off('isEditing', this.toggleEdit);
@ -126,7 +126,7 @@ export default {
ladTable.domainObject = domainObject;
ladTable.key = this.openmct.objects.makeKeyString(domainObject.identifier);
this.$set(this.ladTelemetryObjects, ladTable.key, []);
this.ladTelemetryObjects[ladTable.key] = [];
this.ladTableObjects.push(ladTable);
const composition = this.openmct.composition.get(ladTable.domainObject);
@ -165,7 +165,7 @@ export default {
const telemetryObjects = this.ladTelemetryObjects[ladTable.key];
telemetryObjects.push(telemetryObject);
this.$set(this.ladTelemetryObjects, ladTable.key, telemetryObjects);
this.ladTelemetryObjects[ladTable.key] = telemetryObjects;
this.shouldShowUnitsCheckbox();
};
@ -179,7 +179,7 @@ export default {
);
telemetryObjects.splice(index, 1);
this.$set(this.ladTelemetryObjects, ladTable.key, telemetryObjects);
this.ladTelemetryObjects[ladTable.key] = telemetryObjects;
this.shouldShowUnitsCheckbox();
};
@ -220,7 +220,7 @@ export default {
}
if (showUnitsCheckbox && this.headers.units === undefined) {
this.$set(this.headers, 'units', 'Units');
this.headers.units = 'Units';
}
if (!showUnitsCheckbox && this.headers?.units) {

View File

@ -33,8 +33,8 @@
</tr>
</thead>
<tbody>
<template v-for="ladTable in ladTableObjects">
<tr :key="ladTable.key" class="c-table__group-header js-lad-table-set__table-headers">
<template v-for="ladTable in ladTableObjects" :key="ladTable.key">
<tr class="c-table__group-header js-lad-table-set__table-headers">
<td colspan="10">
{{ ladTable.domainObject.name }}
</td>
@ -125,7 +125,7 @@ export default {
this.stalenessSubscription = {};
},
destroyed() {
unmounted() {
this.ladTableConfiguration.off('change', this.handleConfigurationChange);
this.composition.off('add', this.addLadTable);
this.composition.off('remove', this.removeLadTable);
@ -147,7 +147,7 @@ export default {
ladTable.key = this.openmct.objects.makeKeyString(domainObject.identifier);
ladTable.objectPath = [domainObject, ...this.objectPath];
this.$set(this.ladTelemetryObjects, ladTable.key, []);
this.ladTelemetryObjects[ladTable.key] = [];
this.ladTableObjects.push(ladTable);
let composition = this.openmct.composition.get(ladTable.domainObject);
@ -201,7 +201,7 @@ export default {
const telemetryObjects = this.ladTelemetryObjects[ladTable.key];
telemetryObjects.push(telemetryObject);
this.$set(this.ladTelemetryObjects, ladTable.key, telemetryObjects);
this.ladTelemetryObjects[ladTable.key] = telemetryObjects;
this.stalenessSubscription[combinedKey] = {};
this.stalenessSubscription[combinedKey].stalenessUtils = new StalenessUtils(
@ -236,7 +236,7 @@ export default {
this.unwatchStaleness(combinedKey);
telemetryObjects.splice(index, 1);
this.$set(this.ladTelemetryObjects, ladTable.key, telemetryObjects);
this.ladTelemetryObjects[ladTable.key] = telemetryObjects;
};
},
unwatchStaleness(combinedKey) {

View File

@ -84,7 +84,7 @@ define([
rowCount: 'reflow'
},
template: autoflowTemplate,
destroyed: function () {
unmounted: function () {
controller.destroy();
if (interval) {
@ -109,7 +109,7 @@ define([
});
}
AutoflowTabularView.prototype = Object.create(VueView.prototype);
AutoflowTabularView.prototype = Object.create(VueView.default.prototype);
return AutoflowTabularView;
});

View File

@ -20,15 +20,15 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['vue'], function (Vue) {
function VueView(options) {
const vm = new Vue(options);
import mount from 'utils/mount';
export default function () {
return function VueView(options) {
const { vNode, destroy } = mount(options);
this.show = function (container) {
container.appendChild(vm.$mount().$el);
container.appendChild(vNode.el);
};
this.destroy = vm.$destroy.bind(vm);
}
return VueView;
});
this.destroy = destroy;
};
}

View File

@ -93,7 +93,7 @@ export default {
});
this.registerListeners();
},
beforeDestroy() {
beforeUnmount() {
if (this.plotResizeObserver) {
this.plotResizeObserver.unobserve(this.$refs.plotWrapper);
clearTimeout(this.resizeTimer);

View File

@ -83,7 +83,7 @@ export default {
this.refreshData
);
},
beforeDestroy() {
beforeUnmount() {
this.stopFollowingTimeContext();
this.removeAllSubscriptions();

View File

@ -22,7 +22,7 @@
import BarGraphView from './BarGraphView.vue';
import { BAR_GRAPH_KEY, BAR_GRAPH_VIEW } from './BarGraphConstants';
import Vue from 'vue';
import mount from 'utils/mount';
export default function BarGraphViewProvider(openmct) {
function isCompactView(objectPath) {
@ -44,34 +44,43 @@ export default function BarGraphViewProvider(openmct) {
},
view: function (domainObject, objectPath) {
let component;
let _destroy = null;
let component = null;
return {
show: function (element) {
let isCompact = isCompactView(objectPath);
component = new Vue({
el: element,
components: {
BarGraphView
const { vNode, destroy } = mount(
{
el: element,
components: {
BarGraphView
},
provide: {
openmct,
domainObject,
path: objectPath
},
data() {
return {
options: {
compact: isCompact
}
};
},
template: '<bar-graph-view ref="graphComponent" :options="options"></bar-graph-view>'
},
provide: {
openmct,
domainObject,
path: objectPath
},
data() {
return {
options: {
compact: isCompact
}
};
},
template: '<bar-graph-view ref="graphComponent" :options="options"></bar-graph-view>'
});
{
app: openmct.app,
element
}
);
_destroy = destroy;
component = vNode.componentInstance;
},
destroy: function () {
component.$destroy();
component = undefined;
_destroy();
},
onClearData() {
component.$refs.graphComponent.refreshData();

View File

@ -1,6 +1,6 @@
import { BAR_GRAPH_INSPECTOR_KEY, BAR_GRAPH_KEY } from '../BarGraphConstants';
import Vue from 'vue';
import BarGraphOptions from './BarGraphOptions.vue';
import mount from 'utils/mount';
export default function BarGraphInspectorViewProvider(openmct) {
return {
@ -16,29 +16,35 @@ export default function BarGraphInspectorViewProvider(openmct) {
return object && object.type === BAR_GRAPH_KEY;
},
view: function (selection) {
let component;
let _destroy = null;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
BarGraphOptions
const { destroy } = mount(
{
el: element,
components: {
BarGraphOptions
},
provide: {
openmct,
domainObject: selection[0][0].context.item
},
template: '<bar-graph-options></bar-graph-options>'
},
provide: {
openmct,
domainObject: selection[0][0].context.item
},
template: '<bar-graph-options></bar-graph-options>'
});
{
app: openmct.app,
element
}
);
_destroy = destroy;
},
priority: function () {
return openmct.priority.HIGH + 1;
},
destroy: function () {
if (component) {
component.$destroy();
component = undefined;
if (_destroy) {
_destroy();
}
}
};

View File

@ -167,7 +167,7 @@ export default {
this.registerListeners();
this.composition.load();
},
beforeDestroy() {
beforeUnmount() {
this.openmct.editor.off('isEditing', this.setEditState);
this.stopListening();
},
@ -192,7 +192,7 @@ export default {
}
},
addSeries(series, index) {
this.$set(this.plotSeries, this.plotSeries.length, series);
this.plotSeries.push(series);
this.setupOptions();
},
removeSeries(seriesIdentifier) {

View File

@ -115,7 +115,7 @@ export default {
this.initColorAndName
);
},
beforeDestroy() {
beforeUnmount() {
if (this.removeBarStylesListener) {
this.removeBarStylesListener();
}

View File

@ -77,7 +77,7 @@ export default {
this.reloadTelemetry
);
},
beforeDestroy() {
beforeUnmount() {
this.stopFollowingTimeContext();
if (!this.composition) {

View File

@ -22,7 +22,7 @@
import ScatterPlotView from './ScatterPlotView.vue';
import { SCATTER_PLOT_KEY, SCATTER_PLOT_VIEW, TIME_STRIP_KEY } from './scatterPlotConstants.js';
import Vue from 'vue';
import mount from 'utils/mount';
export default function ScatterPlotViewProvider(openmct) {
function isCompactView(objectPath) {
@ -44,34 +44,42 @@ export default function ScatterPlotViewProvider(openmct) {
},
view: function (domainObject, objectPath) {
let component;
let _destroy = null;
return {
show: function (element) {
let isCompact = isCompactView(objectPath);
component = new Vue({
el: element,
components: {
ScatterPlotView
const isCompact = isCompactView(objectPath);
const { destroy } = mount(
{
el: element,
components: {
ScatterPlotView
},
provide: {
openmct,
domainObject,
path: objectPath
},
data() {
return {
options: {
compact: isCompact
}
};
},
template: '<scatter-plot-view :options="options"></scatter-plot-view>'
},
provide: {
openmct,
domainObject,
path: objectPath
},
data() {
return {
options: {
compact: isCompact
}
};
},
template: '<scatter-plot-view :options="options"></scatter-plot-view>'
});
{
app: openmct.app,
element
}
);
_destroy = destroy;
},
destroy: function () {
component.$destroy();
component = undefined;
if (_destroy) {
_destroy();
}
}
};
}

View File

@ -87,7 +87,10 @@ export default {
watch: {
data: {
immediate: false,
handler: 'updateData'
handler() {
this.updateData();
},
deep: true
}
},
mounted() {
@ -106,7 +109,7 @@ export default {
this.$refs.plot.on('plotly_relayout', this.zoom);
},
beforeDestroy() {
beforeUnmount() {
if (this.$refs.plot && this.$refs.plot.off) {
this.$refs.plot.off('plotly_relayout', this.zoom);
}

View File

@ -52,7 +52,7 @@ export default {
mounted() {
this.openmct.editor.on('isEditing', this.setEditState);
},
beforeDestroy() {
beforeUnmount() {
this.openmct.editor.off('isEditing', this.setEditState);
},
methods: {

View File

@ -64,7 +64,7 @@ export default {
this.registerListeners();
this.composition.load();
},
beforeDestroy() {
beforeUnmount() {
this.stopListening();
},
methods: {
@ -102,7 +102,7 @@ export default {
}
},
addSeries(series, index) {
this.$set(this.plotSeries, this.plotSeries.length, series);
this.plotSeries.push(series);
this.setAxesLabels();
},
removeSeries(seriesKey) {

View File

@ -89,7 +89,7 @@ export default {
this.registerListeners();
this.composition.load();
},
beforeDestroy() {
beforeUnmount() {
this.stopListening();
},
methods: {
@ -135,7 +135,7 @@ export default {
}
},
addSeries(series, index) {
this.$set(this.plotSeries, this.plotSeries.length, series);
this.plotSeries.push(series);
this.setupOptions();
},
removeSeries(seriesIdentifier) {

View File

@ -1,5 +1,5 @@
import { SCATTER_PLOT_INSPECTOR_KEY, SCATTER_PLOT_KEY } from '../scatterPlotConstants';
import Vue from 'vue';
import mount from 'utils/mount';
import PlotOptions from './PlotOptions.vue';
export default function ScatterPlotInspectorViewProvider(openmct) {
@ -16,29 +16,34 @@ export default function ScatterPlotInspectorViewProvider(openmct) {
return object && object.type === SCATTER_PLOT_KEY;
},
view: function (selection) {
let component;
let _destroy = null;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
PlotOptions
const { destroy } = mount(
{
el: element,
components: {
PlotOptions
},
provide: {
openmct,
domainObject: selection[0][0].context.item
},
template: '<plot-options></plot-options>'
},
provide: {
openmct,
domainObject: selection[0][0].context.item
},
template: '<plot-options></plot-options>'
});
{
app: openmct.app,
element
}
);
_destroy = destroy;
},
priority: function () {
return openmct.priority.HIGH + 1;
},
destroy: function () {
if (component) {
component.$destroy();
component = undefined;
if (_destroy) {
_destroy();
}
}
};

View File

@ -23,8 +23,8 @@ import { SCATTER_PLOT_KEY } from './scatterPlotConstants.js';
import ScatterPlotViewProvider from './ScatterPlotViewProvider';
import ScatterPlotInspectorViewProvider from './inspector/ScatterPlotInspectorViewProvider';
import ScatterPlotCompositionPolicy from './ScatterPlotCompositionPolicy';
import Vue from 'vue';
import ScatterPlotForm from './ScatterPlotForm.vue';
import mount from 'utils/mount';
export default function () {
return function install(openmct) {
@ -100,24 +100,30 @@ export default function () {
function getScatterPlotFormControl(openmct) {
return {
show(element, model, onChange) {
const rowComponent = new Vue({
el: element,
components: {
ScatterPlotForm
const { vNode } = mount(
{
el: element,
components: {
ScatterPlotForm
},
provide: {
openmct
},
data() {
return {
model,
onChange
};
},
template: `<scatter-plot-form :model="model" @onChange="onChange"></scatter-plot-form>`
},
provide: {
openmct
},
data() {
return {
model,
onChange
};
},
template: `<scatter-plot-form :model="model" @onChange="onChange"></scatter-plot-form>`
});
{
app: openmct.app,
element
}
);
return rowComponent;
return vNode;
}
};
}

View File

@ -19,39 +19,42 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import ClearDataAction from './ClearDataAction';
import GlobalClearIndicator from './components/globalClearIndicator.vue';
import mount from 'utils/mount';
define(['./components/globalClearIndicator.vue', './ClearDataAction', 'vue'], function (
GlobaClearIndicator,
ClearDataAction,
Vue
) {
return function plugin(appliesToObjects, options = { indicator: true }) {
let installIndicator = options.indicator;
export default function plugin(appliesToObjects, options = { indicator: true }) {
let installIndicator = options.indicator;
appliesToObjects = appliesToObjects || [];
appliesToObjects = appliesToObjects || [];
return function install(openmct) {
if (installIndicator) {
let component = new Vue({
return function install(openmct) {
if (installIndicator) {
const { vNode } = mount(
{
components: {
GlobalClearIndicator: GlobaClearIndicator.default
GlobalClearIndicator
},
provide: {
openmct
},
template: '<GlobalClearIndicator></GlobalClearIndicator>'
});
},
{
app: openmct.app,
element: document.createElement('div')
}
);
let indicator = {
element: component.$mount().$el,
key: 'global-clear-indicator',
priority: openmct.priority.DEFAULT
};
let indicator = {
element: vNode.el,
key: 'global-clear-indicator',
priority: openmct.priority.DEFAULT
};
openmct.indicators.add(indicator);
}
openmct.indicators.add(indicator);
}
openmct.actions.register(new ClearDataAction.default(openmct, appliesToObjects));
};
openmct.actions.register(new ClearDataAction(openmct, appliesToObjects));
};
});
}

View File

@ -21,7 +21,7 @@
*****************************************************************************/
import Clock from './components/Clock.vue';
import Vue from 'vue';
import mount from 'utils/mount';
export default function ClockViewProvider(openmct) {
return {
@ -33,25 +33,33 @@ export default function ClockViewProvider(openmct) {
},
view: function (domainObject) {
let component;
let _destroy = null;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
Clock
const { destroy } = mount(
{
el: element,
components: {
Clock
},
provide: {
openmct,
domainObject
},
template: '<clock />'
},
provide: {
openmct,
domainObject
},
template: '<clock />'
});
{
app: openmct.app,
element
}
);
_destroy = destroy;
},
destroy: function () {
component.$destroy();
component = undefined;
if (_destroy) {
_destroy();
}
}
};
}

View File

@ -21,18 +21,16 @@
-->
<template>
<div class="l-angular-ov-wrapper">
<div class="u-contents">
<div class="c-clock l-time-display u-style-receiver js-style-receiver">
<div class="c-clock__timezone">
{{ timeZoneAbbr }}
</div>
<div class="c-clock__value">
{{ timeTextValue }}
</div>
<div class="c-clock__ampm">
{{ timeAmPm }}
</div>
<div class="u-contents">
<div class="c-clock l-time-display u-style-receiver js-style-receiver">
<div class="c-clock__timezone">
{{ timeZoneAbbr }}
</div>
<div class="c-clock__value">
{{ timeTextValue }}
</div>
<div class="c-clock__ampm">
{{ timeAmPm }}
</div>
</div>
</div>
@ -47,13 +45,11 @@ export default {
inject: ['openmct', 'domainObject'],
data() {
return {
configuration: this.domainObject.configuration,
lastTimestamp: this.openmct.time.now()
};
},
computed: {
configuration() {
return this.domainObject.configuration;
},
baseFormat() {
return this.configuration.baseFormat;
},
@ -85,10 +81,21 @@ export default {
}
},
mounted() {
this.unobserve = this.openmct.objects.observe(
this.domainObject,
'configuration',
(configuration) => {
this.configuration = configuration;
}
);
this.tick = raf(this.tick);
this.openmct.time.on('tick', this.tick);
},
beforeDestroy() {
beforeUnmount() {
if (this.unobserve) {
this.unobserve();
}
this.openmct.time.off('tick', this.tick);
},
methods: {

View File

@ -50,7 +50,7 @@ export default {
this.openmct.time.on('tick', this.tick);
this.tick(this.timeTextValue);
},
beforeDestroy() {
beforeUnmount() {
this.openmct.time.off('tick', this.tick);
},
methods: {

View File

@ -24,7 +24,7 @@ import ClockViewProvider from './ClockViewProvider';
import ClockIndicator from './components/ClockIndicator.vue';
import momentTimezone from 'moment-timezone';
import Vue from 'vue';
import mount from 'utils/mount';
export default function ClockPlugin(options) {
return function install(openmct) {
@ -93,26 +93,33 @@ export default function ClockPlugin(options) {
openmct.objectViews.addProvider(new ClockViewProvider(openmct));
if (options && options.enableClockIndicator === true) {
const clockIndicator = new Vue({
components: {
ClockIndicator
const element = document.createElement('div');
const { vNode } = mount(
{
components: {
ClockIndicator
},
provide: {
openmct
},
data() {
return {
indicatorFormat: CLOCK_INDICATOR_FORMAT
};
},
template: '<ClockIndicator :indicator-format="indicatorFormat" />'
},
provide: {
openmct
},
data() {
return {
indicatorFormat: CLOCK_INDICATOR_FORMAT
};
},
template: '<ClockIndicator :indicator-format="indicatorFormat" />'
});
{
app: openmct.app,
element
}
);
const indicator = {
element: clockIndicator.$mount().$el,
element: vNode.el,
key: 'clock-indicator',
priority: openmct.priority.LOW
};
openmct.indicators.add(indicator);
}

View File

@ -21,7 +21,7 @@
*****************************************************************************/
import ConditionSet from './components/ConditionSet.vue';
import Vue from 'vue';
import mount from 'utils/mount';
const DEFAULT_VIEW_PRIORITY = 100;
@ -46,35 +46,44 @@ export default class ConditionSetViewProvider {
}
view(domainObject, objectPath) {
let component;
const openmct = this.openmct;
let _destroy = null;
let component = null;
return {
show: (container, isEditing) => {
component = new Vue({
el: container,
components: {
ConditionSet
const { vNode, destroy } = mount(
{
el: container,
components: {
ConditionSet
},
provide: {
openmct: this.openmct,
domainObject,
objectPath
},
data() {
return {
isEditing
};
},
template: '<condition-set :isEditing="isEditing"></condition-set>'
},
provide: {
openmct,
domainObject,
objectPath
},
data() {
return {
isEditing
};
},
template: '<condition-set :isEditing="isEditing"></condition-set>'
});
{
app: this.openmct.app,
element: container
}
);
_destroy = destroy;
component = vNode.componentInstance;
},
onEditModeChange: (isEditing) => {
component.isEditing = isEditing;
},
destroy: () => {
component.$destroy();
component = undefined;
if (_destroy) {
_destroy();
}
}
};
}

View File

@ -270,7 +270,7 @@ export default {
return false;
}
},
destroyed() {
unmounted() {
this.destroy();
},
mounted() {

View File

@ -122,7 +122,7 @@ export default {
deep: true
}
},
destroyed() {
unmounted() {
this.composition.off('add', this.addTelemetryObject);
this.composition.off('remove', this.removeTelemetryObject);
if (this.conditionManager) {

View File

@ -154,7 +154,7 @@ export default {
deep: true
}
},
beforeDestroy() {
beforeUnmount() {
this.resetApplied();
},
mounted() {

View File

@ -229,7 +229,7 @@ export default {
return this.styleableFontItems.length && this.allowEditing;
}
},
destroyed() {
unmounted() {
this.removeListeners();
this.openmct.editor.off('isEditing', this.setEditState);
this.stylesManager.off('styleSelected', this.applyStyleToSelection);
@ -878,8 +878,8 @@ export default {
const fontSize = hasConsolidatedFontSize ? styles[0].fontSize : NON_SPECIFIC;
const font = hasConsolidatedFont ? styles[0].font : NON_SPECIFIC;
this.$set(this.consolidatedFontStyle, 'fontSize', fontSize);
this.$set(this.consolidatedFontStyle, 'font', font);
this.consolidatedFontStyle.fontSize = fontSize;
this.consolidatedFontStyle.font = font;
}
},
getFontStyle(selectionPath) {
@ -934,7 +934,7 @@ export default {
}
// sync vue component on font update
this.$set(this.consolidatedFontStyle, property, value);
this.consolidatedFontStyle[property] = value;
},
isLayoutObject(selectionPath) {
const layoutItemType =

View File

@ -21,7 +21,7 @@
*****************************************************************************/
import ConditionWidgetComponent from './components/ConditionWidget.vue';
import Vue from 'vue';
import mount from 'utils/mount';
export default function ConditionWidget(openmct) {
return {
@ -35,25 +35,33 @@ export default function ConditionWidget(openmct) {
return domainObject.type === 'conditionWidget';
},
view: function (domainObject) {
let component;
let _destroy = null;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
ConditionWidgetComponent: ConditionWidgetComponent
const { destroy } = mount(
{
el: element,
components: {
ConditionWidgetComponent: ConditionWidgetComponent
},
provide: {
openmct,
domainObject
},
template: '<condition-widget-component></condition-widget-component>'
},
provide: {
openmct,
domainObject
},
template: '<condition-widget-component></condition-widget-component>'
});
{
app: openmct.app,
element
}
);
_destroy = destroy;
},
destroy: function (element) {
component.$destroy();
component = undefined;
destroy: function () {
if (_destroy) {
_destroy();
}
}
};
},

View File

@ -81,7 +81,7 @@ export default {
this.listenToConditionSetChanges();
}
},
beforeDestroy() {
beforeUnmount() {
this.stopListeningToConditionSetChanges();
},
methods: {

View File

@ -22,30 +22,38 @@
import AlphanumericFormat from './components/AlphanumericFormat.vue';
import Vue from 'vue';
import mount from 'utils/mount';
class AlphanumericFormatView {
constructor(openmct, domainObject, objectPath) {
this.openmct = openmct;
this.domainObject = domainObject;
this.objectPath = objectPath;
this.component = undefined;
this._destroy = null;
this.component = null;
}
show(element) {
this.component = new Vue({
el: element,
name: 'AlphanumericFormat',
components: {
AlphanumericFormat
const { vNode, destroy } = mount(
{
el: element,
components: {
AlphanumericFormat
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath,
currentView: this
},
template: '<AlphanumericFormat ref="alphanumericFormat" />'
},
provide: {
openmct: this.openmct,
objectPath: this.objectPath,
currentView: this
},
template: '<alphanumeric-format ref="alphanumericFormat"></alphanumeric-format>'
});
{
app: this.openmct.app,
element
}
);
this.component = vNode.componentInstance;
this._destroy = destroy;
}
getViewContext() {
@ -61,8 +69,9 @@ class AlphanumericFormatView {
}
destroy() {
this.component.$destroy();
this.component = undefined;
if (this._destroy) {
this._destroy();
}
}
}

View File

@ -61,7 +61,7 @@ export default {
this.openmct.selection.on('change', this.handleSelection);
this.handleSelection(this.openmct.selection.get());
},
destroyed() {
unmounted() {
this.openmct.editor.off('isEditing', this.toggleEdit);
this.openmct.selection.off('change', this.handleSelection);
},

View File

@ -115,7 +115,7 @@ export default {
this.initSelect
);
},
destroyed() {
unmounted() {
if (this.removeSelectable) {
this.removeSelectable();
}

View File

@ -55,7 +55,7 @@
:grid-size="gridSize"
:init-select="initSelectIndex === index"
:index="index"
:multi-select="selectedLayoutItems.length > 1"
:multi-select="selectedLayoutItems.length > 1 || null"
:is-editing="isEditing"
@contextClick="updateViewContext"
@move="move"
@ -161,16 +161,14 @@ export default {
selection: [],
showGrid: true,
viewContext: {},
gridDimensions: [0, 0]
gridDimensions: [0, 0],
layoutItems: this.domainObject.configuration.items
};
},
computed: {
gridSize() {
return this.domainObject.configuration.layoutGrid.map(Number);
},
layoutItems() {
return this.domainObject.configuration.items;
},
selectedLayoutItems() {
return this.layoutItems.filter((item) => {
return this.itemIsInCurrentSelection(item);
@ -223,9 +221,13 @@ export default {
this.composition.load();
this.gridDimensions = [this.$el.offsetWidth, this.$el.scrollHeight];
this.openmct.objects.observe(this.domainObject, 'configuration.items', (items) => {
this.layoutItems = items;
});
this.watchDisplayResize();
},
destroyed: function () {
unmounted: function () {
this.openmct.selection.off('change', this.setSelection);
this.composition.off('add', this.addChild);
this.composition.off('remove', this.removeChild);

View File

@ -115,7 +115,7 @@ export default {
this.initSelect
);
},
destroyed() {
unmounted() {
if (this.removeSelectable) {
this.removeSelectable();
}

View File

@ -118,7 +118,7 @@ export default {
this.initSelect
);
},
destroyed() {
unmounted() {
if (this.removeSelectable) {
this.removeSelectable();
}

View File

@ -24,13 +24,13 @@
<div class="l-layout__frame c-frame no-frame c-line-view" :class="[styleClass]" :style="style">
<svg width="100%" height="100%">
<line
class="c-line-view__hover-indicator"
v-bind="linePosition"
class="c-line-view__hover-indicator"
vector-effect="non-scaling-stroke"
/>
<line
class="c-line-view__line"
v-bind="linePosition"
class="c-line-view__line"
:stroke="stroke"
vector-effect="non-scaling-stroke"
/>
@ -257,7 +257,7 @@ export default {
this.initSelect
);
},
destroyed() {
unmounted() {
if (this.removeSelectable) {
this.removeSelectable();
}

View File

@ -133,7 +133,7 @@ export default {
this.openmct.objects.get(this.item.identifier).then(this.setObject);
}
},
beforeDestroy() {
beforeUnmount() {
if (this.removeSelectable) {
this.removeSelectable();
}

View File

@ -238,7 +238,7 @@ export default {
this.status = this.openmct.status.get(this.item.identifier);
this.removeStatusListener = this.openmct.status.observe(this.item.identifier, this.setStatus);
},
beforeDestroy() {
beforeUnmount() {
this.removeStatusListener();
if (this.removeSelectable) {

View File

@ -127,7 +127,7 @@ export default {
this.initSelect
);
},
destroyed() {
unmounted() {
if (this.removeSelectable) {
this.removeSelectable();
}

View File

@ -17,11 +17,6 @@
flex-direction: column;
overflow: auto;
&__grid-holder,
&__dimensions {
display: none;
}
&__dimensions {
$b: 1px dashed $editDimensionsColor;
border-right: $b;

View File

@ -1,6 +1,5 @@
.c-frame-edit {
// In Layouts, this is the editing rect and handles
display: none; // Set to display: block in DisplayLayout.vue
pointer-events: none;
@include abs();
border: $editMarqueeBorder;

View File

@ -40,7 +40,7 @@ export default {
);
this.initObjectStyles();
},
beforeDestroy() {
beforeUnmount() {
if (this.stopListeningObjectStyles) {
this.stopListeningObjectStyles();
}

View File

@ -26,10 +26,8 @@ import DisplayLayout from './components/DisplayLayout.vue';
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js';
import DisplayLayoutType from './DisplayLayoutType.js';
import DisplayLayoutDrawingObjectTypes from './DrawingObjectTypes.js';
import objectUtils from 'objectUtils';
import Vue from 'vue';
import mount from 'utils/mount';
class DisplayLayoutView {
constructor(openmct, domainObject, objectPath, options) {
@ -38,31 +36,40 @@ class DisplayLayoutView {
this.objectPath = objectPath;
this.options = options;
this.component = undefined;
this.component = null;
this.app = null;
}
show(container, isEditing) {
this.component = new Vue({
el: container,
components: {
DisplayLayout
const { vNode, destroy } = mount(
{
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>'
},
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>'
});
{
app: this.openmct.app,
element: container
}
);
this._destroy = destroy;
this.component = vNode.componentInstance;
}
getViewContext() {
@ -95,8 +102,9 @@ class DisplayLayoutView {
}
destroy() {
this.component.$destroy();
this.component = undefined;
if (this._destroy) {
this._destroy();
}
}
}

View File

@ -22,7 +22,7 @@
import FaultManagementInspector from './FaultManagementInspector.vue';
import Vue from 'vue';
import mount from 'utils/mount';
import { FAULT_MANAGEMENT_INSPECTOR, FAULT_MANAGEMENT_TYPE } from './constants';
@ -41,28 +41,34 @@ export default function FaultManagementInspectorViewProvider(openmct) {
return object && object.type === FAULT_MANAGEMENT_TYPE;
},
view: (selection) => {
let component;
let _destroy = null;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
FaultManagementInspector
const { destroy } = mount(
{
el: element,
components: {
FaultManagementInspector
},
provide: {
openmct
},
template: '<FaultManagementInspector></FaultManagementInspector>'
},
provide: {
openmct
},
template: '<FaultManagementInspector></FaultManagementInspector>'
});
{
app: openmct.app,
element
}
);
_destroy = destroy;
},
priority: function () {
return openmct.priority.HIGH + 1;
},
destroy: function () {
if (component) {
component.$destroy();
component = undefined;
if (_destroy) {
_destroy();
}
}
};

View File

@ -167,7 +167,7 @@ export default {
},
toggleSelected({ fault, selected = false }) {
if (selected) {
this.$set(this.selectedFaults, fault.id, fault);
this.selectedFaults[fault.id] = fault;
} else {
this.$delete(this.selectedFaults, fault.id);
}

View File

@ -41,7 +41,7 @@ export default {
mounted() {
this.unsubscribe = this.openmct.faults.subscribe(this.domainObject, this.updateFault);
},
beforeDestroy() {
beforeUnmount() {
if (this.unsubscribe) {
this.unsubscribe();
}
@ -53,7 +53,7 @@ export default {
} else if (type === FAULT_MANAGEMENT_ALARMS) {
this.faultsList.forEach((faultValue, i) => {
if (fault.id === faultValue.id) {
this.$set(this.faultsList, i, fault);
this.faultsList[i] = fault;
}
});
}

View File

@ -22,7 +22,7 @@
import FaultManagementView from './FaultManagementView.vue';
import { FAULT_MANAGEMENT_TYPE, FAULT_MANAGEMENT_VIEW } from './constants';
import Vue from 'vue';
import mount from 'utils/mount';
export default class FaultManagementViewProvider {
constructor(openmct) {
@ -39,30 +39,34 @@ export default class FaultManagementViewProvider {
}
view(domainObject) {
let component;
const openmct = this.openmct;
let _destroy = null;
return {
show: (element) => {
component = new Vue({
el: element,
components: {
FaultManagementView
const { destroy } = mount(
{
el: element,
components: {
FaultManagementView
},
provide: {
openmct,
domainObject
},
template: '<FaultManagementView></FaultManagementView>'
},
provide: {
openmct,
domainObject
},
template: '<FaultManagementView></FaultManagementView>'
});
{
app: openmct.app,
element
}
);
_destroy = destroy;
},
destroy: () => {
if (!component) {
return;
if (_destroy) {
_destroy();
}
component.$destroy();
component = undefined;
}
};
}

View File

@ -20,59 +20,70 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['./components/FiltersView.vue', 'vue'], function (FiltersView, Vue) {
function FiltersInspectorViewProvider(openmct, supportedObjectTypesArray) {
import mount from 'utils/mount';
import FiltersView from './components/FiltersView.vue';
const FILTERS_INSPECTOR_KEY = 'filters-inspector';
export default class FiltersInspectorViewProvider {
constructor(openmct, supportedObjectTypesArray) {
this.openmct = openmct;
this.supportedObjectTypesArray = supportedObjectTypesArray;
this.key = FILTERS_INSPECTOR_KEY;
this.name = 'Filters';
}
canView(selection) {
const domainObject = selection?.[0]?.[0]?.context?.item;
return (
domainObject && this.supportedObjectTypesArray.some((type) => domainObject.type === type)
);
}
view(selection) {
let openmct = this.openmct;
let _destroy = null;
const domainObject = selection?.[0]?.[0]?.context?.item;
return {
key: 'filters-inspector',
name: 'Filters',
canView: function (selection) {
const domainObject = selection?.[0]?.[0]?.context?.item;
return domainObject && supportedObjectTypesArray.some((type) => domainObject.type === type);
},
view: function (selection) {
let component;
const domainObject = selection?.[0]?.[0]?.context?.item;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
FiltersView: FiltersView.default
},
provide: {
openmct
},
template: '<filters-view></filters-view>'
});
show: function (element) {
const { destroy } = mount(
{
el: element,
components: {
FiltersView
},
provide: {
openmct: openmct
},
template: '<filters-view></filters-view>'
},
showTab: function (isEditing) {
if (isEditing) {
return true;
}
const metadata = openmct.telemetry.getMetadata(domainObject);
const metadataWithFilters = metadata
? metadata.valueMetadatas.filter((value) => value.filters)
: [];
return metadataWithFilters.length;
},
priority: function () {
return openmct.priority.DEFAULT;
},
destroy: function () {
if (component) {
component.$destroy();
component = undefined;
}
{
app: openmct.app,
element
}
};
);
_destroy = destroy;
},
showTab: function (isEditing) {
if (isEditing) {
return true;
}
const metadata = openmct.telemetry.getMetadata(domainObject);
const metadataWithFilters = metadata
? metadata.valueMetadatas.filter((value) => value.filters)
: [];
return metadataWithFilters.length;
},
priority: function () {
return openmct.priority.DEFAULT;
},
destroy: function () {
if (_destroy) {
_destroy();
}
}
};
}
return FiltersInspectorViewProvider;
});
}

View File

@ -133,7 +133,7 @@ export default {
mounted() {
this.openmct.editor.on('isEditing', this.toggleIsEditing);
},
beforeDestroy() {
beforeUnmount() {
this.openmct.editor.off('isEditing', this.toggleIsEditing);
},
methods: {

View File

@ -136,7 +136,7 @@ export default {
this.objectCssClass = type.definition.cssClass;
this.openmct.editor.on('isEditing', this.toggleIsEditing);
},
beforeDestroy() {
beforeUnmount() {
this.openmct.editor.off('isEditing', this.toggleIsEditing);
},
methods: {
@ -151,32 +151,32 @@ export default {
filterValue[comparator].push(valueName);
} else {
if (filterValue[comparator].length === 1) {
this.$set(this.updatedFilters, key, {});
this.updatedFilters[key] = {};
} else {
filterValue[comparator] = filterValue[comparator].filter((v) => v !== valueName);
}
}
} else {
this.$set(this.updatedFilters[key], comparator, [valueName]);
this.updatedFilters[key][comparator] = [valueName];
}
this.$emit('updateFilters', this.keyString, this.updatedFilters);
},
clearFilters(key) {
this.$set(this.updatedFilters, key, {});
this.updatedFilters[key] = {};
this.$emit('updateFilters', this.keyString, this.updatedFilters);
},
updateFiltersWithTextValue(key, comparator, value) {
if (value.trim() === '') {
this.$set(this.updatedFilters, key, {});
this.updatedFilters[key] = {};
} else {
this.$set(this.updatedFilters[key], comparator, value);
this.updatedFilters[key][comparator] = value;
}
this.$emit('updateFilters', this.keyString, this.updatedFilters);
},
updateSingleSelection(key, comparator, value) {
this.$set(this.updatedFilters[key], comparator, [value]);
this.updatedFilters[key][comparator] = [value];
this.$emit('updateFilters', this.keyString, this.updatedFilters);
},
useGlobalFilter(checked) {

View File

@ -114,7 +114,7 @@ export default {
this.updateGlobalFilters
);
},
beforeDestroy() {
beforeUnmount() {
this.composition.off('add', this.addChildren);
this.composition.off('remove', this.removeChildren);
this.unobserve();
@ -136,21 +136,21 @@ export default {
};
if (metadataWithFilters.length) {
this.$set(this.children, keyString, childObject);
this.children[keyString] = childObject;
metadataWithFilters.forEach((metadatum) => {
if (!this.globalFilters[metadatum.key]) {
this.$set(this.globalFilters, metadatum.key, {});
this.globalFilters[metadatum.key] = {};
}
if (!this.globalMetadata[metadatum.key]) {
this.$set(this.globalMetadata, metadatum.key, metadatum);
this.globalMetadata[metadatum.key] = metadatum;
}
if (!hasFiltersWithKeyString) {
if (!this.persistedFilters[keyString]) {
this.$set(this.persistedFilters, keyString, {});
this.$set(this.persistedFilters[keyString], 'useGlobal', true);
this.persistedFilters[keyString] = {};
this.persistedFilters[keyString].useGlobal = true;
mutateFilters = true;
}
@ -239,10 +239,10 @@ export default {
this.containsField(keyString, key)
) {
if (!this.persistedFilters[keyString][key]) {
this.$set(this.persistedFilters[keyString], key, {});
this.persistedFilters[keyString][key] = {};
}
this.$set(this.persistedFilters[keyString], key, filters[key]);
this.persistedFilters[keyString][key] = filters[key];
mutateFilters = true;
}
});

View File

@ -101,7 +101,7 @@ export default {
this.expanded = !this.expanded;
},
clearFilters(key) {
this.$set(this.updatedFilters, key, {});
this.updatedFilters[key] = {};
this.$emit('persistGlobalFilters', key, this.updatedFilters);
},
updateFiltersWithSelectedValue(key, comparator, valueName, value) {
@ -112,26 +112,26 @@ export default {
filterValue[comparator].push(valueName);
} else {
if (filterValue[comparator].length === 1) {
this.$set(this.updatedFilters, key, {});
this.updatedFilters[key] = {};
} else {
filterValue[comparator] = filterValue[comparator].filter((v) => v !== valueName);
}
}
} else {
this.$set(this.updatedFilters[key], comparator, [valueName]);
this.updatedFilters[key][comparator] = [valueName];
}
this.$emit('persistGlobalFilters', key, this.updatedFilters);
},
updateSingleSelection(key, comparator, value) {
this.$set(this.updatedFilters[key], comparator, [value]);
this.updatedFilters[key][comparator] = [value];
this.$emit('persistGlobalFilters', key, this.updatedFilters);
},
updateFiltersWithTextValue(key, comparator, value) {
if (value.trim() === '') {
this.$set(this.updatedFilters, key, {});
this.updatedFilters[key] = {};
} else {
this.$set(this.updatedFilters[key], comparator, value);
this.updatedFilters[key][comparator] = value;
}
this.$emit('persistGlobalFilters', key, this.updatedFilters);

View File

@ -24,7 +24,7 @@ define(['./FiltersInspectorViewProvider'], function (FiltersInspectorViewProvide
return function plugin(supportedObjectTypesArray) {
return function install(openmct) {
openmct.inspectorViews.addProvider(
new FiltersInspectorViewProvider(openmct, supportedObjectTypesArray)
new FiltersInspectorViewProvider.default(openmct, supportedObjectTypesArray)
);
};
};

View File

@ -43,9 +43,8 @@
/>
<div class="c-fl-container__frames-holder">
<template v-for="(frame, i) in frames">
<template v-for="(frame, i) in frames" :key="frame.id">
<frame-component
:key="frame.id"
class="c-fl-container__frame"
:frame="frame"
:index="i"
@ -55,7 +54,6 @@
/>
<drop-hint
:key="'hint-' + i"
class="c-fl-frame__drop-hint"
:index="i"
:allow-drop="allowDrop"
@ -64,7 +62,6 @@
<resize-handle
v-if="i !== frames.length - 1"
:key="'handle-' + i"
:index="i"
:orientation="rowsLayout ? 'horizontal' : 'vertical'"
:is-editing="isEditing"
@ -132,7 +129,7 @@ export default {
this.unsubscribeSelection = this.openmct.selection.selectable(this.$el, context, false);
},
beforeDestroy() {
beforeUnmount() {
this.unsubscribeSelection();
},
methods: {

View File

@ -56,7 +56,7 @@ export default {
document.addEventListener('dragend', this.dragend);
document.addEventListener('drop', this.dragend);
},
destroyed() {
unmounted() {
document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend);
document.removeEventListener('drop', this.dragend);

View File

@ -34,7 +34,7 @@
'c-fl--rows': rowsLayout === true
}"
>
<template v-for="(container, index) in containers">
<template v-for="(container, index) in containers" :key="`component-${container.id}`">
<drop-hint
v-if="index === 0 && containers.length > 1"
:key="`hint-top-${container.id}`"
@ -45,7 +45,6 @@
/>
<container-component
:key="`component-${container.id}`"
class="c-fl__container"
:index="index"
:container="container"
@ -174,7 +173,7 @@ export default {
this.composition.on('add', this.addFrame);
this.composition.load();
},
beforeDestroy() {
beforeUnmount() {
this.composition.off('remove', this.removeChildObject);
this.composition.off('add', this.addFrame);
},

View File

@ -114,7 +114,7 @@ export default {
this.dragGhost = document.getElementById('js-fl-drag-ghost');
},
beforeDestroy() {
beforeUnmount() {
if (this.domainObjectPromise) {
this.domainObjectPromise.then(() => {
if (this?.domainObject?.isMutable) {

View File

@ -56,7 +56,7 @@ export default {
document.addEventListener('dragend', this.unsetDragging);
document.addEventListener('drop', this.unsetDragging);
},
destroyed() {
unmounted() {
document.removeEventListener('dragstart', this.setDragging);
document.removeEventListener('dragend', this.unsetDragging);
document.removeEventListener('drop', this.unsetDragging);

View File

@ -20,65 +20,82 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(['./components/flexibleLayout.vue', 'vue'], function (FlexibleLayoutComponent, Vue) {
function FlexibleLayoutViewProvider(openmct) {
return {
key: 'flexible-layout',
name: 'FlexibleLayout',
cssClass: 'icon-layout-view',
canView: function (domainObject) {
return domainObject.type === 'flexible-layout';
},
canEdit: function (domainObject) {
return domainObject.type === 'flexible-layout';
},
view: function (domainObject, objectPath) {
let component;
import mount from 'utils/mount';
import FlexibleLayoutComponent from './components/flexibleLayout.vue';
return {
show: function (element, isEditing) {
component = new Vue({
el: element,
components: {
FlexibleLayoutComponent: FlexibleLayoutComponent.default
},
provide: {
openmct,
objectPath,
layoutObject: domainObject
},
data() {
return {
isEditing: isEditing
};
},
template:
'<flexible-layout-component ref="flexibleLayout" :isEditing="isEditing"></flexible-layout-component>'
});
const FLEXIBLE_LAYOUT_KEY = 'flexible-layout';
export default class FlexibleLayoutViewProvider {
constructor(openmct) {
this.openmct = openmct;
this.key = FLEXIBLE_LAYOUT_KEY;
this.name = 'Flexible Layout';
this.cssClass = 'icon-layout-view';
this.destroy = null;
}
canView(domainObject) {
return domainObject.type === FLEXIBLE_LAYOUT_KEY;
}
canEdit(domainObject) {
return domainObject.type === FLEXIBLE_LAYOUT_KEY;
}
view(domainObject, objectPath) {
let openmct = this.openmct;
let _destroy = null;
let component = null;
return {
show: function (element, isEditing) {
const { vNode, destroy } = mount(
{
el: element,
components: {
FlexibleLayoutComponent
},
provide: {
openmct: openmct,
objectPath,
layoutObject: domainObject
},
data() {
return {
isEditing: isEditing
};
},
template:
'<flexible-layout-component ref="flexibleLayout" :isEditing="isEditing"></flexible-layout-component>'
},
getSelectionContext: function () {
return {
item: domainObject,
addContainer: component.$refs.flexibleLayout.addContainer,
deleteContainer: component.$refs.flexibleLayout.deleteContainer,
deleteFrame: component.$refs.flexibleLayout.deleteFrame,
type: 'flexible-layout'
};
},
onEditModeChange: function (isEditing) {
component.isEditing = isEditing;
},
destroy: function (element) {
component.$destroy();
component = undefined;
{
app: openmct.app,
element
}
);
component = vNode.componentInstance;
_destroy = destroy;
},
getSelectionContext: function () {
return {
item: domainObject,
addContainer: component.$refs.flexibleLayout.addContainer,
deleteContainer: component.$refs.flexibleLayout.deleteContainer,
deleteFrame: component.$refs.flexibleLayout.deleteFrame,
type: 'flexible-layout'
};
},
priority: function () {
return 1;
onEditModeChange: function (isEditing) {
component.isEditing = isEditing;
},
destroy: function (element) {
if (_destroy) {
_destroy();
component = null;
}
}
};
}
return FlexibleLayoutViewProvider;
});
priority() {
return 1;
}
}

View File

@ -27,7 +27,7 @@ define(['./flexibleLayoutViewProvider', './utils/container', './toolbarProvider'
) {
return function plugin() {
return function install(openmct) {
openmct.objectViews.addProvider(new FlexibleLayoutViewProvider(openmct));
openmct.objectViews.addProvider(new FlexibleLayoutViewProvider.default(openmct));
openmct.types.addType('flexible-layout', {
name: 'Flexible Layout',

View File

@ -19,50 +19,51 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import GridViewComponent from './components/GridView.vue';
import { ALLOWED_FOLDER_TYPES } from './constants.js';
import mount from 'utils/mount';
define(['./components/GridView.vue', './constants.js', 'vue'], function (
GridViewComponent,
constants,
Vue
) {
function FolderGridView(openmct) {
const ALLOWED_FOLDER_TYPES = constants.ALLOWED_FOLDER_TYPES;
export default class FolderGridView {
constructor(openmct) {
this.openmct = openmct;
this.key = 'grid';
this.name = 'Grid View';
this.cssClass = 'icon-thumbs-strip';
}
canView(domainObject) {
return ALLOWED_FOLDER_TYPES.includes(domainObject.type);
}
view(domainObject) {
return {
key: 'grid',
name: 'Grid View',
cssClass: 'icon-thumbs-strip',
canView: function (domainObject) {
return ALLOWED_FOLDER_TYPES.includes(domainObject.type);
},
view: function (domainObject) {
let component;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
gridViewComponent: GridViewComponent.default
},
provide: {
openmct,
domainObject
},
template: '<grid-view-component></grid-view-component>'
});
show: (element) => {
const { destroy } = mount(
{
components: {
GridViewComponent
},
provide: {
openmct: this.openmct,
domainObject
},
template: '<GridViewComponent></GridViewComponent>'
},
destroy: function (element) {
component.$destroy();
component = undefined;
{
app: this.openmct.app,
element
}
};
);
this._destroy = destroy;
},
priority: function () {
return 1;
destroy: () => {
if (this._destroy) {
this._destroy();
}
}
};
}
return FolderGridView;
});
priority() {
return 1;
}
}

View File

@ -19,52 +19,54 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import mount from 'utils/mount';
import ListViewComponent from './components/ListView.vue';
import Moment from 'moment';
import { ALLOWED_FOLDER_TYPES } from './constants.js';
define(['./components/ListView.vue', './constants.js', 'vue', 'moment'], function (
ListViewComponent,
constants,
Vue,
Moment
) {
function FolderListView(openmct) {
const ALLOWED_FOLDER_TYPES = constants.ALLOWED_FOLDER_TYPES;
export default class FolderListView {
constructor(openmct) {
this.openmct = openmct;
this.key = 'list-view';
this.name = 'List View';
this.cssClass = 'icon-list-view';
}
canView(domainObject) {
return ALLOWED_FOLDER_TYPES.includes(domainObject.type);
}
view(domainObject) {
return {
key: 'list-view',
name: 'List View',
cssClass: 'icon-list-view',
canView: function (domainObject) {
return ALLOWED_FOLDER_TYPES.includes(domainObject.type);
},
view: function (domainObject) {
let component;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
listViewComponent: ListViewComponent.default
},
provide: {
openmct,
domainObject,
Moment
},
template: '<list-view-component></list-view-component>'
});
show: (element) => {
const { destroy } = mount(
{
el: element,
components: {
ListViewComponent
},
provide: {
openmct: this.openmct,
domainObject,
Moment
},
template: '<ListViewComponent></ListViewComponent>'
},
destroy: function (element) {
component.$destroy();
component = undefined;
{
app: this.openmct.app,
element
}
};
);
this._destroy = destroy;
},
priority: function () {
return 1;
destroy: () => {
if (this._destroy) {
this._destroy();
}
}
};
}
return FolderListView;
});
priority() {
return 1;
}
}

View File

@ -21,6 +21,7 @@
-->
<template>
<a
ref="root"
class="l-grid-view__item c-grid-item js-folder-child"
:class="[
{
@ -30,7 +31,7 @@
},
statusClass
]"
@click="navigate"
@click="navigate($event)"
>
<div
class="c-grid-item__type-icon"
@ -69,7 +70,7 @@ export default {
}
},
methods: {
navigate() {
navigate(_event) {
this.openmct.router.navigate(this.objectLink);
}
}

View File

@ -21,6 +21,7 @@
-->
<template>
<tr
ref="root"
class="c-list-item js-folder-child"
:class="{
'is-alias': item.isAlias === true

View File

@ -23,11 +23,10 @@ export default {
this.composition.on('remove', this.remove);
this.composition.load();
},
destroyed() {
beforeUnmount() {
if (!this.composition) {
return;
}
this.composition.off('add', this.add);
this.composition.off('remove', this.remove);
},

View File

@ -27,7 +27,7 @@ export default {
this.status = this.openmct.status.get(identifier);
this.removeStatusListener = this.openmct.status.observe(identifier, this.setStatus);
},
destroyed() {
unmounted() {
this.removeStatusListener();
}
};

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