Compare commits

..

1 Commits

Author SHA1 Message Date
Joshi
14b5c8c1be OpenMCT version 1.4.1 2020-12-11 05:44:46 -08:00
8 changed files with 9 additions and 513 deletions

View File

@@ -182,7 +182,7 @@ The following guidelines are provided for anyone contributing source code to the
1. Avoid the use of "magic" values.
eg.
```JavaScript
const UNAUTHORIZED = 401;
Const UNAUTHORIZED = 401
if (responseCode === UNAUTHORIZED)
```
is preferable to

View File

@@ -1,6 +1,6 @@
{
"name": "openmct",
"version": "1.5.0-SNAPSHOT",
"version": "1.4.1",
"description": "The Open MCT core platform",
"dependencies": {},
"devDependencies": {
@@ -101,5 +101,5 @@
},
"author": "",
"license": "Apache-2.0",
"private": true
"private": false
}

View File

@@ -36,7 +36,7 @@
<div class="c-imagery__main-image__bg"
:class="{'paused unnsynced': isPaused,'stale':false }"
>
<div class="c-imagery__main-image__image js-imageryView-image"
<div class="c-imagery__main-image__image"
:style="{
'background-image': imageUrl ? `url(${imageUrl})` : 'none',
'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)`

View File

@@ -1,258 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, 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 ImageryPlugin from './plugin.js';
import Vue from 'vue';
import {
createOpenMct,
resetApplicationState
} from 'utils/testing';
const ONE_MINUTE = 1000 * 60;
const TEN_MINUTES = ONE_MINUTE * 10;
const MAIN_IMAGE_CLASS = '.js-imageryView-image';
const NEW_IMAGE_CLASS = '.c-imagery__age.c-imagery--new';
const REFRESH_CSS_MS = 500;
function getImageInfo(doc) {
let imageElement = doc.querySelectorAll(MAIN_IMAGE_CLASS)[0];
let timestamp = imageElement.dataset.openmctImageTimestamp;
let identifier = imageElement.dataset.openmctObjectKeystring;
let url = imageElement.style.backgroundImage;
return {
timestamp,
identifier,
url
};
}
function isNew(doc) {
let newIcon = doc.querySelectorAll(NEW_IMAGE_CLASS);
return newIcon.length !== 0;
}
function generateTelemetry(start, count) {
let telemetry = [];
for (let i = 1, l = count + 1; i < l; i++) {
let stringRep = i + 'minute';
let logo = 'images/logo-openmct.svg';
telemetry.push({
"name": stringRep + " Imagery",
"utc": start + (i * ONE_MINUTE),
"url": location.host + '/' + logo + '?time=' + stringRep,
"timeId": stringRep
});
}
return telemetry;
}
describe("The Imagery View Layout", () => {
const imageryKey = 'example.imagery';
const START = Date.now();
const COUNT = 10;
let openmct;
let imageryPlugin;
let parent;
let child;
let timeFormat = 'utc';
let bounds = {
start: START - TEN_MINUTES,
end: START
};
let imageTelemetry = generateTelemetry(START - TEN_MINUTES, COUNT);
let imageryObject = {
identifier: {
namespace: "",
key: "imageryId"
},
name: "Example Imagery",
type: "example.imagery",
location: "parentId",
modified: 0,
persisted: 0,
telemetry: {
values: [
{
"name": "Image",
"key": "url",
"format": "image",
"hints": {
"image": 1,
"priority": 3
},
"source": "url"
},
{
"name": "Name",
"key": "name",
"source": "name",
"hints": {
"priority": 0
}
},
{
"name": "Time",
"key": "utc",
"format": "utc",
"hints": {
"domain": 2,
"priority": 1
},
"source": "utc"
},
{
"name": "Local Time",
"key": "local",
"format": "local-format",
"hints": {
"domain": 1,
"priority": 2
},
"source": "local"
}
]
}
};
// this setups up the app
beforeEach((done) => {
const appHolder = document.createElement('div');
appHolder.style.width = '640px';
appHolder.style.height = '480px';
openmct = createOpenMct();
parent = document.createElement('div');
child = document.createElement('div');
parent.appendChild(child);
spyOn(openmct.telemetry, 'request').and.returnValue(Promise.resolve([]));
imageryPlugin = new ImageryPlugin();
openmct.install(imageryPlugin);
spyOn(openmct.objects, 'get').and.returnValue(Promise.resolve({}));
openmct.time.timeSystem(timeFormat, {
start: 0,
end: 4
});
openmct.on('start', done);
openmct.startHeadless(appHolder);
});
afterEach(() => {
return resetApplicationState(openmct);
});
it("should provide an imagery view only for imagery producing objects", () => {
let applicableViews = openmct.objectViews.get(imageryObject);
let imageryView = applicableViews.find(
viewProvider => viewProvider.key === imageryKey
);
expect(imageryView).toBeDefined();
});
describe("imagery view", () => {
let applicableViews;
let imageryViewProvider;
let imageryView;
beforeEach(async (done) => {
let telemetryRequestResolve;
let telemetryRequestPromise = new Promise((resolve) => {
telemetryRequestResolve = resolve;
});
openmct.telemetry.request.and.callFake(() => {
telemetryRequestResolve(imageTelemetry);
return telemetryRequestPromise;
});
openmct.time.clock('local', {
start: bounds.start,
end: bounds.end + 100
});
applicableViews = openmct.objectViews.get(imageryObject);
imageryViewProvider = applicableViews.find(viewProvider => viewProvider.key === imageryKey);
imageryView = imageryViewProvider.view(imageryObject);
imageryView.show(child);
await telemetryRequestPromise;
await Vue.nextTick();
return done();
});
it("on mount should show the the most recent image", () => {
const imageInfo = getImageInfo(parent);
expect(imageInfo.url.indexOf(imageTelemetry[COUNT - 1].timeId)).not.toEqual(-1);
});
it("should show the clicked thumbnail as the main image", async () => {
const target = imageTelemetry[5].url;
parent.querySelectorAll(`img[src='${target}']`)[0].click();
await Vue.nextTick();
const imageInfo = getImageInfo(parent);
expect(imageInfo.url.indexOf(imageTelemetry[5].timeId)).not.toEqual(-1);
});
it("should show that an image is new", async (done) => {
await Vue.nextTick();
// used in code, need to wait to the 500ms here too
setTimeout(() => {
const imageIsNew = isNew(parent);
expect(imageIsNew).toBeTrue();
done();
}, REFRESH_CSS_MS);
});
it("should show that an image is not new", async (done) => {
const target = imageTelemetry[2].url;
parent.querySelectorAll(`img[src='${target}']`)[0].click();
await Vue.nextTick();
// used in code, need to wait to the 500ms here too
setTimeout(() => {
const imageIsNew = isNew(parent);
expect(imageIsNew).toBeFalse();
done();
}, REFRESH_CSS_MS);
});
});
});

