Compare commits

...

4 Commits

11 changed files with 287 additions and 269 deletions

View File

@@ -24,41 +24,6 @@
ref="plotWrapper"
class="c-plot holder holder-plot has-control-bar"
>
<div
v-if="!options.compact"
class="c-control-bar"
>
<span class="c-button-set c-button-set--strip-h">
<button
class="c-button icon-download"
title="Export This View's Data as PNG"
@click="exportPNG()"
>
<span class="c-button__label">PNG</span>
</button>
<button
class="c-button"
title="Export This View's Data as JPG"
@click="exportJPG()"
>
<span class="c-button__label">JPG</span>
</button>
</span>
<button
class="c-button icon-crosshair"
:class="{ 'is-active': cursorGuide }"
title="Toggle cursor guides"
@click="toggleCursorGuide"
>
</button>
<button
class="c-button"
:class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }"
title="Toggle grid lines"
@click="toggleGridLines"
>
</button>
</div>
<div
ref="plotContainer"

View File

@@ -61,6 +61,8 @@ export default function PlotViewProvider(openmct) {
let component;
return {
isPlotView: true,
show: function (element) {
let isCompact = isCompactView(objectPath);
component = new Vue({
@@ -83,6 +85,9 @@ export default function PlotViewProvider(openmct) {
template: '<plot :options="options"></plot>'
});
},
run(key) {
component.$refs.plot[key]();
},
destroy: function () {
component.$destroy();
component = undefined;

View File

@@ -46,6 +46,8 @@ export default function OverlayPlotViewProvider(openmct) {
let component;
return {
isPlotView: true,
show: function (element) {
let isCompact = isCompactView(objectPath);
component = new Vue({
@@ -65,9 +67,12 @@ export default function OverlayPlotViewProvider(openmct) {
}
};
},
template: '<plot :options="options"></plot>'
template: '<plot ref="plot" :options="options"></plot>'
});
},
run(key) {
component.$refs.plot[key]();
},
destroy: function () {
component.$destroy();
component = undefined;

View File

@@ -67,6 +67,54 @@ export default function () {
openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow);
openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow);
// custom actions
const actionsCommon = {
group: 'view',
appliesTo: (objectPath, view) => {
return view?.isPlotView;
}
};
openmct.actions.register({
...actionsCommon,
name: 'Export as PNG',
key: 'export-as-png',
description: "Export This View's Data as PNG",
cssClass: 'c-icon-button icon-download',
showInStatusBar: false,
invoke: (objectPath, view) => view.run('exportPNG')
});
openmct.actions.register({
...actionsCommon,
name: 'Export as JPG',
key: 'export-as-jpg',
description: "Export This View's Data as JPG",
cssClass: 'c-icon-button icon-download',
showInStatusBar: false,
invoke: (objectPath, view) => view.run('exportJPG')
});
openmct.actions.register({
...actionsCommon,
name: 'Toggle cursor guides',
key: 'toggle-cursor-guide',
description: 'Toggle cursor guide lines',
cssClass: 'c-icon-button icon-crosshair',
showInStatusBar: true,
invoke: (objectPath, view) => view.run('toggleCursorGuide')
});
openmct.actions.register({
...actionsCommon,
name: 'Toggle grid lines',
key: 'toggle-grid-lines',
description: 'Toggle plot grid lines',
cssClass: 'c-icon-button icon-grid-on',
showInStatusBar: true,
invoke: (objectPath, view) => view.run('toggleGridLines')
});
};
}

View File

@@ -22,41 +22,6 @@
<template>
<div class="c-plot c-plot--stacked holder holder-plot has-control-bar">
<div
v-show="!hideExportButtons && !options.compact"
class="c-control-bar"
>
<span class="c-button-set c-button-set--strip-h">
<button
class="c-button icon-download"
title="Export This View's Data as PNG"
@click="exportPNG()"
>
<span class="c-button__label">PNG</span>
</button>
<button
class="c-button"
title="Export This View's Data as JPG"
@click="exportJPG()"
>
<span class="c-button__label">JPG</span>
</button>
</span>
<button
class="c-button icon-crosshair"
:class="{ 'is-active': cursorGuide }"
title="Toggle cursor guides"
@click="toggleCursorGuide"
>
</button>
<button
class="c-button"
:class="{ 'icon-grid-on': gridLines, 'icon-grid-off': !gridLines }"
title="Toggle grid lines"
@click="toggleGridLines"
>
</button>
</div>
<div class="l-view-section">
<stacked-plot-item
v-for="object in compositionObjects"

View File

@@ -46,6 +46,8 @@ export default function StackedPlotViewProvider(openmct) {
let component;
return {
isPlotView: true,
show: function (element) {
let isCompact = isCompactView(objectPath);
@@ -70,6 +72,9 @@ export default function StackedPlotViewProvider(openmct) {
template: '<stacked-plot :options="options"></stacked-plot>'
});
},
run(key) {
component.$refs.plot[key]();
},
destroy: function () {
component.$destroy();
component = undefined;

View File

@@ -20,46 +20,41 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div
class="c-conductor"
:class="[
isFixed ? 'is-fixed-mode' : independentTCEnabled ? 'is-realtime-mode' : 'is-fixed-mode'
]"
>
<div class="c-conductor__time-bounds">
<toggle-switch
id="independentTCToggle"
:checked="independentTCEnabled"
:title="`${independentTCEnabled ? 'Disable' : 'Enable'} independent Time Conductor`"
@change="toggleIndependentTC"
/>
<div class="c-conductor-holder--compact l-shell__main-independent-time-conductor">
<div
class="c-conductor"
:class="[
isFixed ? 'is-fixed-mode' : independentTCEnabled ? 'is-realtime-mode' : 'is-fixed-mode'
]"
>
<div class="c-conductor__time-bounds">
<ConductorModeIcon />
<ConductorModeIcon />
<div
v-if="timeOptions && independentTCEnabled"
class="c-conductor__controls"
>
<Mode
v-if="mode"
class="c-conductor__mode-select"
:key-string="domainObject.identifier.key"
:mode="timeOptions.mode"
:enabled="independentTCEnabled"
@modeChanged="saveMode"
/>
<div
v-if="timeOptions && independentTCEnabled"
class="c-conductor__controls"
>
<Mode
v-if="mode"
class="c-conductor__mode-select"
:key-string="domainObject.identifier.key"
:mode="timeOptions.mode"
:enabled="independentTCEnabled"
@modeChanged="saveMode"
/>
<conductor-inputs-fixed
v-if="isFixed"
:key-string="domainObject.identifier.key"
@updated="saveFixedOffsets"
/>
<conductor-inputs-fixed
v-if="isFixed"
:key-string="domainObject.identifier.key"
@updated="saveFixedOffsets"
/>
<conductor-inputs-realtime
v-else
:key-string="domainObject.identifier.key"
@updated="saveClockOffsets"
/>
<conductor-inputs-realtime
v-else
:key-string="domainObject.identifier.key"
@updated="saveClockOffsets"
/>
</div>
</div>
</div>
</div>
@@ -69,7 +64,6 @@
import ConductorInputsFixed from "../ConductorInputsFixed.vue";
import ConductorInputsRealtime from "../ConductorInputsRealtime.vue";
import ConductorModeIcon from "@/plugins/timeConductor/ConductorModeIcon.vue";
import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue';
import Mode from "./Mode.vue";
export default {
@@ -77,15 +71,15 @@ export default {
Mode,
ConductorModeIcon,
ConductorInputsRealtime,
ConductorInputsFixed,
ToggleSwitch
ConductorInputsFixed
},
inject: ['openmct'],
props: {
domainObject: {
type: Object,
required: true
}
},
independentTCEnabled: Boolean
},
data() {
return {
@@ -93,8 +87,7 @@ export default {
clockOffsets: this.openmct.time.clockOffsets(),
fixedOffsets: this.openmct.time.bounds()
},
mode: undefined,
independentTCEnabled: this.domainObject.configuration.useIndependentTime === true
mode: undefined
};
},
computed: {
@@ -114,7 +107,6 @@ export default {
//domain object has changed
this.destroyIndependentTime();
this.independentTCEnabled = domainObject.configuration.useIndependentTime === true;
this.timeOptions = domainObject.configuration.timeOptions || {
clockOffsets: this.openmct.time.clockOffsets(),
fixedOffsets: this.openmct.time.bounds()
@@ -124,6 +116,13 @@ export default {
}
},
deep: true
},
independentTCEnabled(independentTCEnabled) {
if (independentTCEnabled) {
this.registerIndependentTimeOffsets();
} else {
this.destroyIndependentTime();
}
}
},
mounted() {
@@ -152,16 +151,6 @@ export default {
this.registerIndependentTimeOffsets();
}
},
toggleIndependentTC() {
this.independentTCEnabled = !this.independentTCEnabled;
if (this.independentTCEnabled) {
this.registerIndependentTimeOffsets();
} else {
this.destroyIndependentTime();
}
this.$emit('stateChanged', this.independentTCEnabled);
},
setTimeContext() {
this.stopFollowingTimeContext();
this.timeContext = this.openmct.time.getContextForView([this.domainObject]);

View File

@@ -1,15 +1,14 @@
<template>
<div>
<div
v-if="supportsIndependentTime"
class="c-conductor-holder--compact l-shell__main-independent-time-conductor"
>
<div :style="'display: ' + (showTimeConductor ? 'contents' : 'none')">
<independent-time-conductor
v-if="supportsIndependentTime"
:domain-object="domainObject"
@stateChanged="updateIndependentTimeState"
:independentTCEnabled="showTimeConductor"
@updated="saveTimeOptions"
/>
</div>
<div
ref="objectViewWrapper"
class="c-object-view"
@@ -23,13 +22,8 @@ import _ from "lodash";
import StyleRuleManager from "@/plugins/condition/StyleRuleManager";
import {STYLE_CONSTANTS} from "@/plugins/condition/utils/constants";
import IndependentTimeConductor from '@/plugins/timeConductor/independent/IndependentTimeConductor.vue';
import {SupportedIndependentTimeConductorViews} from '../constants'
const SupportedViewTypes = [
'plot-stacked',
'plot-overlay',
'bar-graph.view',
'time-strip.view'
];
export default {
components: {
IndependentTimeConductor
@@ -37,6 +31,7 @@ export default {
inject: ["openmct"],
props: {
showEditView: Boolean,
showTimeConductor: Boolean,
defaultObject: {
type: Object,
default: undefined
@@ -75,10 +70,12 @@ export default {
font() {
return this.objectFontStyle ? this.objectFontStyle.font : this.layoutFont;
},
// similar to BrowseBar#supportsIndependentTime
// TODO move higher up, pass it down
supportsIndependentTime() {
const viewKey = this.getViewKey();
return this.domainObject && SupportedViewTypes.includes(viewKey);
return this.domainObject && SupportedIndependentTimeConductorViews.includes(viewKey);
},
objectTypeClass() {
return this.domainObject && ('is-object-type-' + this.domainObject.type);
@@ -434,10 +431,6 @@ export default {
elemToStyle.dataset.font = newFont;
}
},
//Should the domainObject be updated in the Independent Time conductor component itself?
updateIndependentTimeState(useIndependentTime) {
this.openmct.objects.mutate(this.domainObject, 'configuration.useIndependentTime', useIndependentTime);
},
saveTimeOptions(options) {
this.openmct.objects.mutate(this.domainObject, 'configuration.timeOptions', options);
}

6
src/ui/constants.js Normal file
View File

@@ -0,0 +1,6 @@
export const SupportedIndependentTimeConductorViews = [
'plot-stacked',
'plot-overlay',
'bar-graph.view',
'time-strip.view'
];

View File

@@ -1,121 +1,133 @@
<template>
<div class="l-browse-bar">
<div class="l-browse-bar__start">
<button
v-if="hasParent"
class="l-browse-bar__nav-to-parent-button c-icon-button c-icon-button--major icon-arrow-nav-to-parent"
title="Navigate up to parent"
@click="goToParent"
></button>
<div
class="l-browse-bar__object-name--w c-object-label"
:class="[statusClass]"
>
<div
class="c-object-label__type-icon"
:class="type.cssClass"
>
<span
class="is-status__indicator"
:title="`This item is ${status}`"
></span>
</div>
<span
class="l-browse-bar__object-name c-object-label__name"
:class="{ 'c-input-inline' : isPersistable}"
:contenteditable="isPersistable"
@blur="updateName"
@keydown.enter.prevent
@keyup.enter.prevent="updateNameOnEnterKeyPress"
>
{{ domainObject.name }}
</span>
</div>
</div>
<div class="l-browse-bar__end">
<ViewSwitcher
v-if="!isEditing"
:current-view="currentView"
:views="views"
/>
<!-- Action buttons -->
<NotebookMenuSwitcher
v-if="notebookEnabled"
:domain-object="domainObject"
:object-path="openmct.router.path"
class="c-notebook-snapshot-menubutton"
/>
<div class="l-browse-bar__actions">
<div>
<div class="l-browse-bar">
<div class="l-browse-bar__start">
<button
v-for="(item, index) in statusBarItems"
:key="index"
class="c-button"
:class="item.cssClass"
@click="item.onItemClicked"
>
</button>
<button
v-if="isViewEditable & !isEditing"
:title="lockedOrUnlockedTitle"
:class="{
'c-button icon-lock': domainObject.locked,
'c-icon-button icon-unlocked': !domainObject.locked
}"
@click="toggleLock(!domainObject.locked)"
v-if="hasParent"
class="l-browse-bar__nav-to-parent-button c-icon-button c-icon-button--major icon-arrow-nav-to-parent"
title="Navigate up to parent"
@click="goToParent"
></button>
<button
v-if="isViewEditable && !isEditing && !domainObject.locked"
class="l-browse-bar__actions__edit c-button c-button--major icon-pencil"
title="Edit"
@click="edit()"
></button>
<div
v-if="isEditing"
class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
class="l-browse-bar__object-name--w c-object-label"
:class="[statusClass]"
>
<button
class="c-button--menu c-button--major icon-save"
title="Save"
@click.stop="toggleSaveMenu"
></button>
<div
v-show="showSaveMenu"
class="c-menu"
class="c-object-label__type-icon"
:class="type.cssClass"
>
<ul>
<li
class="icon-save"
title="Save and Finish Editing"
@click="saveAndFinishEditing"
>
Save and Finish Editing
</li>
<li
class="icon-save"
title="Save and Continue Editing"
@click="saveAndContinueEditing"
>
Save and Continue Editing
</li>
</ul>
<span
class="is-status__indicator"
:title="`This item is ${status}`"
></span>
</div>
<span
class="l-browse-bar__object-name c-object-label__name"
:class="{ 'c-input-inline' : isPersistable}"
:contenteditable="isPersistable"
@blur="updateName"
@keydown.enter.prevent
@keyup.enter.prevent="updateNameOnEnterKeyPress"
>
{{ domainObject.name }}
</span>
</div>
</div>
<button
v-if="isEditing"
class="l-browse-bar__actions c-button icon-x"
title="Cancel Editing"
@click="promptUserandCancelEditing()"
></button>
<button
class="l-browse-bar__actions c-icon-button icon-3-dots"
title="More options"
@click.prevent.stop="showMenuItems($event)"
></button>
<div class="l-browse-bar__end">
<template v-if="supportsIndependentTime">
<ConductorModeIcon />
<toggle-switch
id="tcToggle"
:checked="showTimeConductor"
:title="`${showTimeConductor ? 'Disable' : 'Enable'} independent Time Conductor`"
@change="$emit('toggleTimeConductor', !showTimeConductor)"
/>
</template>
<ViewSwitcher
v-if="!isEditing"
:current-view="currentView"
:views="views"
/>
<!-- Action buttons -->
<NotebookMenuSwitcher
v-if="notebookEnabled"
:domain-object="domainObject"
:object-path="openmct.router.path"
class="c-notebook-snapshot-menubutton"
/>
<div class="l-browse-bar__actions">
<button
v-for="(item, index) in statusBarItems"
:key="index"
class="c-button"
:class="item.cssClass"
@click="item.onItemClicked"
>
</button>
<button
v-if="isViewEditable & !isEditing"
:title="lockedOrUnlockedTitle"
:class="{
'c-button icon-lock': domainObject.locked,
'c-icon-button icon-unlocked': !domainObject.locked
}"
@click="toggleLock(!domainObject.locked)"
></button>
<button
v-if="isViewEditable && !isEditing && !domainObject.locked"
class="l-browse-bar__actions__edit c-button c-button--major icon-pencil"
title="Edit"
@click="edit()"
></button>
<div
v-if="isEditing"
class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
>
<button
class="c-button--menu c-button--major icon-save"
title="Save"
@click.stop="toggleSaveMenu"
></button>
<div
v-show="showSaveMenu"
class="c-menu"
>
<ul>
<li
class="icon-save"
title="Save and Finish Editing"
@click="saveAndFinishEditing"
>
Save and Finish Editing
</li>
<li
class="icon-save"
title="Save and Continue Editing"
@click="saveAndContinueEditing"
>
Save and Continue Editing
</li>
</ul>
</div>
</div>
<button
v-if="isEditing"
class="l-browse-bar__actions c-button icon-x"
title="Cancel Editing"
@click="promptUserandCancelEditing()"
></button>
<button
class="l-browse-bar__actions c-icon-button icon-3-dots"
title="More options"
@click.prevent.stop="showMenuItems($event)"
></button>
</div>
</div>
</div>
</div>
@@ -124,13 +136,18 @@
<script>
import ViewSwitcher from './ViewSwitcher.vue';
import NotebookMenuSwitcher from '@/plugins/notebook/components/NotebookMenuSwitcher.vue';
import ToggleSwitch from '../components/ToggleSwitch.vue';
import ConductorModeIcon from "@/plugins/timeConductor/ConductorModeIcon.vue";
import {SupportedIndependentTimeConductorViews} from '../constants';
const PLACEHOLDER_OBJECT = {};
export default {
components: {
NotebookMenuSwitcher,
ViewSwitcher
ViewSwitcher,
ToggleSwitch,
ConductorModeIcon
},
inject: ['openmct'],
props: {
@@ -139,7 +156,8 @@ export default {
default: () => {
return {};
}
}
},
showTimeConductor: Boolean
},
data: function () {
return {
@@ -218,6 +236,12 @@ export default {
} else {
return 'Unlocked for editing - click to lock.';
}
},
// similar to ObjectView#supportsIndependentTime
supportsIndependentTime() {
const viewKey = this.viewKey;
return this.domainObject && SupportedIndependentTimeConductorViews.includes(viewKey);
}
},
watch: {

View File

@@ -5,10 +5,7 @@
'is-editing': isEditing
}"
>
<div
id="splash-screen"
></div>
<div id="splash-screen"></div>
<div
class="l-shell__head"
@@ -62,15 +59,13 @@
class="c-icon-button l-shell__reset-tree-button icon-folders-collapse"
title="Collapse all tree items"
@click="handleTreeReset"
>
</button>
></button>
<button
slot="controls"
class="c-icon-button l-shell__sync-tree-button icon-target"
title="Show selected item in tree"
@click="handleSyncTreeNavigation"
>
</button>
></button>
<mct-tree
:sync-tree-navigation="triggerSync"
:reset-tree-navigation="triggerReset"
@@ -82,7 +77,9 @@
ref="browseBar"
class="l-shell__main-view-browse-bar"
:action-collection="actionCollection"
:show-time-conductor="useIndependentTime"
@sync-tree-navigation="handleSyncTreeNavigation"
@toggleTimeConductor="toggleIndependentTime"
/>
<toolbar
v-if="toolbar"
@@ -93,6 +90,7 @@
class="l-shell__main-container js-main-container js-notebook-snapshot-item"
data-selectable
:show-edit-view="true"
:show-time-conductor="useIndependentTime"
@change-action-collection="setActionCollection"
/>
<component
@@ -157,6 +155,7 @@ export default {
conductorComponent: undefined,
isEditing: false,
hasToolbar: false,
useIndependentTime: false,
actionCollection: undefined,
triggerSync: false,
triggerReset: false,
@@ -173,23 +172,39 @@ export default {
}
},
mounted() {
this.openmct.editor.on('isEditing', (isEditing) => {
// HACK: timeout needed because `this.$refs.browseObject.domainObject`
// is undefined until ObjectView sets it after a 10ms timeout.
// TODO: get rid of hacks. :D
setTimeout(() => {
this.useIndependentTime = this.$refs.browseObject.domainObject.configuration.useIndependentTime;
}, 15);
this.openmct.editor.on('isEditing', isEditing => {
this.isEditing = isEditing;
});
this.openmct.selection.on('change', this.toggleHasToolbar);
},
methods: {
//Should the domainObject be updated in the Independent Time conductor component itself?
toggleIndependentTime() {
this.useIndependentTime = !this.useIndependentTime;
// What's the best way to get domainObject here in Layout?
const domainObject = this.$refs.browseObject.domainObject;
this.openmct.objects.mutate(domainObject, 'configuration.useIndependentTime', this.useIndependentTime);
},
enterFullScreen() {
let docElm = document.documentElement;
if (docElm.requestFullscreen) {
docElm.requestFullscreen();
} else if (docElm.mozRequestFullScreen) { /* Firefox */
} else if (docElm.mozRequestFullScreen) { // Firefox
docElm.mozRequestFullScreen();
} else if (docElm.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
} else if (docElm.webkitRequestFullscreen) { // Chrome, Safari and Opera
docElm.webkitRequestFullscreen();
} else if (docElm.msRequestFullscreen) { /* IE/Edge */
} else if (docElm.msRequestFullscreen) { // IE/Edge
docElm.msRequestFullscreen();
}
},
@@ -209,11 +224,9 @@ export default {
window.localStorage.setItem(
'openmct-shell-head',
JSON.stringify(
{
expanded: this.headExpanded
}
)
JSON.stringify({
expanded: this.headExpanded
})
);
},
fullScreenToggle() {