Compare commits

...

26 Commits

Author SHA1 Message Date
David Tsay
ec010c00f3 code cleanup 2021-08-19 10:15:32 -07:00
David Tsay
e0d5293bea make tick width reactive 2021-08-19 10:15:20 -07:00
David Tsay
8e3cd7d08b silence component error 2021-08-17 12:47:28 -07:00
David Tsay
e0a3a8ca68 tree and inspector tests in one 2021-08-17 12:47:18 -07:00
David Tsay
e934ca6eb0 tests for tree pane 2021-08-17 12:47:04 -07:00
David Tsay
14dbb85f17 WIP unit tests for layout 2021-08-17 12:46:53 -07:00
David Tsay
6eb266c210 do not constantly listen to param changes 2021-08-17 12:46:43 -07:00
Joshi
314d636733 Prevent extra loading of plots data 2021-08-17 09:50:29 -07:00
Joshi
fd4dcc8513 Add check for destroy method on store.
Change failing test to use new data getter.
2021-08-10 09:55:22 -07:00
Joshi
9ebd18318b Remve console log 2021-08-10 09:55:22 -07:00
Joshi
4a89b81f4f Logging for beforeunload events 2021-08-10 09:55:22 -07:00
Joshi
98e1abd7b1 Don't draw points if the count is 0 2021-08-10 09:55:22 -07:00
Joshi
56c25762ac Fix resize handler for plots 2021-08-10 09:55:22 -07:00
Joshi
5c8e726b87 Fix data store id 2021-08-10 09:55:22 -07:00
Joshi
d80f4a1f7d Revert commented out code 2021-08-10 09:55:22 -07:00
Joshi
3fe4c7a954 Revert eslint changes 2021-08-10 09:55:22 -07:00
Joshi
676ef60128 Revert eslint changes 2021-08-10 09:55:22 -07:00
Joshi
5a90d28450 Separate plot series data from the configuration (like it should be!) 2021-08-10 09:55:22 -07:00
Joshi
2bb6822e6b Draft 2021-08-10 09:55:22 -07:00
Joshi
383b4c0d8d Fix no mutating props violation for Browsebar and StyleEditor 2021-08-10 09:55:22 -07:00
Joshi
404ab720ad Enable no mutating props vue lint configuration. Fix error for plots 2021-08-10 09:55:22 -07:00
Khalid Adil
259ab53060 Refactor clock object and clock indicator to remove AngularJS dependency (#4094)
* To enable clock indicator, pass in the following configuration { enableClockIndicator: true }.
2021-08-09 14:29:45 -07:00
Nikhil
1db7ac55b4 [Imagery] Click on image to get a large view #3582 (#4085)
fixed issue where large imagery view opens only once.
2021-08-04 15:44:50 -07:00
Shefali Joshi
82b3383834 Set the yKey value on the series when it's changed (#4083) 2021-08-04 13:56:37 -07:00
Shefali Joshi
ac240d524c Add check for stop observing before calling it (#4080) 2021-08-04 10:40:16 -07:00
Henry Hsu
1b034f6125 remove can edit from hyperlink (#4076) 2021-08-03 16:01:29 -07:00
32 changed files with 677 additions and 672 deletions

View File

@@ -195,6 +195,7 @@
['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked'],
{indicator: true}
));
openmct.install(openmct.plugins.Clock({ enableClockIndicator: true }));
openmct.start();
</script>
</html>

View File

@@ -21,32 +21,24 @@
*****************************************************************************/
define([
"moment-timezone",
"./src/indicators/ClockIndicator",
"./src/services/TickerService",
"./src/services/TimerService",
"./src/controllers/ClockController",
"./src/controllers/TimerController",
"./src/controllers/RefreshingController",
"./src/actions/StartTimerAction",
"./src/actions/RestartTimerAction",
"./src/actions/StopTimerAction",
"./src/actions/PauseTimerAction",
"./res/templates/clock.html",
"./res/templates/timer.html"
], function (
MomentTimezone,
ClockIndicator,
TickerService,
TimerService,
ClockController,
TimerController,
RefreshingController,
StartTimerAction,
RestartTimerAction,
StopTimerAction,
PauseTimerAction,
clockTemplate,
timerTemplate
) {
return {
@@ -73,16 +65,6 @@ define([
"value": "YYYY/MM/DD HH:mm:ss"
}
],
"indicators": [
{
"implementation": ClockIndicator,
"depends": [
"tickerService",
"CLOCK_INDICATOR_FORMAT"
],
"priority": "preferred"
}
],
"services": [
{
"key": "tickerService",
@@ -99,14 +81,6 @@ define([
}
],
"controllers": [
{
"key": "ClockController",
"implementation": ClockController,
"depends": [
"$scope",
"tickerService"
]
},
{
"key": "TimerController",
"implementation": TimerController,
@@ -126,12 +100,6 @@ define([
}
],
"views": [
{
"key": "clock",
"type": "clock",
"editable": false,
"template": clockTemplate
},
{
"key": "timer",
"type": "timer",
@@ -186,70 +154,6 @@ define([
}
],
"types": [
{
"key": "clock",
"name": "Clock",
"cssClass": "icon-clock",
"description": "A UTC-based clock that supports a variety of display formats. Clocks can be added to Display Layouts.",
"priority": 101,
"features": [
"creation"
],
"properties": [
{
"key": "clockFormat",
"name": "Display Format",
"control": "composite",
"items": [
{
"control": "select",
"options": [
{
"value": "YYYY/MM/DD hh:mm:ss",
"name": "YYYY/MM/DD hh:mm:ss"
},
{
"value": "YYYY/DDD hh:mm:ss",
"name": "YYYY/DDD hh:mm:ss"
},
{
"value": "hh:mm:ss",
"name": "hh:mm:ss"
}
],
"cssClass": "l-inline"
},
{
"control": "select",
"options": [
{
"value": "clock12",
"name": "12hr"
},
{
"value": "clock24",
"name": "24hr"
}
],
"cssClass": "l-inline"
}
]
},
{
"key": "timezone",
"name": "Timezone",
"control": "autocomplete",
"options": MomentTimezone.tz.names()
}
],
"model": {
"clockFormat": [
"YYYY/MM/DD hh:mm:ss",
"clock12"
],
"timezone": "UTC"
}
},
{
"key": "timer",
"name": "Timer",

View File

@@ -1,32 +0,0 @@
<!--
Open MCT, Copyright (c) 2009-2016, 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.
-->
<div class="c-clock l-time-display u-style-receiver js-style-receiver" ng-controller="ClockController as clock">
<div class="c-clock__timezone">
{{clock.zone()}}
</div>
<div class="c-clock__value">
{{clock.text()}}
</div>
<div class="c-clock__ampm">
{{clock.ampm()}}
</div>
</div>

View File

@@ -1,110 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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.
*****************************************************************************/
define([
'moment',
'moment-timezone'
],
function (
moment,
momentTimezone
) {
/**
* Controller for views of a Clock domain object.
*
* @constructor
* @memberof platform/features/clock
* @param {angular.Scope} $scope the Angular scope
* @param {platform/features/clock.TickerService} tickerService
* a service used to align behavior with clock ticks
*/
function ClockController($scope, tickerService) {
var lastTimestamp,
unlisten,
timeFormat,
zoneName,
self = this;
function update() {
var m = zoneName
? moment.utc(lastTimestamp).tz(zoneName) : moment.utc(lastTimestamp);
self.zoneAbbr = m.zoneAbbr();
self.textValue = timeFormat && m.format(timeFormat);
self.ampmValue = m.format("A"); // Just the AM or PM part
}
function tick(timestamp) {
lastTimestamp = timestamp;
update();
}
function updateModel(model) {
var baseFormat;
if (model !== undefined) {
baseFormat = model.clockFormat[0];
self.use24 = model.clockFormat[1] === 'clock24';
timeFormat = self.use24
? baseFormat.replace('hh', "HH") : baseFormat;
// If wrong timezone is provided, the UTC will be used
zoneName = momentTimezone.tz.names().includes(model.timezone)
? model.timezone : "UTC";
update();
}
}
// Pull in the model (clockFormat and timezone) from the domain object model
$scope.$watch('model', updateModel);
// Listen for clock ticks ... and stop listening on destroy
unlisten = tickerService.listen(tick);
$scope.$on('$destroy', unlisten);
}
/**
* Get the clock's time zone, as displayable text.
* @returns {string}
*/
ClockController.prototype.zone = function () {
return this.zoneAbbr;
};
/**
* Get the current time, as displayable text.
* @returns {string}
*/
ClockController.prototype.text = function () {
return this.textValue;
};
/**
* Get the text to display to qualify a time as AM or PM.
* @returns {string}
*/
ClockController.prototype.ampm = function () {
return this.use24 ? '' : this.ampmValue;
};
return ClockController;
}
);

View File

@@ -1,65 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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.
*****************************************************************************/
define(
['moment'],
function (moment) {
/**
* Indicator that displays the current UTC time in the status area.
* @implements {Indicator}
* @memberof platform/features/clock
* @param {platform/features/clock.TickerService} tickerService
* a service used to align behavior with clock ticks
* @param {string} indicatorFormat format string for timestamps
* shown in this indicator
*/
function ClockIndicator(tickerService, indicatorFormat) {
var self = this;
this.text = "";
tickerService.listen(function (timestamp) {
self.text = moment.utc(timestamp)
.format(indicatorFormat) + " UTC";
});
}
ClockIndicator.prototype.getGlyphClass = function () {
return "";
};
ClockIndicator.prototype.getCssClass = function () {
return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable";
};
ClockIndicator.prototype.getText = function () {
return this.text;
};
ClockIndicator.prototype.getDescription = function () {
return "";
};
return ClockIndicator;
}
);

View File

@@ -1,107 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2017, 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.
*****************************************************************************/
define(
["../../src/controllers/ClockController"],
function (ClockController) {
// Wed, 03 Jun 2015 17:56:14 GMT
var TEST_TIMESTAMP = 1433354174000;
describe("A clock view's controller", function () {
var mockScope,
mockTicker,
mockUnticker,
controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj('$scope', ['$watch', '$on']);
mockTicker = jasmine.createSpyObj('ticker', ['listen']);
mockUnticker = jasmine.createSpy('unticker');
mockTicker.listen.and.returnValue(mockUnticker);
controller = new ClockController(mockScope, mockTicker);
});
it("watches for model (clockFormat and timezone) from the domain object model", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
"model",
jasmine.any(Function)
);
});
it("subscribes to clock ticks", function () {
expect(mockTicker.listen)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("unsubscribes to ticks when destroyed", function () {
// Make sure $destroy is being listened for...
expect(mockScope.$on.calls.mostRecent().args[0]).toEqual('$destroy');
expect(mockUnticker).not.toHaveBeenCalled();
// ...and makes sure that its listener unsubscribes from ticker
mockScope.$on.calls.mostRecent().args[1]();
expect(mockUnticker).toHaveBeenCalled();
});
it("formats using the format string from the model", function () {
mockTicker.listen.calls.mostRecent().args[0](TEST_TIMESTAMP);
mockScope.$watch.calls.mostRecent().args[1]({
"clockFormat": [
"YYYY-DDD hh:mm:ss",
"clock24"
],
"timezone": "Canada/Eastern"
});
expect(controller.zone()).toEqual("EDT");
expect(controller.text()).toEqual("2015-154 13:56:14");
expect(controller.ampm()).toEqual("");
});
it("formats 12-hour time", function () {
mockTicker.listen.calls.mostRecent().args[0](TEST_TIMESTAMP);
mockScope.$watch.calls.mostRecent().args[1]({
"clockFormat": [
"YYYY-DDD hh:mm:ss",
"clock12"
],
"timezone": ""
});
expect(controller.zone()).toEqual("UTC");
expect(controller.text()).toEqual("2015-154 05:56:14");
expect(controller.ampm()).toEqual("PM");
});
it("does not throw exceptions when model is undefined", function () {
mockTicker.listen.calls.mostRecent().args[0](TEST_TIMESTAMP);
expect(function () {
mockScope.$watch.calls.mostRecent().args[1](undefined);
}).not.toThrow();
});
});
}
);

View File

@@ -1,58 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2009-2016, 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.
*****************************************************************************/
define(
["../../src/indicators/ClockIndicator"],
function (ClockIndicator) {
// Wed, 03 Jun 2015 17:56:14 GMT
var TEST_TIMESTAMP = 1433354174000,
TEST_FORMAT = "YYYY-DDD HH:mm:ss";
describe("The clock indicator", function () {
var mockTicker,
mockUnticker,
indicator;
beforeEach(function () {
mockTicker = jasmine.createSpyObj('ticker', ['listen']);
mockUnticker = jasmine.createSpy('unticker');
mockTicker.listen.and.returnValue(mockUnticker);
indicator = new ClockIndicator(mockTicker, TEST_FORMAT);
});
it("displays the current time", function () {
mockTicker.listen.calls.mostRecent().args[0](TEST_TIMESTAMP);
expect(indicator.getText()).toEqual("2015-154 17:56:14 UTC");
});
it("implements the Indicator interface", function () {
expect(indicator.getCssClass()).toEqual(jasmine.any(String));
expect(indicator.getText()).toEqual(jasmine.any(String));
expect(indicator.getDescription()).toEqual(jasmine.any(String));
});
});
}
);

View File

@@ -0,0 +1,59 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
import Clock from './components/Clock.vue';
import Vue from 'vue';
export default function ClockViewProvider(openmct) {
return {
key: 'clock.view',
name: 'Clock',
cssClass: 'icon-clock',
canView(domainObject) {
return domainObject.type === 'clock';
},
view: function (domainObject) {
let component;
return {
show: function (element) {
component = new Vue({
el: element,
components: {
Clock
},
provide: {
openmct,
domainObject
},
template: '<clock></clock>'
});
},
destroy: function () {
component.$destroy();
component = undefined;
}
};
}
};
}

View File

@@ -0,0 +1,99 @@
<!--
Open MCT, Copyright (c) 2014-2021, 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="l-angular-ov-wrapper">
<div class="u-contents">
<div class="c-clock l-time-display u-style-receiver js-style-receiver">
<div class="c-clock__timezone">
{{ timeZoneAbbr }}
</div>
<div class="c-clock__value">
{{ timeTextValue }}
</div>
<div class="c-clock__ampm">
{{ timeAmPm }}
</div>
</div>
</div>
</div>
</template>
<script>
import moment from 'moment';
import momentTimezone from 'moment-timezone';
export default {
inject: ['openmct', 'domainObject'],
data() {
return {
lastTimestamp: null
};
},
computed: {
configuration() {
return this.domainObject.configuration;
},
baseFormat() {
return this.configuration.baseFormat;
},
use24() {
return this.configuration.use24 === 'clock24';
},
timezone() {
return this.configuration.timezone;
},
timeFormat() {
return this.use24 ? this.baseFormat.replace('hh', "HH") : this.baseFormat;
},
zoneName() {
return momentTimezone.tz.names().includes(this.timezone) ? this.timezone : "UTC";
},
momentTime() {
return this.zoneName ? moment.utc(this.lastTimestamp).tz(this.zoneName) : moment.utc(this.lastTimestamp);
},
timeZoneAbbr() {
return this.momentTime.zoneAbbr();
},
timeTextValue() {
return this.timeFormat && this.momentTime.format(this.timeFormat);
},
timeAmPm() {
return this.use24 ? '' : this.momentTime.format("A");
}
},
mounted() {
const TickerService = this.openmct.$injector.get('tickerService');
this.unlisten = TickerService.listen(this.tick);
},
beforeDestroy() {
if (this.unlisten) {
this.unlisten();
}
},
methods: {
tick(timestamp) {
this.lastTimestamp = timestamp;
}
}
};
</script>

View File

@@ -0,0 +1,64 @@
<!--
Open MCT, Copyright (c) 2014-2021, 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="c-indicator t-indicator-clock icon-clock no-minify c-indicator--not-clickable">
<span class="label c-indicator__label">
{{ timeTextValue }}
</span>
</div>
</template>
<script>
import moment from 'moment';
export default {
inject: ['openmct'],
props: {
indicatorFormat: {
type: String,
required: true
}
},
data() {
return {
timeTextValue: null
};
},
mounted() {
this.openmct.on('start', () => {
const TickerService = this.openmct.$injector.get('tickerService');
this.unlisten = TickerService.listen(this.tick);
});
},
beforeDestroy() {
if (this.unlisten) {
this.unlisten();
}
},
methods: {
tick(timestamp) {
this.timeTextValue = `${moment.utc(timestamp).format(this.indicatorFormat)} UTC`;
}
}
};
</script>

154
src/plugins/clock/plugin.js Normal file
View File

@@ -0,0 +1,154 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
import ClockViewProvider from './ClockViewProvider';
import ClockIndicator from './components/ClockIndicator.vue';
import momentTimezone from 'moment-timezone';
import Vue from 'vue';
export default function ClockPlugin(options) {
return function install(openmct) {
const CLOCK_INDICATOR_FORMAT = 'YYYY/MM/DD HH:mm:ss';
openmct.types.addType('clock', {
name: 'Clock',
description: 'A UTC-based clock that supports a variety of display formats. Clocks can be added to Display Layouts.',
creatable: true,
cssClass: 'icon-clock',
initialize: function (domainObject) {
domainObject.configuration = {
baseFormat: 'YYYY/MM/DD hh:mm:ss',
use24: 'clock12',
timezone: 'UTC'
};
},
"form": [
{
"key": "displayFormat",
"name": "Display Format",
control: 'select',
options: [
{
value: 'YYYY/MM/DD hh:mm:ss',
name: 'YYYY/MM/DD hh:mm:ss'
},
{
value: 'YYYY/DDD hh:mm:ss',
name: 'YYYY/DDD hh:mm:ss'
},
{
value: 'hh:mm:ss',
name: 'hh:mm:ss'
}
],
cssClass: 'l-inline',
property: [
'configuration',
'baseFormat'
]
},
{
control: 'select',
options: [
{
value: 'clock12',
name: '12hr'
},
{
value: 'clock24',
name: '24hr'
}
],
cssClass: 'l-inline',
property: [
'configuration',
'use24'
]
},
{
"key": "timezone",
"name": "Timezone",
"control": "autocomplete",
"options": momentTimezone.tz.names(),
property: [
'configuration',
'timezone'
]
}
]
});
openmct.objectViews.addProvider(new ClockViewProvider(openmct));
if (options && options.enableClockIndicator) {
const clockIndicator = new Vue ({
components: {
ClockIndicator
},
provide: {
openmct
},
data() {
return {
indicatorFormat: CLOCK_INDICATOR_FORMAT
};
},
template: '<ClockIndicator :indicator-format="indicatorFormat"></ClockIndicator>'
});
const indicator = {
element: clockIndicator.$mount().$el,
key: 'clock-indicator'
};
openmct.indicators.add(indicator);
}
openmct.objects.addGetInterceptor({
appliesTo: (identifier, domainObject) => {
return domainObject && domainObject.type === 'clock';
},
invoke: (identifier, domainObject) => {
if (domainObject.configuration) {
return domainObject;
}
if (domainObject.clockFormat
&& domainObject.timezone) {
const baseFormat = domainObject.clockFormat[0];
const use24 = domainObject.clockFormat[1];
const timezone = domainObject.timezone;
domainObject.configuration = {
baseFormat,
use24,
timezone
};
openmct.objects.mutate(domainObject, 'configuration', domainObject.configuration);
}
return domainObject;
}
});
};
}

View File

@@ -33,10 +33,6 @@ export default function HyperlinkProvider(openmct) {
return domainObject.type === 'hyperlink';
},
canEdit(domainObject) {
return domainObject.type === 'hyperlink';
},
view: function (domainObject) {
let component;

View File

@@ -378,7 +378,7 @@ export default class CouchObjectProvider {
this.observers[keyString] = this.observers[keyString].filter(observer => observer !== callback);
if (this.observers[keyString].length === 0) {
delete this.observers[keyString];
if (Object.keys(this.observers).length === 0) {
if (Object.keys(this.observers).length === 0 && this.isObservingObjectChanges()) {
this.stopObservingObjectChanges();
}
}
@@ -436,7 +436,7 @@ export default class CouchObjectProvider {
if (!this.changesFeedSharedWorker) {
this.changesFeedSharedWorker = this.startSharedWorker();
if (typeof this.stopObservingObjectChanges === 'function') {
if (this.isObservingObjectChanges()) {
this.stopObservingObjectChanges();
}
@@ -458,7 +458,7 @@ export default class CouchObjectProvider {
let error = false;
if (typeof this.stopObservingObjectChanges === 'function') {
if (this.isObservingObjectChanges()) {
this.stopObservingObjectChanges();
}

View File

@@ -25,16 +25,16 @@
:class="[plotLegendExpandedStateClass, plotLegendPositionClass]"
>
<plot-legend :cursor-locked="!!lockHighlightPoint"
:series="config.series.models"
:series="seriesModels"
:highlights="highlights"
:legend="config.legend"
:legend="legend"
@legendHoverChanged="legendHoverChanged"
/>
<div class="plot-wrapper-axis-and-display-area flex-elem grows">
<y-axis v-if="config.series.models.length > 0"
<y-axis v-if="seriesModels.length > 0"
:tick-width="tickWidth"
:single-series="config.series.models.length === 1"
:series-model="config.series.models[0]"
:single-series="seriesModels.length === 1"
:series-model="seriesModels[0]"
@yKeyChanged="setYAxisKey"
@tickWidthChanged="onTickWidthChange"
/>
@@ -141,8 +141,8 @@
>
</div>
</div>
<x-axis v-if="config.series.models.length > 0 && !options.compact"
:series-model="config.series.models[0]"
<x-axis v-if="seriesModels.length > 0 && !options.compact"
:series-model="seriesModels[0]"
/>
</div>
@@ -213,7 +213,8 @@ export default {
plotHistory: [],
selectedXKeyOption: {},
xKeyOptions: [],
config: {},
seriesModels: [],
legend: {},
pending: 0,
isRealTime: this.openmct.time.clock() !== undefined,
loaded: false,
@@ -239,18 +240,13 @@ export default {
watch: {
plotTickWidth(newTickWidth) {
this.onTickWidthChange(newTickWidth, true);
},
gridLines(newGridLines) {
this.setGridLinesVisibility(newGridLines);
},
cursorGuide(newCursorGuide) {
this.setCursorGuideVisibility(newCursorGuide);
}
},
mounted() {
eventHelpers.extend(this);
this.config = this.getConfig();
this.legend = this.config.legend;
this.listenTo(this.config.series, 'add', this.addSeries, this);
this.listenTo(this.config.series, 'remove', this.removeSeries, this);
@@ -290,14 +286,18 @@ export default {
config = new PlotConfigurationModel({
id: configId,
domainObject: this.domainObject,
openmct: this.openmct
openmct: this.openmct,
callback: (data) => {
this.data = data;
}
});
configStore.add(configId, config);
}
return config;
},
addSeries(series) {
addSeries(series, index) {
this.$set(this.seriesModels, index, series);
this.listenTo(series, 'change:xKey', (xKey) => {
this.setDisplayRange(series, xKey);
}, this);
@@ -323,6 +323,8 @@ export default {
return;
}
this.offsetWidth = this.$parent.$refs.plotWrapper.offsetWidth;
this.startLoading();
const options = {
size: this.$parent.$refs.plotWrapper.offsetWidth,
@@ -377,11 +379,8 @@ export default {
},
stopLoading() {
//TODO: Is Vue.$nextTick ok to replace $scope.$evalAsync?
this.$nextTick().then(() => {
this.pending -= 1;
this.updateLoading();
});
this.pending -= 1;
this.updateLoading();
},
updateLoading() {
@@ -507,7 +506,7 @@ export default {
},
initialize() {
_.debounce(this.handleWindowResize, 400);
this.handleWindowResize = _.debounce(this.handleWindowResize, 500);
this.plotContainerResizeObserver = new ResizeObserver(this.handleWindowResize);
this.plotContainerResizeObserver.observe(this.$parent.$refs.plotWrapper);
@@ -556,7 +555,9 @@ export default {
}
}
this.$emit('plotTickWidth', this.tickWidth);
const id = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.$emit('plotTickWidth', this.tickWidth, id);
},
trackMousePosition(event) {
@@ -623,7 +624,7 @@ export default {
this.config.series.models.forEach(series => delete series.closest);
} else {
this.highlights = this.config.series.models
.filter(series => series.data.length > 0)
.filter(series => series.getSeriesData().length > 0)
.map(series => {
series.closest = series.nearestPoint(point);
@@ -927,16 +928,8 @@ export default {
this.userViewportChangeEnd();
},
setCursorGuideVisibility(cursorGuide) {
this.cursorGuide = cursorGuide === true;
},
setGridLinesVisibility(gridLines) {
this.gridLines = gridLines === true;
},
setYAxisKey(yKey) {
this.config.series.models[0].emit('change:yKey', yKey);
this.config.series.models[0].set('yKey', yKey);
},
pause() {

View File

@@ -106,8 +106,9 @@ export default {
},
toggleXKeyOption() {
const selectedXKey = this.selectedXKeyOptionKey;
const dataForSelectedXKey = this.seriesModel.data
? this.seriesModel.data[0][selectedXKey]
const seriesData = this.seriesModel.getSeriesData();
const dataForSelectedXKey = seriesData
? seriesData[0][selectedXKey]
: undefined;
if (dataForSelectedXKey !== undefined) {

View File

@@ -36,7 +36,7 @@ export default class MCTChartAlarmPointSet {
this.listenTo(series, 'reset', this.reset, this);
this.listenTo(series, 'destroy', this.destroy, this);
series.data.forEach(function (point, index) {
this.series.getSeriesData().forEach(function (point, index) {
this.append(point, index, series);
}, this);
}

View File

@@ -36,7 +36,7 @@ export default class MCTChartSeriesElement {
this.listenTo(series, 'remove', this.remove, this);
this.listenTo(series, 'reset', this.reset, this);
this.listenTo(series, 'destroy', this.destroy, this);
series.data.forEach(function (point, index) {
this.series.getSeriesData().forEach(function (point, index) {
this.append(point, index, series);
}, this);
}
@@ -133,7 +133,7 @@ export default class MCTChartSeriesElement {
this.buffer = new Float32Array(20000);
this.count = 0;
if (this.offset.x) {
this.series.data.forEach(function (point, index) {
this.series.getSeriesData().forEach(function (point, index) {
this.append(point, index, this.series);
}, this);
}

View File

@@ -107,6 +107,7 @@ export default class PlotConfigurationModel extends Model {
updateDomainObject(domainObject) {
this.set('domainObject', domainObject);
}
/**
* Clean up all objects and remove all listeners.
*/

View File

@@ -22,6 +22,7 @@
import _ from 'lodash';
import Model from "./Model";
import { MARKER_SHAPES } from '../draw/MarkerShapes';
import configStore from "../configuration/configStore";
/**
* Plot series handle interpreting telemetry metadata for a single telemetry
@@ -62,7 +63,6 @@ import { MARKER_SHAPES } from '../draw/MarkerShapes';
export default class PlotSeries extends Model {
constructor(options) {
super(options);
this.data = [];
this.listenTo(this, 'change:xKey', this.onXKeyChange, this);
this.listenTo(this, 'change:yKey', this.onYKeyChange, this);
@@ -115,6 +115,8 @@ export default class PlotSeries extends Model {
this.openmct = options.openmct;
this.domainObject = options.domainObject;
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.dataStoreId = `data-${options.collection.plot.id}-${this.keyString}`;
this.updateSeriesData([]);
this.limitEvaluator = this.openmct.telemetry.limitEvaluator(options.domainObject);
this.limitDefinition = this.openmct.telemetry.limitDefinition(options.domainObject);
this.limits = [];
@@ -182,7 +184,8 @@ export default class PlotSeries extends Model {
.telemetry
.request(this.domainObject, options)
.then(function (points) {
const newPoints = _(this.data)
const data = this.getSeriesData();
const newPoints = _(data)
.concat(points)
.sortBy(this.getXVal)
.uniq(true, point => [this.getXVal(point), this.getYVal(point)].join())
@@ -236,7 +239,7 @@ export default class PlotSeries extends Model {
*/
resetStats() {
this.unset('stats');
this.data.forEach(this.updateStats, this);
this.getSeriesData().forEach(this.updateStats, this);
}
/**
@@ -244,7 +247,7 @@ export default class PlotSeries extends Model {
* data to series after reset.
*/
reset(newData) {
this.data = [];
this.updateSeriesData([]);
this.resetStats();
this.emit('reset');
if (newData) {
@@ -258,8 +261,9 @@ export default class PlotSeries extends Model {
*/
nearestPoint(xValue) {
const insertIndex = this.sortedIndex(xValue);
const lowPoint = this.data[insertIndex - 1];
const highPoint = this.data[insertIndex];
const data = this.getSeriesData();
const lowPoint = data[insertIndex - 1];
const highPoint = data[insertIndex];
const indexVal = this.getXVal(xValue);
const lowDistance = lowPoint
? indexVal - this.getXVal(lowPoint)
@@ -292,7 +296,7 @@ export default class PlotSeries extends Model {
* @private
*/
sortedIndex(point) {
return _.sortedIndexBy(this.data, point, this.getXVal);
return _.sortedIndexBy(this.getSeriesData(), point, this.getXVal);
}
/**
* Update min/max stats for the series.
@@ -346,9 +350,10 @@ export default class PlotSeries extends Model {
* a point to the end without dupe checking.
*/
add(point, appendOnly) {
let insertIndex = this.data.length;
let data = this.getSeriesData();
let insertIndex = data.length;
const currentYVal = this.getYVal(point);
const lastYVal = this.getYVal(this.data[insertIndex - 1]);
const lastYVal = this.getYVal(data[insertIndex - 1]);
if (this.isValueInvalid(currentYVal) && this.isValueInvalid(lastYVal)) {
console.warn('[Plot] Invalid Y Values detected');
@@ -358,18 +363,19 @@ export default class PlotSeries extends Model {
if (!appendOnly) {
insertIndex = this.sortedIndex(point);
if (this.getXVal(this.data[insertIndex]) === this.getXVal(point)) {
if (this.getXVal(data[insertIndex]) === this.getXVal(point)) {
return;
}
if (this.getXVal(this.data[insertIndex - 1]) === this.getXVal(point)) {
if (this.getXVal(data[insertIndex - 1]) === this.getXVal(point)) {
return;
}
}
this.updateStats(point);
point.mctLimitState = this.evaluate(point);
this.data.splice(insertIndex, 0, point);
data.splice(insertIndex, 0, point);
this.updateSeriesData(data);
this.emit('add', point, insertIndex, this);
}
@@ -386,8 +392,10 @@ export default class PlotSeries extends Model {
* @private
*/
remove(point) {
const index = this.data.indexOf(point);
this.data.splice(index, 1);
let data = this.getSeriesData();
const index = data.indexOf(point);
data.splice(index, 1);
this.updateSeriesData(data);
this.emit('remove', point, index, this);
}
/**
@@ -403,14 +411,16 @@ export default class PlotSeries extends Model {
purgeRecordsOutsideRange(range) {
const startIndex = this.sortedIndex(range.min);
const endIndex = this.sortedIndex(range.max) + 1;
const pointsToRemove = startIndex + (this.data.length - endIndex + 1);
let data = this.getSeriesData();
const pointsToRemove = startIndex + (data.length - endIndex + 1);
if (pointsToRemove > 0) {
if (pointsToRemove < 1000) {
this.data.slice(0, startIndex).forEach(this.remove, this);
this.data.slice(endIndex, this.data.length).forEach(this.remove, this);
data.slice(0, startIndex).forEach(this.remove, this);
data.slice(endIndex, data.length).forEach(this.remove, this);
this.updateSeriesData(data);
this.resetStats();
} else {
const newData = this.data.slice(startIndex, endIndex);
const newData = this.getSeriesData().slice(startIndex, endIndex);
this.reset(newData);
}
}
@@ -441,12 +451,13 @@ export default class PlotSeries extends Model {
}
}
getDisplayRange(xKey) {
const unsortedData = this.data;
this.data = [];
const unsortedData = this.getSeriesData();
this.updateSeriesData([]);
unsortedData.forEach(point => this.add(point, false));
const minValue = this.getXVal(this.data[0]);
const maxValue = this.getXVal(this.data[this.data.length - 1]);
let data = this.getSeriesData();
const minValue = this.getXVal(data[0]);
const maxValue = this.getXVal(data[data.length - 1]);
return {
min: minValue,
@@ -470,4 +481,18 @@ export default class PlotSeries extends Model {
return this.get('name') + (unit ? ' ' + unit : '');
}
/**
* Update the series data with the given value.
*/
updateSeriesData(data) {
configStore.add(this.dataStoreId, data);
}
/**
* Update the series data with the given value.
*/
getSeriesData() {
return configStore.get(this.dataStoreId) || [];
}
}

View File

@@ -25,7 +25,10 @@ function ConfigStore() {
ConfigStore.prototype.deleteStore = function (id) {
if (this.store[id]) {
this.store[id].destroy();
if (this.store[id].destroy) {
this.store[id].destroy();
}
delete this.store[id];
}
};

View File

@@ -176,7 +176,9 @@ DrawWebGL.prototype.doDraw = function (drawType, buf, color, points, shape) {
this.gl.vertexAttribPointer(this.aVertexPosition, 2, this.gl.FLOAT, false, 0, 0);
this.gl.uniform4fv(this.uColor, color);
this.gl.uniform1i(this.uMarkerShape, shapeCode);
this.gl.drawArrays(drawType, 0, points);
if (points !== 0) {
this.gl.drawArrays(drawType, 0, points);
}
};
DrawWebGL.prototype.clear = function () {

View File

@@ -715,14 +715,15 @@ describe("the plugin", function () {
});
it("Adds a new point to the plot", (done) => {
let originalLength = config.series.models[0].data.length;
let originalLength = config.series.models[0].getSeriesData().length;
config.series.models[0].add({
utc: 2,
'some-key': 1,
'some-other-key': 2
});
Vue.nextTick(() => {
expect(config.series.models[0].data.length).toEqual(originalLength + 1);
const seriesData = config.series.models[0].getSeriesData();
expect(seriesData.length).toEqual(originalLength + 1);
done();
});
});

View File

@@ -90,7 +90,8 @@ export default {
cursorGuide: false,
gridLines: true,
loading: false,
compositionObjects: []
compositionObjects: [],
tickWidthMap: {}
};
},
computed: {
@@ -106,8 +107,6 @@ export default {
this.imageExporter = new ImageExporter(this.openmct);
this.tickWidthMap = {};
this.composition.on('add', this.addChild);
this.composition.on('remove', this.removeChild);
this.composition.on('reorder', this.compositionReorder);
@@ -127,18 +126,21 @@ export default {
addChild(child) {
const id = this.openmct.objects.makeKeyString(child.identifier);
this.tickWidthMap[id] = 0;
this.$set(this.tickWidthMap, id, 0);
this.compositionObjects.push(child);
},
removeChild(childIdentifier) {
const id = this.openmct.objects.makeKeyString(childIdentifier);
delete this.tickWidthMap[id];
this.$delete(this.tickWidthMap, id);
const childObj = this.compositionObjects.filter((c) => {
const identifier = this.openmct.objects.makeKeyString(c.identifier);
return identifier === id;
})[0];
if (childObj) {
const index = this.compositionObjects.indexOf(childObj);
this.compositionObjects.splice(index, 1);
@@ -191,14 +193,7 @@ export default {
return;
}
//update the tickWidth for this plotId, the computed max tick width of the stacked plot will be cascaded down
//TODO: Might need to do this using $set
this.tickWidthMap[plotId] = Math.max(width, this.tickWidthMap[plotId]);
// const newTickWidth = Math.max(...Object.values(this.tickWidthMap));
// if (newTickWidth !== tickWidth || width !== tickWidth) {
// tickWidth = newTickWidth;
// $scope.$broadcast('plot:tickWidth', tickWidth);
// }
}
}
};

View File

@@ -68,7 +68,8 @@ define([
'./performanceIndicator/plugin',
'./CouchDBSearchFolder/plugin',
'./timeline/plugin',
'./hyperlink/plugin'
'./hyperlink/plugin',
'./clock/plugin'
], function (
_,
UTCTimeSystem,
@@ -117,7 +118,8 @@ define([
PerformanceIndicator,
CouchDBSearchFolder,
Timeline,
Hyperlink
Hyperlink,
Clock
) {
const bundleMap = {
LocalStorage: 'platform/persistence/local',
@@ -221,6 +223,7 @@ define([
plugins.CouchDBSearchFolder = CouchDBSearchFolder.default;
plugins.Timeline = Timeline.default;
plugins.Hyperlink = Hyperlink.default;
plugins.Clock = Clock.default;
return plugins;
});

View File

@@ -137,7 +137,10 @@ describe("the RemoteClock plugin", () => {
it('will request the latest datum for the object it received and process the datum returned', () => {
expect(openmct.telemetry.request).toHaveBeenCalledWith(remoteClock.timeTelemetryObject, REQ_OPTIONS);
expect(boundsCallback).toHaveBeenCalledWith({ start: TIME_VALUE + OFFSET_START, end: TIME_VALUE + OFFSET_END }, true);
expect(boundsCallback).toHaveBeenCalledWith({
start: TIME_VALUE + OFFSET_START,
end: TIME_VALUE + OFFSET_END
}, true);
});
it('will set up subscriptions correctly', () => {

View File

@@ -22,7 +22,7 @@
import RemoteClock from "./RemoteClock";
/**
* Install a clock that uses a configurable telemetry endpoint.
* Install a clock that uses a configurable telemetry endpoint.
*/
export default function (identifier) {

View File

@@ -233,6 +233,7 @@ export default {
},
mounted: function () {
document.addEventListener('click', this.closeViewAndSaveMenu);
this.promptUserbeforeNavigatingAway = this.promptUserbeforeNavigatingAway.bind(this);
window.addEventListener('beforeunload', this.promptUserbeforeNavigatingAway);
this.openmct.editor.on('isEditing', (isEditing) => {
@@ -253,7 +254,7 @@ export default {
}
document.removeEventListener('click', this.closeViewAndSaveMenu);
window.removeEventListener('click', this.promptUserbeforeNavigatingAway);
window.removeEventListener('beforeunload', this.promptUserbeforeNavigatingAway);
},
methods: {
toggleSaveMenu() {

View File

@@ -53,6 +53,7 @@
class="l-shell__pane-tree"
handle="after"
label="Browse"
hide-param="hideTree"
collapsable
@start-resizing="onStartResizing"
@end-resizing="onEndResizing"
@@ -104,6 +105,7 @@
class="l-shell__pane-inspector l-pane--holds-multipane"
handle="before"
label="Inspect"
hide-param="hideInspector"
collapsable
@start-resizing="onStartResizing"
@end-resizing="onEndResizing"

171
src/ui/layout/LayoutSpec.js Normal file
View File

@@ -0,0 +1,171 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
import {
createOpenMct,
resetApplicationState
} from 'utils/testing';
import Vue from 'vue';
import Layout from './Layout.vue';
describe('Open MCT Layout:', () => {
let openmct;
let element;
let components;
beforeEach((done) => {
openmct = createOpenMct();
openmct.on('start', done);
// to silence error from BrowseBar.vue
spyOn(openmct.objectViews, 'get')
.and.callFake(() => []);
openmct.startHeadless();
});
afterEach(() => {
return resetApplicationState(openmct);
});
describe('the pane:', () => {
it('is displayed on layout load', async () => {
await createLayout();
await Vue.nextTick();
Object.entries(components).forEach(([name, component]) => {
expect(
component.pane
).toBeTruthy();
expect(
isCollapsed(component.pane)
).toBeFalse();
});
});
it('is collapsed on layout load if specified by a hide param', async () => {
setHideParams();
await createLayout();
await Vue.nextTick();
Object.entries(components).forEach(([name, component]) => {
expect(
isCollapsed(component.pane)
).toBeTrue();
});
});
it('on toggle collapses if expanded', async () => {
await createLayout();
toggleCollapseButtons();
await Vue.nextTick();
Object.entries(components).forEach(([name, component]) => {
expect(
openmct.router.getSearchParam(component.param)
).toEqual('true');
expect(
isCollapsed(component.pane)
).toBeTrue();
});
});
it('on toggle expands if collapsed', async () => {
setHideParams();
await createLayout();
toggleExpandButtons();
await Vue.nextTick();
Object.entries(components).forEach(([name, component]) => {
expect(
openmct.router.getSearchParam(component.param)
).not.toEqual('true');
expect(
isCollapsed(component.pane)
).toBeFalse();
});
});
});
async function createLayout() {
const el = document.createElement('div');
const child = document.createElement('div');
el.appendChild(child);
element = await new Vue({
el,
components: {
Layout
},
provide: {
openmct
},
template: `<Layout ref="layout"/>`
}).$mount().$el;
setComponents();
}
function setComponents() {
components = {
tree: {
param: 'hideTree',
pane: element.querySelector('.l-shell__pane-tree'),
collapseButton: element.querySelector('.l-shell__pane-tree .l-pane__collapse-button'),
expandButton: element.querySelector('.l-shell__pane-tree .l-pane__expand-button')
},
inspector: {
param: 'hideInspector',
pane: element.querySelector('.l-shell__pane-inspector'),
collapseButton: element.querySelector('.l-shell__pane-inspector .l-pane__collapse-button'),
expandButton: element.querySelector('.l-shell__pane-inspector .l-pane__expand-button')
}
};
}
function isCollapsed(el) {
return el.classList.contains('l-pane--collapsed');
}
function setHideParams() {
Object.entries(components).forEach(([name, component]) => {
openmct.router.setSearchParam(component.param, true);
});
}
function toggleCollapseButtons() {
Object.entries(components).forEach(([name, component]) => {
component.collapseButton.click();
});
}
function toggleExpandButtons() {
Object.entries(components).forEach(([name, component]) => {
component.expandButton.click();
});
}
});

View File

@@ -41,10 +41,6 @@
<script>
const COLLAPSE_THRESHOLD_PX = 40;
const HIDE_TREE_PARAM = 'hideTree';
const HIDE_INSPECTOR_PARAM = 'hideInspector';
const PANE_INSPECTOR = 'Inspect';
const PANE_TREE = 'Browse';
export default {
inject: ['openmct'],
@@ -63,6 +59,10 @@ export default {
label: {
type: String,
default: ''
},
hideParam: {
type: String,
default: ''
}
},
data() {
@@ -78,39 +78,27 @@ export default {
async mounted() {
await this.$nextTick();
// Hide tree and/or inspector pane if specified in URL
this.handleHideUrl();
this.openmct.router.on('change:params', this.handleHideUrl);
if (this.collapsable) {
this.handleHideUrl();
}
},
beforeDestroy() {
this.openmct.router.off('change:params', this.handleHideUrl);
},
methods: {
toggleCollapse: function (e) {
let target = this.label === PANE_TREE ? HIDE_TREE_PARAM : HIDE_INSPECTOR_PARAM;
this.collapsed = !this.collapsed;
if (this.collapsed) {
this.handleCollapse();
this.addHideParam(target);
} else {
this.handleExpand();
this.removeHideParam(target);
this.removeHideParam(this.hideParam);
} else {
this.handleCollapse();
this.addHideParam(this.hideParam);
}
},
handleHideUrl: function () {
if (!this.collapsable) {
return;
}
const hideParam = this.openmct.router.getSearchParam(this.hideParam);
let hideTreeParam = this.openmct.router.getSearchParam(HIDE_TREE_PARAM);
let hideInspectorParam = this.openmct.router.getSearchParam(HIDE_INSPECTOR_PARAM);
let hideTree = hideTreeParam === 'true' && this.label === PANE_TREE;
let hideInspector = hideInspectorParam === 'true' && this.label === PANE_INSPECTOR;
if (hideTree || hideInspector) {
this.collapsed = true;
if (hideParam === 'true') {
this.handleCollapse();
} else {
this.collapsed = false;
this.handleExpand();
}
},
addHideParam: function (target) {
@@ -122,11 +110,13 @@ export default {
handleCollapse: function () {
this.currentSize = (this.dragCollapse === true) ? this.initial : this.$el.style[this.styleProp];
this.$el.style[this.styleProp] = '';
this.collapsed = true;
},
handleExpand: function () {
this.$el.style[this.styleProp] = this.currentSize;
delete this.currentSize;
delete this.dragCollapse;
this.collapsed = false;
},
trackSize: function () {
if (!this.dragCollapse === true) {

View File

@@ -1,90 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
import {
createOpenMct,
resetApplicationState
} from 'utils/testing';
describe("the pane", () => {
let openmct;
let appHolder;
let element;
let child;
let resolveFunction;
beforeEach((done) => {
openmct = createOpenMct();
appHolder = document.createElement('div');
appHolder.style.width = '640px';
appHolder.style.height = '480px';
openmct = createOpenMct();
openmct.install(openmct.plugins.MyItems());
openmct.install(openmct.plugins.LocalTimeSystem());
openmct.install(openmct.plugins.UTCTimeSystem());
element = document.createElement('div');
child = document.createElement('div');
element.appendChild(child);
openmct.on('start', done);
openmct.start(appHolder);
document.body.append(appHolder);
});
afterEach(() => {
return resetApplicationState(openmct);
});
it('toggling tree will toggle tree hide params', (done) => {
document.querySelector('.l-shell__pane-tree .l-pane__collapse-button').click();
expect(openmct.router.getSearchParam('hideTree')).toBe('true');
done();
});
it('tree pane collapses when adding hide tree param in URL', () => {
openmct.router.setSearchParam('hideTree', 'true');
expect(document.querySelector('.l-shell__pane-tree.l-pane--collapsed')).toBeDefined();
});
it('inspector pane collapses when adding hide inspector param in URL', () => {
openmct.router.setSearchParam('hideInspector', 'true');
expect(document.querySelector('.l-shell__pane-inspector.l-pane--collapsed')).toBeDefined();
});
it('toggle inspector pane will toggle inspector hide param', (done) => {
// There's a short delay on addubg the param.
resolveFunction = () => {
setTimeout(() => {
expect(openmct.router.getSearchParam('hideInspector')).toBe('true');
done();
}, 500);
};
openmct.router.on('change:params', resolveFunction);
document.querySelector('.l-shell__pane-inspector .l-pane__collapse-button').click();
});
});

View File

@@ -104,7 +104,6 @@ export default {
},
mounted() {
if (this.actionCollection) {
this.actionCollection.hide(HIDDEN_ACTIONS);
this.actionCollection.on('update', this.updateActionItems);
this.updateActionItems(this.actionCollection.getActionsObject());
}