View File

@@ -143,9 +143,7 @@ export default {
this.openmct.notifications.alert(message);
}
const relativeHash = hash.slice(hash.indexOf('#'));
const url = new URL(relativeHash, `${location.protocol}//${location.host}${location.pathname}`);
window.location.hash = url.hash;
window.location.hash = hash;
},
formatTime(unixTime, timeFormat) {
return Moment.utc(unixTime).format(timeFormat);

View File

@@ -73,15 +73,6 @@
>
<!-- RT start -->
<div class="c-direction-indicator icon-minus"></div>
<time-popup
v-if="showTCInputStart"
class="pr-tc-input-menu--start"
:type="'start'"
:offset="offsets.start"
@focus.native="$event.target.select()"
@hide="hideAllTimePopups"
@update="timePopUpdate"
/>
<input
ref="startOffset"
v-model="offsets.start"
@@ -90,7 +81,6 @@
autocorrect="off"
spellcheck="false"
@change="validateAllOffsets(); submitForm()"
@click="showTimePopupStart"
>
</div>
@@ -107,7 +97,7 @@
autocorrect="off"
spellcheck="false"
:disabled="!isFixed"
@change="validateAllBounds('endDate'); submitForm ()"
@change="validateAllBounds('endDate'); submitForm()"
>
<date-picker
v-if="isFixed && isUTCBased"
@@ -124,15 +114,6 @@
>
<!-- RT end -->
<div class="c-direction-indicator icon-plus"></div>
<time-popup
v-if="showTCInputEnd"
class="pr-tc-input-menu--end"
:type="'end'"
:offset="offsets.end"
@focus.native="$event.target.select()"
@hide="hideAllTimePopups"
@update="timePopUpdate"
/>
<input
ref="endOffset"
v-model="offsets.end"
@@ -141,7 +122,6 @@
autocorrect="off"
spellcheck="false"
@change="validateAllOffsets(); submitForm()"
@click="showTimePopupEnd"
>
</div>
@@ -183,7 +163,6 @@ import DatePicker from './DatePicker.vue';
import ConductorAxis from './ConductorAxis.vue';
import ConductorModeIcon from './ConductorModeIcon.vue';
import ConductorHistory from './ConductorHistory.vue';
import TimePopup from './timePopup.vue';
const DEFAULT_DURATION_FORMATTER = 'duration';
@@ -195,8 +174,7 @@ export default {
DatePicker,
ConductorAxis,
ConductorModeIcon,
ConductorHistory,
TimePopup
ConductorHistory
},
data() {
let bounds = this.openmct.time.bounds();
@@ -230,9 +208,7 @@ export default {
showDatePicker: false,
altPressed: false,
isPanning: false,
isZooming: false,
showTCInputStart: false,
showTCInputEnd: false
isZooming: false
};
},
computed: {
@@ -481,25 +457,6 @@ export default {
this.formattedBounds.end = this.timeFormatter.format(date);
this.validateAllBounds('endDate');
this.submitForm();
},
hideAllTimePopups() {
this.showTCInputStart = false;
this.showTCInputEnd = false;
},
showTimePopupStart() {
this.hideAllTimePopups();
this.showTCInputStart = !this.showTCInputStart;
},
showTimePopupEnd() {
this.hideAllTimePopups();
this.showTCInputEnd = !this.showTCInputEnd;
},
timePopUpdate(opts) {
let { type, hours, minutes, seconds } = opts;
this.offsets[type] = [hours, minutes, seconds].join(':');
this.setOffsetsFromView();
this.hideAllTimePopups();
}
}
};

