mirror of
https://github.com/nasa/openmct.git
synced 2025-01-29 15:43:52 +00:00
context menu and shared object link generation (#2199)
* temporarily disable remove dialog which is broken * temporarily remove broken context action policy * let openmct generate legacy objects * ensure composition loads in specified order * redo nav and add context menu support to tree * componentize grid and list view, add context menus
This commit is contained in:
parent
1069a45cfc
commit
ff7df9ad1e
@ -69,8 +69,8 @@ define([], function () {
|
||||
}
|
||||
]
|
||||
};
|
||||
setTimeout(() => this.removeCallback(domainObject));
|
||||
|
||||
dialog = this.dialogService.showBlockingMessage(model);
|
||||
};
|
||||
|
||||
return RemoveDialog;
|
||||
|
@ -55,16 +55,19 @@ define(
|
||||
navigatedObject = this.navigationService.getNavigation(),
|
||||
actionMetadata = action.getMetadata ? action.getMetadata() : {};
|
||||
|
||||
// FIXME: need to restore support for changing contextual actions
|
||||
// based on edit mode.
|
||||
// if (navigatedObject.hasCapability("editor") && navigatedObject.getCapability("editor").isEditContextRoot()) {
|
||||
if (selectedObject.hasCapability("editor") && selectedObject.getCapability("editor").inEditContext()) {
|
||||
return this.editModeBlacklist.indexOf(actionMetadata.key) === -1;
|
||||
} else {
|
||||
//Target is in the context menu
|
||||
return this.nonEditContextBlacklist.indexOf(actionMetadata.key) === -1;
|
||||
}
|
||||
// if (selectedObject.hasCapability("editor") && selectedObject.getCapability("editor").inEditContext()) {
|
||||
// return this.editModeBlacklist.indexOf(actionMetadata.key) === -1;
|
||||
// } else {
|
||||
// //Target is in the context menu
|
||||
// return this.nonEditContextBlacklist.indexOf(actionMetadata.key) === -1;
|
||||
// }
|
||||
// } else {
|
||||
// return true;
|
||||
// }
|
||||
return true;
|
||||
};
|
||||
|
||||
return EditContextualActionPolicy;
|
||||
|
30
src/MCT.js
30
src/MCT.js
@ -41,6 +41,7 @@ define([
|
||||
'./styles-new/core.scss',
|
||||
'./styles-new/notebook.scss',
|
||||
'./ui/components/layout/Layout.vue',
|
||||
'../platform/core/src/capabilities/ContextualDomainObject',
|
||||
'vue'
|
||||
], function (
|
||||
EventEmitter,
|
||||
@ -63,6 +64,7 @@ define([
|
||||
coreStyles,
|
||||
NotebookStyles,
|
||||
Layout,
|
||||
ContextualDomainObject,
|
||||
Vue
|
||||
) {
|
||||
/**
|
||||
@ -241,6 +243,34 @@ define([
|
||||
this.legacyBundle.extensions[category].push(extension);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a legacy object, for compatibility purposes only. This method
|
||||
* will be deprecated and removed in the future.
|
||||
* @private
|
||||
*/
|
||||
MCT.prototype.legacyObject = function (domainObject) {
|
||||
if (Array.isArray(domainObject)) {
|
||||
// an array of domain objects. [object, ...ancestors] representing
|
||||
// a single object with a given chain of ancestors. We instantiate
|
||||
// as a single contextual domain object.
|
||||
return domainObject
|
||||
.map((o) => {
|
||||
let keyString = objectUtils.makeKeyString(o.identifier);
|
||||
let oldModel = objectUtils.toOldFormat(o);
|
||||
return this.$injector.get('instantiate')(oldModel, keyString);
|
||||
})
|
||||
.reverse()
|
||||
.reduce((parent, child) => {
|
||||
return new ContextualDomainObject(child, parent);
|
||||
});
|
||||
|
||||
} else {
|
||||
let keyString = objectUtils.makeKeyString(domainObject.identifier);
|
||||
let oldModel = objectUtils.toOldFormat(domainObject);
|
||||
return this.$injector.get('instantiate')(oldModel, keyString);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set path to where assets are hosted. This should be the path to main.js.
|
||||
* @memberof module:openmct.MCT#
|
||||
|
@ -177,7 +177,11 @@ define([
|
||||
CompositionCollection.prototype.load = function () {
|
||||
return this.provider.load(this.domainObject)
|
||||
.then(function (children) {
|
||||
return Promise.all(children.map(this.onProviderAdd, this));
|
||||
return Promise.all(children.map((c) => this.publicAPI.objects.get(c)));
|
||||
}.bind(this))
|
||||
.then(function (childObjects) {
|
||||
childObjects.forEach(c => this.add(c, true));
|
||||
return childObjects;
|
||||
}.bind(this))
|
||||
.then(function (children) {
|
||||
this.emit('load');
|
||||
|
160
src/plugins/folderView/components/GridItem.vue
Normal file
160
src/plugins/folderView/components/GridItem.vue
Normal file
@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<a class="l-grid-view__item c-grid-item"
|
||||
:class="{ 'is-alias': item.isAlias === true }"
|
||||
:href="objectLink">
|
||||
<div class="c-grid-item__type-icon"
|
||||
:class="(item.type.cssClass != undefined) ? 'bg-' + item.type.cssClass : 'bg-icon-object-unknown'">
|
||||
</div>
|
||||
<div class="c-grid-item__details">
|
||||
<!-- Name and metadata -->
|
||||
<div class="c-grid-item__name"
|
||||
:title="item.model.name">{{item.model.name}}</div>
|
||||
<div class="c-grid-item__metadata"
|
||||
:title="item.type.name">
|
||||
<span class="c-grid-item__metadata__type">{{item.type.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="c-grid-item__controls">
|
||||
<div class="icon-people" title='Shared'></div>
|
||||
<button class="c-click-icon icon-info c-info-button" title='More Info'></button>
|
||||
<div class="icon-pointer-right c-pointer-icon"></div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
/******************************* GRID ITEMS */
|
||||
.c-grid-item {
|
||||
// Mobile-first
|
||||
@include button($bg: $colorItemBg, $fg: $colorItemFg);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
padding: $interiorMarginLg;
|
||||
|
||||
&__type-icon {
|
||||
filter: $colorKeyFilter;
|
||||
flex: 0 0 $gridItemMobile;
|
||||
font-size: floor($gridItemMobile / 2);
|
||||
margin-right: $interiorMarginLg;
|
||||
}
|
||||
|
||||
&.is-alias {
|
||||
// Object is an alias to an original.
|
||||
[class*='__type-icon'] {
|
||||
@include isAlias();
|
||||
color: $colorIconAliasForKeyFilter;
|
||||
}
|
||||
}
|
||||
|
||||
&__details {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&__name {
|
||||
@include ellipsize();
|
||||
color: $colorItemFg;
|
||||
font-size: 1.2em;
|
||||
font-weight: 400;
|
||||
margin-bottom: $interiorMarginSm;
|
||||
}
|
||||
|
||||
&__metadata {
|
||||
color: $colorItemFgDetails;
|
||||
font-size: 0.9em;
|
||||
|
||||
body.mobile & {
|
||||
[class*='__item-count'] {
|
||||
&:before {
|
||||
content: ' - ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__controls {
|
||||
color: $colorItemFgDetails;
|
||||
flex: 0 0 64px;
|
||||
font-size: 1.2em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
body.desktop & {
|
||||
$transOutMs: 300ms;
|
||||
flex-flow: column nowrap;
|
||||
transition: background $transOutMs ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background: $colorItemBgHov;
|
||||
transition: $transIn;
|
||||
|
||||
.c-grid-item__type-icon {
|
||||
filter: $colorKeyFilterHov;
|
||||
transform: scale(1);
|
||||
transition: $transInBounce;
|
||||
}
|
||||
}
|
||||
|
||||
> * {
|
||||
margin: 0; // Reset from mobile
|
||||
}
|
||||
|
||||
&__controls {
|
||||
align-items: start;
|
||||
flex: 0 0 auto;
|
||||
order: 1;
|
||||
.c-info-button,
|
||||
.c-pointer-icon { display: none; }
|
||||
}
|
||||
|
||||
&__type-icon {
|
||||
flex: 1 1 auto;
|
||||
font-size: floor($gridItemDesk / 3);
|
||||
margin: $interiorMargin 22.5% $interiorMargin * 3 22.5%;
|
||||
order: 2;
|
||||
transform: scale(0.9);
|
||||
transform-origin: center;
|
||||
transition: all $transOutMs ease-in-out;
|
||||
}
|
||||
|
||||
&__details {
|
||||
flex: 0 0 auto;
|
||||
justify-content: flex-end;
|
||||
order: 3;
|
||||
}
|
||||
|
||||
&__metadata {
|
||||
display: flex;
|
||||
|
||||
&__type {
|
||||
flex: 1 1 auto;
|
||||
@include ellipsize();
|
||||
}
|
||||
|
||||
&__item-count {
|
||||
opacity: 0.7;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import contextMenu from '../../../ui/components/mixins/context-menu';
|
||||
import objectLink from '../../../ui/components/mixins/object-link';
|
||||
|
||||
export default {
|
||||
mixins: [contextMenu, objectLink],
|
||||
props: ['item']
|
||||
}
|
||||
</script>
|
@ -1,28 +1,10 @@
|
||||
<template>
|
||||
<div class="l-grid-view">
|
||||
<div v-for="(item, index) in items"
|
||||
v-bind:key="index"
|
||||
class="l-grid-view__item c-grid-item"
|
||||
:class="{ 'is-alias': item.isAlias === true }"
|
||||
@click="navigate(item)">
|
||||
<div class="c-grid-item__type-icon"
|
||||
:class="(item.type.cssClass != undefined) ? 'bg-' + item.type.cssClass : 'bg-icon-object-unknown'">
|
||||
</div>
|
||||
<div class="c-grid-item__details">
|
||||
<!-- Name and metadata -->
|
||||
<div class="c-grid-item__name"
|
||||
:title="item.model.name">{{item.model.name}}</div>
|
||||
<div class="c-grid-item__metadata"
|
||||
:title="item.type.name">
|
||||
<span class="c-grid-item__metadata__type">{{item.type.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="c-grid-item__controls">
|
||||
<div class="icon-people" title='Shared'></div>
|
||||
<button class="c-click-icon icon-info c-info-button" title='More Info'></button>
|
||||
<div class="icon-pointer-right c-pointer-icon"></div>
|
||||
</div>
|
||||
</div>
|
||||
<grid-item v-for="(item, index) in items"
|
||||
:key="index"
|
||||
:item="item"
|
||||
:object-path="item.objectPath">
|
||||
</grid-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -177,17 +159,11 @@
|
||||
<script>
|
||||
|
||||
import compositionLoader from './composition-loader';
|
||||
import GridItem from './GridItem.vue';
|
||||
|
||||
export default {
|
||||
components: {GridItem},
|
||||
mixins: [compositionLoader],
|
||||
inject: ['domainObject', 'openmct'],
|
||||
methods: {
|
||||
navigate(item) {
|
||||
let currentLocation = this.openmct.router.currentLocation.path,
|
||||
navigateToPath = `${currentLocation}/${this.openmct.objects.makeKeyString(item.model.identifier)}`;
|
||||
|
||||
this.openmct.router.setPath(navigateToPath);
|
||||
}
|
||||
}
|
||||
inject: ['openmct']
|
||||
}
|
||||
</script>
|
||||
|
72
src/plugins/folderView/components/ListItem.vue
Normal file
72
src/plugins/folderView/components/ListItem.vue
Normal file
@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<tr class="c-list-item"
|
||||
:class="{ 'is-alias': item.isAlias === true }"
|
||||
@click="navigate">
|
||||
<td class="c-list-item__name">
|
||||
<a :href="objectLink" ref="objectLink">
|
||||
<div class="c-list-item__type-icon"
|
||||
:class="item.type.cssClass"></div>
|
||||
{{item.model.name}}
|
||||
</a>
|
||||
</td>
|
||||
<td class="c-list-item__type">{{ item.type.name }}</td>
|
||||
<td class="c-list-item__date-created">{{ formatTime(item.model.persisted, 'YYYY-MM-DD HH:mm:ss:SSS') }}Z</td>
|
||||
<td class="c-list-item__date-updated">{{ formatTime(item.model.modified, 'YYYY-MM-DD HH:mm:ss:SSS') }}Z</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
/******************************* LIST ITEM */
|
||||
.c-list-item {
|
||||
&__name {
|
||||
@include ellipsize();
|
||||
}
|
||||
|
||||
&__type-icon {
|
||||
color: $colorKey;
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
margin-right:$interiorMarginSm;
|
||||
}
|
||||
|
||||
&.is-alias {
|
||||
// Object is an alias to an original.
|
||||
[class*='__type-icon'] {
|
||||
&:after {
|
||||
color: $colorIconAlias;
|
||||
content: $glyph-icon-link;
|
||||
font-family: symbolsfont;
|
||||
display: block;
|
||||
position: absolute;
|
||||
text-shadow: rgba(black, 0.5) 0 1px 2px;
|
||||
top: auto; left: -1px; bottom: 1px; right: auto;
|
||||
transform-origin: bottom left;
|
||||
transform: scale(0.65);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
import moment from 'moment';
|
||||
import contextMenu from '../../../ui/components/mixins/context-menu';
|
||||
import objectLink from '../../../ui/components/mixins/object-link';
|
||||
|
||||
export default {
|
||||
mixins: [contextMenu, objectLink],
|
||||
props: ['item'],
|
||||
methods: {
|
||||
formatTime(timestamp, format) {
|
||||
return moment(timestamp).format(format);
|
||||
},
|
||||
navigate() {
|
||||
this.$refs.objectLink.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -2,60 +2,50 @@
|
||||
<div class="c-table c-table--sortable c-list-view">
|
||||
<table class="c-table__body">
|
||||
<thead class="c-table__header">
|
||||
<tr>
|
||||
<th class="is-sortable"
|
||||
:class="{
|
||||
'is-sorting': sortBy === 'model.name',
|
||||
'asc': ascending,
|
||||
'desc': !ascending
|
||||
}"
|
||||
@click="sort('model.name', true)">
|
||||
Name
|
||||
</th>
|
||||
<th class="is-sortable"
|
||||
:class="{
|
||||
'is-sorting': sortBy === 'type.name',
|
||||
'asc': ascending,
|
||||
'desc': !ascending
|
||||
}"
|
||||
@click="sort('type.name', true)">
|
||||
Type
|
||||
</th>
|
||||
<th class="is-sortable"
|
||||
:class="{
|
||||
'is-sorting': sortBy === 'model.persisted',
|
||||
'asc': ascending,
|
||||
'desc': !ascending
|
||||
}"
|
||||
@click="sort('model.persisted', false)">
|
||||
Created Date
|
||||
</th>
|
||||
<th class="is-sortable"
|
||||
:class="{
|
||||
'is-sorting': sortBy === 'model.modified',
|
||||
'asc': ascending,
|
||||
'desc': !ascending
|
||||
}"
|
||||
@click="sort('model.modified', false)">
|
||||
Updated Date
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="is-sortable"
|
||||
:class="{
|
||||
'is-sorting': sortBy === 'model.name',
|
||||
'asc': ascending,
|
||||
'desc': !ascending
|
||||
}"
|
||||
@click="sort('model.name', true)">
|
||||
Name
|
||||
</th>
|
||||
<th class="is-sortable"
|
||||
:class="{
|
||||
'is-sorting': sortBy === 'type.name',
|
||||
'asc': ascending,
|
||||
'desc': !ascending
|
||||
}"
|
||||
@click="sort('type.name', true)">
|
||||
Type
|
||||
</th>
|
||||
<th class="is-sortable"
|
||||
:class="{
|
||||
'is-sorting': sortBy === 'model.persisted',
|
||||
'asc': ascending,
|
||||
'desc': !ascending
|
||||
}"
|
||||
@click="sort('model.persisted', false)">
|
||||
Created Date
|
||||
</th>
|
||||
<th class="is-sortable"
|
||||
:class="{
|
||||
'is-sorting': sortBy === 'model.modified',
|
||||
'asc': ascending,
|
||||
'desc': !ascending
|
||||
}"
|
||||
@click="sort('model.modified', false)">
|
||||
Updated Date
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="c-list-item"
|
||||
v-for="(item,index) in sortedItems"
|
||||
v-bind:key="index"
|
||||
:class="{ 'is-alias': item.isAlias === true }"
|
||||
@click="navigate(item)">
|
||||
<td class="c-list-item__name">
|
||||
<div class="c-list-item__type-icon"
|
||||
:class="item.type.cssClass"></div>
|
||||
{{item.model.name}}
|
||||
</td>
|
||||
<td class="c-list-item__type">{{ item.type.name }}</td>
|
||||
<td class="c-list-item__date-created">{{ formatTime(item.model.persisted, 'YYYY-MM-DD HH:mm:ss:SSS') }}Z</td>
|
||||
<td class="c-list-item__date-updated">{{ formatTime(item.model.modified, 'YYYY-MM-DD HH:mm:ss:SSS') }}Z</td>
|
||||
</tr>
|
||||
<list-item v-for="(item,index) in sortedItems"
|
||||
:item="item"
|
||||
:object-path="item.objectPath">
|
||||
</list-item>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -96,48 +86,16 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-list-item {
|
||||
&__name {
|
||||
@include ellipsize();
|
||||
}
|
||||
|
||||
&__type-icon {
|
||||
color: $colorKey;
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
margin-right:$interiorMarginSm;
|
||||
}
|
||||
|
||||
&.is-alias {
|
||||
// Object is an alias to an original.
|
||||
[class*='__type-icon'] {
|
||||
&:after {
|
||||
color: $colorIconAlias;
|
||||
content: $glyph-icon-link;
|
||||
font-family: symbolsfont;
|
||||
display: block;
|
||||
position: absolute;
|
||||
text-shadow: rgba(black, 0.5) 0 1px 2px;
|
||||
top: auto; left: -1px; bottom: 1px; right: auto;
|
||||
transform-origin: bottom left;
|
||||
transform: scale(0.65);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************* LIST ITEM */
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
import lodash from 'lodash';
|
||||
import moment from 'moment';
|
||||
import compositionLoader from './composition-loader';
|
||||
import ListItem from './ListItem.vue';
|
||||
|
||||
export default {
|
||||
components: {ListItem},
|
||||
mixins: [compositionLoader],
|
||||
inject: ['domainObject', 'openmct'],
|
||||
data() {
|
||||
@ -156,15 +114,6 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatTime(timestamp, format) {
|
||||
return moment(timestamp).format(format);
|
||||
},
|
||||
navigate(item) {
|
||||
let currentLocation = this.openmct.router.currentLocation.path,
|
||||
navigateToPath = `${currentLocation}/${this.openmct.objects.makeKeyString(item.model.identifier)}`;
|
||||
|
||||
this.openmct.router.setPath(navigateToPath);
|
||||
},
|
||||
sort(field, defaultDirection) {
|
||||
if (this.sortBy === field) {
|
||||
this.ascending = !this.ascending;
|
||||
|
@ -31,16 +31,19 @@ export default {
|
||||
methods: {
|
||||
add(child, index, anything) {
|
||||
var type = this.openmct.types.get(child.type) || unknownObjectType;
|
||||
|
||||
this.items.push({
|
||||
model: child,
|
||||
type: type.definition,
|
||||
isAlias: this.domainObject.identifier.key !== child.location
|
||||
isAlias: this.domainObject.identifier.key !== child.location,
|
||||
objectPath: [child].concat(openmct.router.path)
|
||||
});
|
||||
},
|
||||
remove(child) {
|
||||
// TODO: implement remove action
|
||||
console.log('remove child? might be identifier');
|
||||
remove(identifier) {
|
||||
this.items = this.items
|
||||
.filter((i) => {
|
||||
return i.model.identifier.key !== identifier.key
|
||||
|| i.model.identifier.namespace !== identifier.namespace
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,51 +2,37 @@
|
||||
<a class="c-tree__item__label"
|
||||
draggable="true"
|
||||
@dragstart="dragStart"
|
||||
:href="urlLink">
|
||||
:href="objectLink">
|
||||
<div class="c-tree__item__type-icon"
|
||||
:class="cssClass"></div>
|
||||
:class="typeClass"></div>
|
||||
<div class="c-tree__item__name">{{ domainObject.name }}</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import ContextMenu from '../mixins/context-menu';
|
||||
import ObjectLink from '../mixins/object-link';
|
||||
|
||||
export default {
|
||||
mixins: [ContextMenu, ObjectLink],
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
'domainObject': Object,
|
||||
'path': Array
|
||||
},
|
||||
computed: {
|
||||
urlLink() {
|
||||
if (!this.path) {
|
||||
return;
|
||||
typeClass() {
|
||||
let type = this.openmct.types.get(this.domainObject.type);
|
||||
if (!type) {
|
||||
return 'icon-object-unknown';
|
||||
}
|
||||
return '#/browse/' + this.path
|
||||
.map(o => this.openmct.objects.makeKeyString(o))
|
||||
.join('/');
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cssClass: 'icon-object-unknown'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let type = this.openmct.types.get(this.domainObject.type);
|
||||
|
||||
if (type.definition.cssClass) {
|
||||
this.cssClass = type.definition.cssClass;
|
||||
} else {
|
||||
console.log("Failed to get typeDef.cssClass for object", this.domainObject.name, this.domainObject.type);
|
||||
return type.definition.cssClass;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
dragStart(event) {
|
||||
event.dataTransfer.setData("domainObject", JSON.stringify(this.domainObject));
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -114,7 +114,7 @@
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(c.identifier),
|
||||
object: c,
|
||||
path: [c.identifier]
|
||||
objectPath: [c]
|
||||
};
|
||||
}))
|
||||
},
|
||||
|
@ -7,7 +7,9 @@
|
||||
:expanded="expanded"
|
||||
@click="toggleChildren">
|
||||
</view-control>
|
||||
<object-label :domainObject="node.object" :path="node.path"></object-label>
|
||||
<object-label :domainObject="node.object"
|
||||
:objectPath="node.objectPath">
|
||||
</object-label>
|
||||
</div>
|
||||
<ul v-if="expanded" class="c-tree">
|
||||
<tree-item v-for="child in children"
|
||||
@ -76,12 +78,13 @@
|
||||
this.children.push({
|
||||
id: this.openmct.objects.makeKeyString(child.identifier),
|
||||
object: child,
|
||||
path: this.node.path.concat([child.identifier])
|
||||
objectPath: [child].concat(this.node.objectPath)
|
||||
});
|
||||
},
|
||||
removeChild(child) {
|
||||
// TODO: remove child on remove event.
|
||||
console.log('Tree should remove child', child);
|
||||
removeChild(identifier) {
|
||||
let removeId = this.openmct.objects.makeKeyString(identifier);
|
||||
this.children = this.children
|
||||
.filter(c => c.id !== removeId);
|
||||
},
|
||||
finishLoading () {
|
||||
this.isLoading = false;
|
||||
|
38
src/ui/components/mixins/context-menu.js
Normal file
38
src/ui/components/mixins/context-menu.js
Normal file
@ -0,0 +1,38 @@
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
'objectPath': {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// TODO: handle mobile contet menu listeners.
|
||||
this.$el.addEventListener('contextmenu', this.showContextMenu);
|
||||
this.objectPath.forEach((o, i) => {
|
||||
let removeListener = this.openmct.objects.observe(
|
||||
o,
|
||||
'*',
|
||||
(newDomainObject) => {
|
||||
this.objectPath.splice(i, 1, newDomainObject);
|
||||
}
|
||||
);
|
||||
this.$once('hook:destroyed', removeListener);
|
||||
});
|
||||
},
|
||||
destroyed() {
|
||||
this.$el.removeEventListener('contextmenu', this.showContextMenu);
|
||||
},
|
||||
methods: {
|
||||
showContextMenu(event) {
|
||||
let legacyObject = this.openmct.legacyObject(this.objectPath);
|
||||
legacyObject.getCapability('action').perform({
|
||||
key: 'menu',
|
||||
domainObject: legacyObject,
|
||||
event: event
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
22
src/ui/components/mixins/object-link.js
Normal file
22
src/ui/components/mixins/object-link.js
Normal file
@ -0,0 +1,22 @@
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
'objectPath': {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
objectLink() {
|
||||
if (!this.objectPath.length) {
|
||||
return;
|
||||
}
|
||||
return '#/browse/' + this.objectPath
|
||||
.map(o => this.openmct.objects.makeKeyString(o.identifier))
|
||||
.reverse()
|
||||
.join('/');
|
||||
}
|
||||
}
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user