Compare commits

...

8 Commits

Author SHA1 Message Date
7a0041b663 Add static root plugin files 2022-01-28 11:43:15 -06:00
44f5372c31 fix typo when using fallback template (#4784) 2022-01-26 13:34:22 -08:00
2f292fbd07 Follow domain object changes for Independent time conductor (#4783)
* Track if domain object changes when independent time conductor is in use.
2022-01-26 13:04:47 -08:00
205dc67809 Observe changes to sub-objects in flexible layouts. (#4780)
* Get child of flex layout as mutable if possible

* Fix bug when no default notebook defined
2022-01-25 23:22:42 -08:00
169c23dbcc update copyright (#4775) 2022-01-25 12:27:27 -08:00
457cd42987 Update version number (#4759) 2022-01-20 18:57:05 -08:00
45373c56f7 [MCT Tree] Enhance to be used as selection tree as well (#4734)
* removed selector tree, using mct-tree for selctor now, updated style view to use new forms api, update mct-tree to be a selector if need be

* added some extra calculations for height when the tree is being used as a selector in forms

Co-authored-by: Shefali Joshi <simplyrender@gmail.com>
2022-01-21 02:46:40 +00:00
91e909bb4a Fix notebook sync (#4738)
* Do not keep fetching default notebook

* Fixes issue where notebooks would stop listening for remote changes.

* Fix issue with notebook merge conflicts
2022-01-20 18:43:17 -08:00
33 changed files with 251 additions and 643 deletions

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -195,6 +195,7 @@
)); ));
openmct.install(openmct.plugins.Clock({ enableClockIndicator: true })); openmct.install(openmct.plugins.Clock({ enableClockIndicator: true }));
openmct.install(openmct.plugins.Timer()); openmct.install(openmct.plugins.Timer());
openmct.install(openmct.plugins.StaticRootPlugin('root', './dist/static-root.json'));
openmct.start(); openmct.start();
</script> </script>
</html> </html>

View File

@ -1,6 +1,6 @@
{ {
"name": "openmct", "name": "openmct",
"version": "1.8.4-SNAPSHOT", "version": "1.8.4",
"description": "The Open MCT core platform", "description": "The Open MCT core platform",
"devDependencies": { "devDependencies": {
"@braintree/sanitize-url": "^5.0.2", "@braintree/sanitize-url": "^5.0.2",

View File

@ -21,19 +21,19 @@
*****************************************************************************/ *****************************************************************************/
<template> <template>
<SelectorDialogTree :ignore-type-check="true" <mct-tree
:css-class="`form-locator c-form-control--locator`" :is-selector-tree="true"
:parent="model.parent" :initial-selection="model.parent"
@treeItemSelected="handleItemSelection" @tree-item-selection="handleItemSelection"
/> />
</template> </template>
<script> <script>
import SelectorDialogTree from '@/ui/components/SelectorDialogTree.vue'; import MctTree from '@/ui/layout/mct-tree.vue';
export default { export default {
components: { components: {
SelectorDialogTree MctTree
}, },
inject: ['openmct'], inject: ['openmct'],
props: { props: {
@ -43,10 +43,10 @@ export default {
} }
}, },
methods: { methods: {
handleItemSelection({ parentObjectPath }) { handleItemSelection(item) {
const data = { const data = {
model: this.model, model: this.model,
value: parentObjectPath value: item.objectPath
}; };
this.$emit('onChange', data); this.$emit('onChange', data);

View File

@ -465,23 +465,6 @@ ObjectAPI.prototype.mutate = function (domainObject, path, value) {
} }
}; };
/**
* Updates a domain object based on its latest persisted state. Note that this will mutate the provided object.
* @param {module:openmct.DomainObject} domainObject an object to refresh from its persistence store
* @returns {Promise} the provided object, updated to reflect the latest persisted state of the object.
*/
ObjectAPI.prototype.refresh = async function (domainObject) {
const refreshedObject = await this.get(domainObject.identifier);
if (domainObject.isMutable) {
domainObject.$refresh(refreshedObject);
} else {
utils.refresh(domainObject, refreshedObject);
}
return domainObject;
};
/** /**
* @private * @private
*/ */

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -148,10 +148,8 @@ import FontStyleEditor from '@/ui/inspector/styles/FontStyleEditor.vue';
import StyleEditor from "./StyleEditor.vue"; import StyleEditor from "./StyleEditor.vue";
import PreviewAction from "@/ui/preview/PreviewAction.js"; import PreviewAction from "@/ui/preview/PreviewAction.js";
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionSetIdentifierForItem } from "@/plugins/condition/utils/styleUtils"; import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionSetIdentifierForItem } from "@/plugins/condition/utils/styleUtils";
import SelectorDialogTree from '@/ui/components/SelectorDialogTree.vue';
import ConditionError from "@/plugins/condition/components/ConditionError.vue"; import ConditionError from "@/plugins/condition/components/ConditionError.vue";
import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue"; import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue";
import Vue from 'vue';
const NON_SPECIFIC = '??'; const NON_SPECIFIC = '??';
const NON_STYLEABLE_CONTAINER_TYPES = [ const NON_STYLEABLE_CONTAINER_TYPES = [
@ -551,53 +549,28 @@ export default {
return this.conditions ? this.conditions[id] : {}; return this.conditions ? this.conditions[id] : {};
}, },
addConditionSet() { addConditionSet() {
let conditionSetDomainObject; const conditionWidgetParent = this.openmct.router.path[1];
let self = this; const formStructure = {
function handleItemSelection({ item }) { title: 'Select Condition Set',
if (item) { sections: [{
conditionSetDomainObject = item; name: 'Location',
} cssClass: 'grows',
} rows: [{
key: 'location',
function dismissDialog(overlay, initialize) { name: 'Condition Set',
overlay.dismiss(); cssClass: 'grows',
control: 'locator',
if (initialize && conditionSetDomainObject) { required: true,
self.conditionSetDomainObject = conditionSetDomainObject; parent: conditionWidgetParent,
self.conditionalStyles = []; validate: data => data.value[0].type === 'conditionSet'
self.initializeConditionalStyles(); }]
} }]
}
let vm = new Vue({
components: { SelectorDialogTree },
provide: {
openmct: this.openmct
},
data() {
return {
handleItemSelection,
title: 'Select Condition Set'
}; };
},
template: '<SelectorDialogTree :title="title" @treeItemSelected="handleItemSelection"></SelectorDialogTree>'
}).$mount();
let overlay = this.openmct.overlays.overlay({ this.openmct.forms.showForm(formStructure).then(data => {
element: vm.$el, this.conditionSetDomainObject = data.location[0];
size: 'small', this.conditionalStyles = [];
buttons: [ this.initializeConditionalStyles();
{
label: 'OK',
emphasis: 'true',
callback: () => dismissDialog(overlay, true)
},
{
label: 'Cancel',
callback: () => dismissDialog(overlay, false)
}
],
onDestroy: () => vm.$destroy()
}); });
}, },
removeConditionSet() { removeConditionSet() {

View File

@ -97,7 +97,14 @@ export default {
}, },
mounted() { mounted() {
if (this.frame.domainObjectIdentifier) { if (this.frame.domainObjectIdentifier) {
this.openmct.objects.get(this.frame.domainObjectIdentifier).then((object) => { let domainObjectPromise;
if (this.openmct.objects.supportsMutation(this.frame.domainObjectIdentifier)) {
domainObjectPromise = this.openmct.objects.getMutable(this.frame.domainObjectIdentifier);
} else {
domainObjectPromise = this.openmct.objects.get(this.frame.domainObjectIdentifier);
}
domainObjectPromise.then((object) => {
this.setDomainObject(object); this.setDomainObject(object);
}); });
} }
@ -105,6 +112,10 @@ export default {
this.dragGhost = document.getElementById('js-fl-drag-ghost'); this.dragGhost = document.getElementById('js-fl-drag-ghost');
}, },
beforeDestroy() { beforeDestroy() {
if (this.domainObject.isMutable) {
this.openmct.objects.destroyMutable(this.domainObject);
}
if (this.unsubscribeSelection) { if (this.unsubscribeSelection) {
this.unsubscribeSelection(); this.unsubscribeSelection();
} }

View File

@ -322,7 +322,7 @@ export default {
cleanupDefaultNotebook() { cleanupDefaultNotebook() {
this.defaultPageId = undefined; this.defaultPageId = undefined;
this.defaultSectionId = undefined; this.defaultSectionId = undefined;
this.removeDefaultClass(this.domainObject); this.removeDefaultClass(this.domainObject.identifier);
clearDefaultNotebook(); clearDefaultNotebook();
}, },
setSectionAndPageFromUrl() { setSectionAndPageFromUrl() {
@ -619,12 +619,8 @@ export default {
this.sectionsChanged({ sections }); this.sectionsChanged({ sections });
}, },
removeDefaultClass(defaultNotebookIdentifier) { removeDefaultClass(identifier) {
if (!defaultNotebookIdentifier) { this.openmct.status.delete(identifier);
return;
}
this.openmct.status.delete(defaultNotebookIdentifier);
}, },
resetSearch() { resetSearch() {
this.search = ''; this.search = '';
@ -633,27 +629,25 @@ export default {
toggleNav() { toggleNav() {
this.showNav = !this.showNav; this.showNav = !this.showNav;
}, },
updateDefaultNotebook(notebookStorage) { updateDefaultNotebook(updatedNotebookStorageObject) {
const defaultNotebook = getDefaultNotebook(); if (!this.isDefaultNotebook()) {
const defaultNotebookIdentifier = defaultNotebook && defaultNotebook.identifier; const persistedNotebookStorageObject = getDefaultNotebook();
const isSameNotebook = defaultNotebookIdentifier if (persistedNotebookStorageObject
&& this.openmct.objects.areIdsEqual(defaultNotebookIdentifier, notebookStorage.identifier); && persistedNotebookStorageObject.identifier !== undefined) {
if (!isSameNotebook) { this.removeDefaultClass(persistedNotebookStorageObject.identifier);
this.removeDefaultClass(defaultNotebookIdentifier);
} }
if (!defaultNotebookIdentifier || !isSameNotebook) { setDefaultNotebook(this.openmct, updatedNotebookStorageObject, this.domainObject);
setDefaultNotebook(this.openmct, notebookStorage, this.domainObject);
} }
if (this.defaultSectionId !== notebookStorage.defaultSectionId) { if (this.defaultSectionId !== updatedNotebookStorageObject.defaultSectionId) {
setDefaultNotebookSectionId(notebookStorage.defaultSectionId); setDefaultNotebookSectionId(updatedNotebookStorageObject.defaultSectionId);
this.defaultSectionId = notebookStorage.defaultSectionId; this.defaultSectionId = updatedNotebookStorageObject.defaultSectionId;
} }
if (this.defaultPageId !== notebookStorage.defaultPageId) { if (this.defaultPageId !== updatedNotebookStorageObject.defaultPageId) {
setDefaultNotebookPageId(notebookStorage.defaultPageId); setDefaultNotebookPageId(updatedNotebookStorageObject.defaultPageId);
this.defaultPageId = notebookStorage.defaultPageId; this.defaultPageId = updatedNotebookStorageObject.defaultPageId;
} }
}, },
updateDefaultNotebookSection(sections, id) { updateDefaultNotebookSection(sections, id) {
@ -671,7 +665,7 @@ export default {
if (defaultNotebookSectionId === id) { if (defaultNotebookSectionId === id) {
const section = sections.find(s => s.id === id); const section = sections.find(s => s.id === id);
if (!section) { if (!section) {
this.removeDefaultClass(this.domainObject); this.removeDefaultClass(this.domainObject.identifier);
clearDefaultNotebook(); clearDefaultNotebook();
return; return;

View File

@ -8,6 +8,7 @@ export default function (openmct) {
return apiSave(domainObject); return apiSave(domainObject);
} }
const isNewMutable = !domainObject.isMutable;
const localMutable = openmct.objects._toMutable(domainObject); const localMutable = openmct.objects._toMutable(domainObject);
let result; let result;
@ -20,18 +21,20 @@ export default function (openmct) {
result = Promise.reject(error); result = Promise.reject(error);
} }
} finally { } finally {
if (isNewMutable) {
openmct.objects.destroyMutable(localMutable); openmct.objects.destroyMutable(localMutable);
} }
}
return result; return result;
}; };
} }
function resolveConflicts(localMutable, openmct) { function resolveConflicts(localMutable, openmct) {
const localEntries = JSON.parse(JSON.stringify(localMutable.configuration.entries));
return openmct.objects.getMutable(localMutable.identifier).then((remoteMutable) => { return openmct.objects.getMutable(localMutable.identifier).then((remoteMutable) => {
const localEntries = localMutable.configuration.entries; applyLocalEntries(remoteMutable, localEntries, openmct);
remoteMutable.$refresh(remoteMutable);
applyLocalEntries(remoteMutable, localEntries);
openmct.objects.destroyMutable(remoteMutable); openmct.objects.destroyMutable(remoteMutable);
@ -39,7 +42,7 @@ function resolveConflicts(localMutable, openmct) {
}); });
} }
function applyLocalEntries(mutable, entries) { function applyLocalEntries(mutable, entries, openmct) {
Object.entries(entries).forEach(([sectionKey, pagesInSection]) => { Object.entries(entries).forEach(([sectionKey, pagesInSection]) => {
Object.entries(pagesInSection).forEach(([pageKey, localEntries]) => { Object.entries(pagesInSection).forEach(([pageKey, localEntries]) => {
const remoteEntries = mutable.configuration.entries[sectionKey][pageKey]; const remoteEntries = mutable.configuration.entries[sectionKey][pageKey];
@ -58,14 +61,15 @@ function applyLocalEntries(mutable, entries) {
locallyModifiedEntries.forEach((locallyModifiedEntry) => { locallyModifiedEntries.forEach((locallyModifiedEntry) => {
let mergedEntry = mergedEntries.find(entry => entry.id === locallyModifiedEntry.id); let mergedEntry = mergedEntries.find(entry => entry.id === locallyModifiedEntry.id);
if (mergedEntry !== undefined) { if (mergedEntry !== undefined
&& locallyModifiedEntry.text.match(/\S/)) {
mergedEntry.text = locallyModifiedEntry.text; mergedEntry.text = locallyModifiedEntry.text;
shouldMutate = true; shouldMutate = true;
} }
}); });
if (shouldMutate) { if (shouldMutate) {
mutable.$set(`configuration.entries.${sectionKey}.${pageKey}`, mergedEntries); openmct.objects.mutate(mutable, `configuration.entries.${sectionKey}.${pageKey}`, mergedEntries);
} }
}); });
}); });

View File

@ -120,7 +120,6 @@ export function addNotebookEntry(openmct, domainObject, notebookStorage, embed =
const newEntries = addEntryIntoPage(notebookStorage, entries, entry); const newEntries = addEntryIntoPage(notebookStorage, entries, entry);
addDefaultClass(domainObject, openmct); addDefaultClass(domainObject, openmct);
mutateObject(openmct, domainObject, 'configuration.entries', newEntries); mutateObject(openmct, domainObject, 'configuration.entries', newEntries);
return id; return id;

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -278,7 +278,7 @@ export default {
// Have to throw away the old canvas elements and replace with new // Have to throw away the old canvas elements and replace with new
// canvas elements in order to get new drawing contexts. // canvas elements in order to get new drawing contexts.
const div = document.createElement('div'); const div = document.createElement('div');
div.innerHTML = this.TEMPLATE; div.innerHTML = this.canvasTemplate + this.canvasTemplate;
const mainCanvas = div.querySelectorAll("canvas")[1]; const mainCanvas = div.querySelectorAll("canvas")[1];
const overlayCanvas = div.querySelectorAll("canvas")[0]; const overlayCanvas = div.querySelectorAll("canvas")[0];
this.canvas.parentNode.replaceChild(mainCanvas, this.canvas); this.canvas.parentNode.replaceChild(mainCanvas, this.canvas);

View File

@ -32,6 +32,8 @@ define([
} }
}); });
console.log(JSON.parse(objectString));
return JSON.parse(objectString); return JSON.parse(objectString);
} }

View File

@ -95,6 +95,11 @@ export default {
isUTCBased: timeSystem.isUTCBased isUTCBased: timeSystem.isUTCBased
}; };
}, },
watch: {
keyString() {
this.setTimeContext();
}
},
mounted() { mounted() {
this.handleNewBounds = _.throttle(this.handleNewBounds, 300); this.handleNewBounds = _.throttle(this.handleNewBounds, 300);
this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem()))); this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem())));

View File

@ -115,6 +115,11 @@ export default {
isUTCBased: timeSystem.isUTCBased isUTCBased: timeSystem.isUTCBased
}; };
}, },
watch: {
keyString() {
this.setTimeContext();
}
},
mounted() { mounted() {
this.handleNewBounds = _.throttle(this.handleNewBounds, 300); this.handleNewBounds = _.throttle(this.handleNewBounds, 300);
this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem()))); this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem())));

View File

@ -105,42 +105,49 @@ export default {
watch: { watch: {
domainObject: { domainObject: {
handler(domainObject) { handler(domainObject) {
const key = this.openmct.objects.makeKeyString(domainObject.identifier);
if (key !== this.keyString) {
//domain object has changed
this.destroyIndependentTime();
this.independentTCEnabled = domainObject.configuration.useIndependentTime === true; this.independentTCEnabled = domainObject.configuration.useIndependentTime === true;
this.timeOptions = domainObject.configuration.timeOptions || {
clockOffsets: this.openmct.time.clockOffsets(),
fixedOffsets: this.openmct.time.bounds()
};
if (!domainObject.configuration.timeOptions || !this.independentTCEnabled) { this.initialize();
this.destroyIndependentTime();
return;
}
if (this.timeOptions.start !== domainObject.configuration.timeOptions.start
|| this.timeOptions.end !== domainObject.configuration.timeOptions.end) {
this.timeOptions = domainObject.configuration.timeOptions;
this.destroyIndependentTime();
this.registerIndependentTimeOffsets();
} }
}, },
deep: true deep: true
} }
}, },
mounted() { mounted() {
this.setTimeContext(); this.initialize();
if (this.timeOptions.mode) {
this.mode = this.timeOptions.mode;
} else {
this.timeOptions.mode = this.mode = this.timeContext.clock() === undefined ? { key: 'fixed' } : { key: Object.create(this.timeContext.clock()).key};
}
if (this.independentTCEnabled) {
this.registerIndependentTimeOffsets();
}
}, },
beforeDestroy() { beforeDestroy() {
this.stopFollowingTimeContext(); this.stopFollowingTimeContext();
this.destroyIndependentTime(); this.destroyIndependentTime();
}, },
methods: { methods: {
initialize() {
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.setTimeContext();
if (this.timeOptions.mode) {
this.mode = this.timeOptions.mode;
} else {
if (this.timeContext.clock() === undefined) {
this.timeOptions.mode = this.mode = { key: 'fixed' };
} else {
this.timeOptions.mode = this.mode = { key: Object.create(this.timeContext.clock()).key};
}
}
if (this.independentTCEnabled) {
this.registerIndependentTimeOffsets();
}
},
toggleIndependentTC() { toggleIndependentTC() {
this.independentTCEnabled = !this.independentTCEnabled; this.independentTCEnabled = !this.independentTCEnabled;
if (this.independentTCEnabled) { if (this.independentTCEnabled) {
@ -213,10 +220,9 @@ export default {
offsets = this.timeOptions.clockOffsets; offsets = this.timeOptions.clockOffsets;
} }
const key = this.openmct.objects.makeKeyString(this.domainObject.identifier); const timeContext = this.openmct.time.getIndependentContext(this.keyString);
const timeContext = this.openmct.time.getIndependentContext(key);
if (!timeContext.hasOwnContext()) { if (!timeContext.hasOwnContext()) {
this.unregisterIndependentTime = this.openmct.time.addIndependentContext(key, offsets, this.isFixed ? undefined : this.mode.key); this.unregisterIndependentTime = this.openmct.time.addIndependentContext(this.keyString, offsets, this.isFixed ? undefined : this.mode.key);
} else { } else {
if (this.isFixed) { if (this.isFixed) {
timeContext.stopClock(); timeContext.stopClock();

View File

@ -1,5 +1,5 @@
<!-- <!--
Open MCT, Copyright (c) 2014-2021, United States Government Open MCT, Copyright (c) 2014-2022, United States Government
as represented by the Administrator of the National Aeronautics and Space as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved. Administration. All rights reserved.

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, United States Government * Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *

View File

@ -1,240 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="u-contents">
<div v-if="title.length"
class="c-overlay__top-bar"
>
<div class="c-overlay__dialog-title">{{ title }}</div>
</div>
<div class="c-selector c-tree-and-search"
:class="cssClass"
>
<div class="c-tree-and-search__search">
<Search ref="shell-search"
class="c-search"
:value="searchValue"
@input="searchTree"
@clear="searchTree"
/>
</div>
<div v-if="isLoading"
class="c-tree-and-search__loading loading"
></div>
<div v-if="shouldDisplayNoResultsText"
class="c-tree-and-search__no-results"
>
No results found
</div>
<ul v-if="!isLoading"
v-show="!searchValue"
class="c-tree-and-search__tree c-tree"
>
<SelectorDialogTreeItem
v-for="treeItem in allTreeItems"
:key="treeItem.id"
:node="treeItem"
:selected-item="selectedItem"
:handle-item-selected="handleItemSelection"
:navigate-to-parent="navigateToParent"
/>
</ul>
<ul v-if="searchValue && !isLoading"
class="c-tree-and-search__tree c-tree"
>
<SelectorDialogTreeItem
v-for="treeItem in filteredTreeItems"
:key="treeItem.id"
:node="treeItem"
:selected-item="selectedItem"
:handle-item-selected="handleItemSelection"
/>
</ul>
</div>
</div>
</template>
<script>
import debounce from 'lodash/debounce';
import Search from '@/ui/components/search.vue';
import SelectorDialogTreeItem from './SelectorDialogTreeItem.vue';
export default {
name: 'SelectorDialogTree',
components: {
Search,
SelectorDialogTreeItem
},
inject: ['openmct'],
props: {
cssClass: {
type: String,
required: false,
default() {
return '';
}
},
title: {
type: String,
required: false,
default() {
return '';
}
},
ignoreTypeCheck: {
type: Boolean,
required: false,
default() {
return false;
}
},
parent: {
type: Object,
required: false,
default() {
return undefined;
}
}
},
data() {
return {
allTreeItems: [],
expanded: false,
filteredTreeItems: [],
isLoading: false,
navigateToParent: undefined,
searchValue: '',
selectedItem: undefined
};
},
computed: {
shouldDisplayNoResultsText() {
if (this.isLoading) {
return false;
}
return this.allTreeItems.length === 0
|| (this.searchValue && this.filteredTreeItems.length === 0);
}
},
created() {
this.getDebouncedFilteredChildren = debounce(this.getFilteredChildren, 400);
},
mounted() {
if (this.parent) {
(async () => {
const objectPath = await this.openmct.objects.getOriginalPath(this.parent.identifier);
this.navigateToParent = '/browse/'
+ objectPath
.map(parent => this.openmct.objects.makeKeyString(parent.identifier))
.reverse()
.join('/');
this.getAllChildren(this.navigateToParent);
})();
} else {
this.getAllChildren();
}
},
methods: {
async aggregateFilteredChildren(results) {
for (const object of results) {
const objectPath = await this.openmct.objects.getOriginalPath(object.identifier);
const navigateToParent = '/browse/'
+ objectPath.slice(1)
.map(parent => this.openmct.objects.makeKeyString(parent.identifier))
.join('/');
const filteredChild = {
id: this.openmct.objects.makeKeyString(object.identifier),
object,
objectPath,
navigateToParent
};
this.filteredTreeItems.push(filteredChild);
}
},
getAllChildren(navigateToParent) {
this.isLoading = true;
this.openmct.objects.get('ROOT')
.then(root => {
return this.openmct.composition.get(root).load();
})
.then(children => {
this.isLoading = false;
this.allTreeItems = children.map(c => {
return {
id: this.openmct.objects.makeKeyString(c.identifier),
object: c,
objectPath: [c],
navigateToParent: navigateToParent || '/browse'
};
});
});
},
getFilteredChildren() {
// clear any previous search results
this.filteredTreeItems = [];
const promises = this.openmct.objects.search(this.searchValue)
.map(promise => promise
.then(results => this.aggregateFilteredChildren(results)));
Promise.all(promises).then(() => {
this.isLoading = false;
});
},
handleItemSelection(item, node) {
if (item && (this.ignoreTypeCheck || item.type === 'conditionSet')) {
const parentId = (node.objectPath && node.objectPath.length > 1) ? node.objectPath[1].identifier : undefined;
this.selectedItem = {
itemId: item.identifier,
parentId
};
this.$emit('treeItemSelected',
{
item,
parentObjectPath: node.objectPath
});
}
},
searchTree(value) {
this.searchValue = value;
this.isLoading = true;
if (this.searchValue !== '') {
this.getDebouncedFilteredChildren();
} else {
this.isLoading = false;
}
}
}
};
</script>

View File

@ -1,206 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2022, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<li class="c-tree__item-h">
<div
class="c-tree__item"
:class="{ 'is-alias': isAlias, 'is-navigated-object': navigated }"
@click="handleItemSelected(node.object, node)"
>
<view-control
v-model="expanded"
class="c-tree__item__view-control"
:enabled="hasChildren"
/>
<div class="c-tree__item__label c-object-label">
<div
class="c-tree__item__type-icon c-object-label__type-icon"
:class="typeClass"
></div>
<div class="c-tree__item__name c-object-label__name">{{ node.object.name }}</div>
</div>
</div>
<ul
v-if="expanded && !isLoading"
class="c-tree"
>
<li
v-if="isLoading && !loaded"
class="c-tree__item-h"
>
<div class="c-tree__item loading">
<span class="c-tree__item__label">Loading...</span>
</div>
</li>
<SelectorDialogTreeItem
v-for="child in children"
:key="child.id"
:node="child"
:selected-item="selectedItem"
:handle-item-selected="handleItemSelected"
:navigate-to-parent="navigateToParent"
/>
</ul>
</li>
</template>
<script>
import viewControl from '@/ui/components/viewControl.vue';
export default {
name: 'SelectorDialogTreeItem',
components: {
viewControl
},
inject: ['openmct'],
props: {
node: {
type: Object,
required: true
},
selectedItem: {
type: Object,
default() {
return undefined;
}
},
handleItemSelected: {
type: Function,
default() {
return (item) => {};
}
},
navigateToParent: {
type: String,
default() {
return undefined;
}
}
},
data() {
return {
hasChildren: false,
isLoading: false,
loaded: false,
children: [],
expanded: false
};
},
computed: {
navigated() {
const itemId = this.selectedItem && this.selectedItem.itemId;
const isSelectedObject = itemId && this.openmct.objects.areIdsEqual(this.node.object.identifier, itemId);
if (isSelectedObject && this.node.objectPath && this.node.objectPath.length > 1) {
const isParent = this.openmct.objects.areIdsEqual(this.node.objectPath[1].identifier, this.selectedItem.parentId);
return isSelectedObject && isParent;
}
return isSelectedObject;
},
isAlias() {
let parent = this.node.objectPath[1];
if (!parent) {
return false;
}
let parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
return parentKeyString !== this.node.object.location;
},
typeClass() {
let type = this.openmct.types.get(this.node.object.type);
if (!type) {
return 'icon-object-unknown';
}
return type.definition.cssClass;
}
},
watch: {
expanded() {
if (!this.hasChildren) {
return;
}
if (!this.loaded && !this.isLoading) {
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addChild);
this.composition.on('remove', this.removeChild);
this.composition.load().then(this.finishLoading);
this.isLoading = true;
}
}
},
mounted() {
this.domainObject = this.node.object;
if (this.navigateToParent && this.navigateToParent.includes(this.openmct.objects.makeKeyString(this.domainObject.identifier))) {
this.expanded = true;
}
if (this.navigateToParent && this.navigateToParent.endsWith(this.openmct.objects.makeKeyString(this.domainObject.identifier))) {
this.handleItemSelected(this.node.object, this.node);
}
let removeListener = this.openmct.objects.observe(this.domainObject, '*', (newObject) => {
this.domainObject = newObject;
});
this.$once('hook:destroyed', removeListener);
if (this.openmct.composition.get(this.node.object)) {
this.hasChildren = true;
}
},
beforeDestroy() {
this.expanded = false;
},
destroyed() {
if (this.composition) {
this.composition.off('add', this.addChild);
this.composition.off('remove', this.removeChild);
delete this.composition;
}
},
methods: {
addChild(child) {
this.children.push({
id: this.openmct.objects.makeKeyString(child.identifier),
object: child,
objectPath: [child].concat(this.node.objectPath),
navigateToParent: this.navigateToPath
});
},
removeChild(identifier) {
let removeId = this.openmct.objects.makeKeyString(identifier);
this.children = this.children
.filter(c => c.id !== removeId);
},
finishLoading() {
this.isLoading = false;
this.loaded = true;
}
}
};
</script>

View File

@ -280,38 +280,5 @@
border: 1px solid $colorFormLines; border: 1px solid $colorFormLines;
border-radius: $controlCr; border-radius: $controlCr;
padding: $interiorMargin; padding: $interiorMargin;
> .c-tree {
overflow: auto;
} }
} }
}
// TRANSITIONS
.children-enter-active {
&.down {
animation: animSlideLeft 500ms;
}
&.up {
animation: animSlideRight 500ms;
}
}
@keyframes animSlideLeft {
0% {opacity: 0; transform: translateX(100%);}
10% {opacity: 1;}
100% {transform: translateX(0);}
}
@keyframes animSlideRight {
0% {opacity: 0; transform: translateX(-100%);}
10% {opacity: 1;}
100% {transform: translateX(0);}
}
@keyframes animTemporaryHighlight {
from { background: transparent; }
30% { background: $colorItemTreeNewNode; }
100% { background: transparent; }
}

View File

@ -1,6 +1,12 @@
<template> <template>
<div class="c-tree-and-search"> <div
ref="treeContainer"
class="c-tree-and-search"
:class="{
'c-selector': isSelectorTree
}"
:style="treeHeight"
>
<div <div
ref="search" ref="search"
class="c-tree-and-search__search" class="c-tree-and-search__search"
@ -72,6 +78,8 @@
v-for="(treeItem, index) in visibleItems" v-for="(treeItem, index) in visibleItems"
:key="treeItem.navigationPath" :key="treeItem.navigationPath"
:node="treeItem" :node="treeItem"
:is-selector-tree="isSelectorTree"
:selected-item="selectedItem"
:active-search="activeSearch" :active-search="activeSearch"
:left-offset="!activeSearch ? treeItem.leftOffset : '0px'" :left-offset="!activeSearch ? treeItem.leftOffset : '0px'"
:is-new="treeItem.isNew" :is-new="treeItem.isNew"
@ -82,7 +90,8 @@
:loading-items="treeItemLoading" :loading-items="treeItemLoading"
@tree-item-mounted="scrollToCheck($event)" @tree-item-mounted="scrollToCheck($event)"
@tree-item-destroyed="removeCompositionListenerFor($event)" @tree-item-destroyed="removeCompositionListenerFor($event)"
@navigation-click="treeItemAction(treeItem, $event)" @tree-item-action="treeItemAction(treeItem, $event)"
@tree-item-selection="treeItemSelection(treeItem)"
/> />
<!-- main loading --> <!-- main loading -->
<div <div
@ -115,6 +124,7 @@ const ITEM_BUFFER = 25;
const LOCAL_STORAGE_KEY__TREE_EXPANDED = 'mct-tree-expanded'; const LOCAL_STORAGE_KEY__TREE_EXPANDED = 'mct-tree-expanded';
const SORT_MY_ITEMS_ALPH_ASC = true; const SORT_MY_ITEMS_ALPH_ASC = true;
const TREE_ITEM_INDENT_PX = 18; const TREE_ITEM_INDENT_PX = 18;
const LOCATOR_ITEM_COUNT_HEIGHT = 10; // how many tree items to make the locator selection box show
export default { export default {
name: 'MctTree', name: 'MctTree',
@ -124,13 +134,27 @@ export default {
}, },
inject: ['openmct'], inject: ['openmct'],
props: { props: {
isSelectorTree: {
type: Boolean,
required: false,
default() {
return false;
}
},
initialSelection: {
type: Object,
required: false,
default() {
return {};
}
},
syncTreeNavigation: { syncTreeNavigation: {
type: Boolean, type: Boolean,
required: true required: false
}, },
resetTreeNavigation: { resetTreeNavigation: {
type: Boolean, type: Boolean,
required: true required: false
} }
}, },
data() { data() {
@ -149,7 +173,8 @@ export default {
itemHeight: 27, itemHeight: 27,
itemOffset: 0, itemOffset: 0,
activeSearch: false, activeSearch: false,
mainTreeTopMargin: undefined mainTreeTopMargin: undefined,
selectedItem: {}
}; };
}, },
computed: { computed: {
@ -179,6 +204,13 @@ export default {
}, },
showNoSearchResults() { showNoSearchResults() {
return this.searchValue && this.searchResultItems.length === 0 && !this.searchLoading; return this.searchValue && this.searchResultItems.length === 0 && !this.searchLoading;
},
treeHeight() {
if (!this.isSelectorTree) {
return {};
} else {
return { height: this.itemHeight * LOCATOR_ITEM_COUNT_HEIGHT + 'px' };
}
} }
}, },
watch: { watch: {
@ -223,7 +255,14 @@ export default {
await this.loadRoot(); await this.loadRoot();
this.isLoading = false; this.isLoading = false;
if (!this.isSelectorTree) {
await this.syncTreeOpenItems(); await this.syncTreeOpenItems();
} else {
const objectPath = await this.openmct.objects.getOriginalPath(this.initialSelection.identifier);
const navigationPath = this.buildNavigationPath(objectPath);
this.openAndScrollTo(navigationPath);
}
}, },
created() { created() {
this.getSearchResults = _.debounce(this.getSearchResults, 400); this.getSearchResults = _.debounce(this.getSearchResults, 400);
@ -265,6 +304,10 @@ export default {
this.openTreeItem(parentItem); this.openTreeItem(parentItem);
} }
}, },
treeItemSelection(item) {
this.selectedItem = item;
this.$emit('tree-item-selection', item);
},
async openTreeItem(parentItem) { async openTreeItem(parentItem) {
let parentPath = parentItem.navigationPath; let parentPath = parentItem.navigationPath;
@ -358,6 +401,10 @@ export default {
} }
}, },
openAndScrollTo(navigationPath) { openAndScrollTo(navigationPath) {
if (navigationPath.includes('/ROOT')) {
navigationPath = navigationPath.split('/ROOT').join('');
}
let idArray = navigationPath.split('/'); let idArray = navigationPath.split('/');
let fullPathArray = []; let fullPathArray = [];
let pathsToOpen; let pathsToOpen;
@ -367,7 +414,6 @@ export default {
// skip root // skip root
idArray.splice(0, 2); idArray.splice(0, 2);
idArray[0] = 'browse/' + idArray[0]; idArray[0] = 'browse/' + idArray[0];
idArray.reduce((parentPath, childPath) => { idArray.reduce((parentPath, childPath) => {
let fullPath = [parentPath, childPath].join('/'); let fullPath = [parentPath, childPath].join('/');
@ -383,7 +429,11 @@ export default {
return this.openTreeItem(this.getTreeItemByPath(childPath)); return this.openTreeItem(this.getTreeItemByPath(childPath));
}, Promise.resolve()); }, Promise.resolve()).then(() => {
if (this.isSelectorTree) {
this.treeItemSelection(this.getTreeItemByPath(navigationPath));
}
});
}, },
scrollToCheck(navigationPath) { scrollToCheck(navigationPath) {
if (this.scrollToPath && this.scrollToPath === navigationPath) { if (this.scrollToPath && this.scrollToPath === navigationPath) {
@ -721,18 +771,26 @@ export default {
let checkHeights = () => { let checkHeights = () => {
let treeTopMargin = this.getElementStyleValue(this.$refs.mainTree, 'marginTop'); let treeTopMargin = this.getElementStyleValue(this.$refs.mainTree, 'marginTop');
let paddingOffset = 0;
if ( if (
this.$el this.$el
&& this.$refs.search && this.$refs.search
&& this.$refs.mainTree && this.$refs.mainTree
&& this.$refs.treeContainer
&& this.$refs.dummyItem && this.$refs.dummyItem
&& this.$el.offsetHeight !== 0 && this.$el.offsetHeight !== 0
&& treeTopMargin > 0 && treeTopMargin > 0
) { ) {
if (this.isSelectorTree) {
paddingOffset = this.getElementStyleValue(this.$refs.treeContainer, 'padding');
}
this.mainTreeTopMargin = treeTopMargin; this.mainTreeTopMargin = treeTopMargin;
this.mainTreeHeight = this.$el.offsetHeight this.mainTreeHeight = this.$el.offsetHeight
- this.$refs.search.offsetHeight - this.$refs.search.offsetHeight
- this.mainTreeTopMargin; - this.mainTreeTopMargin
- (paddingOffset * 2);
this.itemHeight = this.getElementStyleValue(this.$refs.dummyItem, 'height'); this.itemHeight = this.getElementStyleValue(this.$refs.dummyItem, 'height');
resolve(); resolve();
@ -783,10 +841,18 @@ export default {
return Number(styleString.slice(0, index)); return Number(styleString.slice(0, index));
}, },
getSavedOpenItems() { getSavedOpenItems() {
if (this.isSelectorTree) {
return;
}
let openItems = localStorage.getItem(LOCAL_STORAGE_KEY__TREE_EXPANDED); let openItems = localStorage.getItem(LOCAL_STORAGE_KEY__TREE_EXPANDED);
this.openTreeItems = openItems ? JSON.parse(openItems) : []; this.openTreeItems = openItems ? JSON.parse(openItems) : [];
}, },
setSavedOpenItems() { setSavedOpenItems() {
if (this.isSelectorTree) {
return;
}
localStorage.setItem(LOCAL_STORAGE_KEY__TREE_EXPANDED, JSON.stringify(this.openTreeItems)); localStorage.setItem(LOCAL_STORAGE_KEY__TREE_EXPANDED, JSON.stringify(this.openTreeItems));
}, },
handleTreeResize() { handleTreeResize() {

View File

@ -7,19 +7,19 @@
class="c-tree__item" class="c-tree__item"
:class="{ :class="{
'is-alias': isAlias, 'is-alias': isAlias,
'is-navigated-object': navigated, 'is-navigated-object': shouldHightlight,
'is-context-clicked': contextClickActive, 'is-context-clicked': contextClickActive,
'is-new': isNewItem 'is-new': isNewItem
}" }"
@click.capture="handleClick" @click.capture="itemClick"
@contextmenu.capture="handleContextMenu" @contextmenu.capture="handleContextMenu"
> >
<view-control <view-control
ref="navigate" ref="action"
class="c-tree__item__view-control" class="c-tree__item__view-control"
:value="isOpen || isLoading" :value="isOpen || isLoading"
:enabled="!activeSearch && hasComposition" :enabled="!activeSearch && hasComposition"
@input="navigationClick()" @input="itemAction()"
/> />
<object-label <object-label
ref="objectLabel" ref="objectLabel"
@ -52,6 +52,14 @@ export default {
type: Object, type: Object,
required: true required: true
}, },
isSelectorTree: {
type: Boolean,
required: true
},
selectedItem: {
type: Object,
required: true
},
activeSearch: { activeSearch: {
type: Boolean, type: Boolean,
default: false default: false
@ -109,6 +117,9 @@ export default {
return parentKeyString !== this.node.object.location; return parentKeyString !== this.node.object.location;
}, },
isSelectedItem() {
return this.selectedItem.objectPath === this.node.objectPath;
},
isNewItem() { isNewItem() {
return this.isNew; return this.isNew;
}, },
@ -118,6 +129,13 @@ export default {
isOpen() { isOpen() {
return this.openItems.includes(this.navigationPath); return this.openItems.includes(this.navigationPath);
}, },
shouldHightlight() {
if (this.isSelectorTree) {
return this.isSelectedItem;
} else {
return this.navigated;
}
},
treeItemStyles() { treeItemStyles() {
let itemTop = (this.itemOffset + this.itemIndex) * this.itemHeight + 'px'; let itemTop = (this.itemOffset + this.itemIndex) * this.itemHeight + 'px';
@ -144,20 +162,30 @@ export default {
this.$emit('tree-item-destoyed', this.navigationPath); this.$emit('tree-item-destoyed', this.navigationPath);
}, },
methods: { methods: {
navigationClick() { itemAction() {
this.$emit('navigation-click', this.isOpen || this.isLoading ? 'close' : 'open'); this.$emit('tree-item-action', this.isOpen || this.isLoading ? 'close' : 'open');
}, },
handleClick(event) { itemClick(event) {
// skip for navigation, let viewControl handle click // skip for navigation, let viewControl handle click
if (this.$refs.navigate.$el === event.target) { if (this.$refs.action.$el === event.target) {
return; return;
} }
event.stopPropagation(); event.stopPropagation();
if (!this.isSelectorTree) {
this.$refs.objectLabel.navigateOrPreview(event); this.$refs.objectLabel.navigateOrPreview(event);
} else {
this.$emit('tree-item-selection', this.node);
}
}, },
handleContextMenu(event) { handleContextMenu(event) {
event.stopPropagation(); event.stopPropagation();
if (this.isSelectorTree) {
return;
}
this.$refs.objectLabel.showContextMenu(event); this.$refs.objectLabel.showContextMenu(event);
}, },
isNavigated() { isNavigated() {

1
static-root.json Normal file
View File

@ -0,0 +1 @@
{"openmct":{"c1b7f449-459e-4f37-ac00-07b91936d079":{"identifier":{"key":"c1b7f449-459e-4f37-ac00-07b91936d079","namespace":""},"name":"A Folder","type":"folder","composition":[{"key":"3e1b49d7-4b95-47a6-9744-93d18c1f7d86","namespace":""},{"key":"da052eaf-1631-48e4-944f-c4688276181b","namespace":""}],"modified":1641506166404,"location":"mine","persisted":1641506166404},"3e1b49d7-4b95-47a6-9744-93d18c1f7d86":{"identifier":{"key":"3e1b49d7-4b95-47a6-9744-93d18c1f7d86","namespace":""},"name":"Test Clock","type":"clock","configuration":{"baseFormat":"YYYY/MM/DD hh:mm:ss","use24":"clock12","timezone":"UTC"},"modified":1641506137466,"location":"c1b7f449-459e-4f37-ac00-07b91936d079","persisted":1641506137466},"da052eaf-1631-48e4-944f-c4688276181b":{"identifier":{"key":"da052eaf-1631-48e4-944f-c4688276181b","namespace":""},"name":"B Hyperlink","type":"hyperlink","displayFormat":"link","linkTarget":"_self","url":"www.google.com","displayText":"Google","modified":1641506166402,"location":"c1b7f449-459e-4f37-ac00-07b91936d079","persisted":1641506166402}},"rootId":"c1b7f449-459e-4f37-ac00-07b91936d079"}

View File

@ -1,5 +1,6 @@
const { merge } = require('webpack-merge'); const { merge } = require('webpack-merge');
const common = require('./webpack.common'); const common = require('./webpack.common');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
@ -14,6 +15,14 @@ module.exports = merge(common, {
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
__OPENMCT_ROOT_RELATIVE__: '"dist/"' __OPENMCT_ROOT_RELATIVE__: '"dist/"'
}),
new CopyWebpackPlugin({
patterns: [
{
from: './static-root.json',
to: '.'
}
]
}) })
], ],
devtool: 'eval-source-map' devtool: 'eval-source-map'