View File

@@ -207,7 +207,7 @@
}
.is-realtime-mode {
.c-conductor__controls button {
button {
@include themedButton($colorTimeBg);
color: $colorTimeFg;
@@ -236,77 +236,3 @@
}
}
}
// Prototype
[class^='pr-tc-input-menu'] {
background: $colorBodyBg;
border-radius: $controlCr;
filter: brightness(1.4);
box-shadow: $shdwMenu;
padding: $interiorMargin;
position: absolute;
width: 170px;
height: 90px;
bottom: 20px;
z-index: 99;
&[class*='--start'] {
left: -25px;
}
&[class*='--end'] {
right: 0;
}
> * + * {
margin-top: $interiorMargin;
}
}
[class^='pr-tim'] {
display: flex;
align-items: center;
justify-content: flex-start;
> * + * {
//margin-left: $interiorMarginSm;
}
&[class*='labels'] {
font-size: 0.8em;
[class*='__'] {
opacity: 0.6;
width: 50px;
}
[class*='_hrs'] {
width: 67px;
}
}
&[class*='inputs'] {
//background: deeppink;
border: 1px solid rgba($colorBodyFg, 0.2);
border-radius: $controlCr;
padding: 2px;
input {
font-size: 1.25em;
width: 42px;
}
[class*='_hrs'] {
width: 52px;
}
[class*="colon"] {
padding: 0 2px;
}
}
&[class*='__buttons'] {
justify-content: flex-end;
}
}

View File

@@ -1,127 +0,0 @@
<template>
<div
class="pr-tc-input-menu"
@keydown.enter.prevent
@keyup.enter.prevent="submit"
@click.stop
>
<div class="pr-tim-labels">
<div class="pr-time-label__hrs">Hrs</div>
<div class="pr-time-label__mins">Mins</div>
<div class="pr-time-label__secs">Secs</div>
</div>
<div class="pr-tim-inputs">
<input
ref="inputHrs"
v-model="inputHrs"
class="pr-time-input__hrs"
step="1"
type="number"
min="0"
max="999"
@focusin="selectAll($event)"
@focusout="format('inputHrs')"
@wheel="increment($event, 'inputHrs')"
>
<span class="pr-tim-colon">:</span>
<input
ref="inputMins"
v-model="inputMins"
type="number"
class="pr-time-input__mins"
min="0"
max="59"
step="1"
@focusin="selectAll($event)"
@focusout="format('inputMins')"
@wheel="increment($event, 'inputMins')"
>
<span class="pr-tim-colon">:</span>
<input
ref="inputSecs"
v-model="inputSecs"
type="number"
class="pr-time-input__secs"
min="0"
max="59"
step="1"
@focusin="selectAll($event)"
@focusout="format('inputSecs')"
@wheel="increment($event, 'inputSecs')"
>
</div>
<div class="pr-tim__buttons c-button-set c-button-set--strip-h">
<button class="c-button icon-check"
@click.prevent="submit"
></button>
<button class="c-button icon-x"
@click.prevent="hide"
></button>
</div>
</div>
</template>
<script>
export default {
props: {
type: {
type: String,
required: true
},
offset: {
type: String,
required: true
}
},
data() {
return {
inputHrs: '000',
inputMins: '00',
inputSecs: '00'
};
},
mounted() {
this.setOffset();
document.addEventListener('click', this.hide);
},
beforeDestroy() {
document.removeEventListener('click', this.hide);
},
methods: {
format(ref) {
const curVal = this[ref];
const padAmt = (ref === 'inputHrs') ? 3 : 2;
this[ref] = curVal.padStart(padAmt, '0');
},
submit() {
this.$emit('update', {
type: this.type,
hours: this.inputHrs,
minutes: this.inputMins,
seconds: this.inputSecs
});
},
hide() {
this.$emit('hide');
},
increment($ev, ref) {
$ev.preventDefault();
const padAmt = (ref === 'inputHrs') ? 3 : 2;
const step = (ref === 'inputHrs') ? 1 : 5;
const maxVal = (ref === 'inputHrs') ? 999 : 59;
let cv = Math.round(parseInt(this[ref], 10) / step) * step;
cv = Math.min(maxVal, Math.max(0, ($ev.deltaY < 0) ? cv + step : cv - step));
this[ref] = cv.toString().padStart(padAmt, '0');
},
setOffset() {
[this.inputHrs, this.inputMins, this.inputSecs] = this.offset.split(':');
this.inputHrs = this.inputHrs.padStart(3, '0');
this.$refs.inputHrs.focus();
},
selectAll($ev) {
$ev.target.select();
}
}
};
</script>