mirror of
https://github.com/nasa/openmct.git
synced 2025-01-09 14:32:43 +00:00
Merge branch 'master' into remove-action-tests
Merging master
This commit is contained in:
commit
6bd0246db6
@ -28,6 +28,16 @@ define([
|
|||||||
domain: 2
|
domain: 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Need to enable "LocalTimeSystem" plugin to make use of this
|
||||||
|
// {
|
||||||
|
// key: "local",
|
||||||
|
// name: "Time",
|
||||||
|
// format: "local-format",
|
||||||
|
// source: "utc",
|
||||||
|
// hints: {
|
||||||
|
// domain: 3
|
||||||
|
// }
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
key: "sin",
|
key: "sin",
|
||||||
name: "Sine",
|
name: "Sine",
|
||||||
@ -61,6 +71,15 @@ define([
|
|||||||
domain: 1
|
domain: 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "local",
|
||||||
|
name: "Time",
|
||||||
|
format: "utc",
|
||||||
|
source: "utc",
|
||||||
|
hints: {
|
||||||
|
domain: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "state",
|
key: "state",
|
||||||
source: "value",
|
source: "value",
|
||||||
|
40
index.html
40
index.html
@ -34,8 +34,8 @@
|
|||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
<script>
|
<script>
|
||||||
const FIVE_MINUTES = 5 * 60 * 1000;
|
const THIRTY_SECONDS = 30 * 1000;
|
||||||
const THIRTY_MINUTES = 30 * 60 * 1000;
|
const THIRTY_MINUTES = THIRTY_SECONDS * 60;
|
||||||
|
|
||||||
[
|
[
|
||||||
'example/eventGenerator'
|
'example/eventGenerator'
|
||||||
@ -63,7 +63,39 @@
|
|||||||
bounds: {
|
bounds: {
|
||||||
start: Date.now() - THIRTY_MINUTES,
|
start: Date.now() - THIRTY_MINUTES,
|
||||||
end: Date.now()
|
end: Date.now()
|
||||||
}
|
},
|
||||||
|
// commonly used bounds can be stored in history
|
||||||
|
// bounds (start and end) can accept either a milliseconds number
|
||||||
|
// or a callback function returning a milliseconds number
|
||||||
|
// a function is useful for invoking Date.now() at exact moment of preset selection
|
||||||
|
presets: [
|
||||||
|
{
|
||||||
|
label: 'Last Day',
|
||||||
|
bounds: {
|
||||||
|
start: () => Date.now() - 1000 * 60 * 60 * 24,
|
||||||
|
end: () => Date.now()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Last 2 hours',
|
||||||
|
bounds: {
|
||||||
|
start: () => Date.now() - 1000 * 60 * 60 * 2,
|
||||||
|
end: () => Date.now()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Last hour',
|
||||||
|
bounds: {
|
||||||
|
start: () => Date.now() - 1000 * 60 * 60,
|
||||||
|
end: () => Date.now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// maximum recent bounds to retain in conductor history
|
||||||
|
records: 10,
|
||||||
|
// maximum duration between start and end bounds
|
||||||
|
// for utc-based time systems this is in milliseconds
|
||||||
|
limit: 1000 * 60 * 60 * 24
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Realtime",
|
name: "Realtime",
|
||||||
@ -71,7 +103,7 @@
|
|||||||
clock: 'local',
|
clock: 'local',
|
||||||
clockOffsets: {
|
clockOffsets: {
|
||||||
start: - THIRTY_MINUTES,
|
start: - THIRTY_MINUTES,
|
||||||
end: FIVE_MINUTES
|
end: THIRTY_SECONDS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -81,10 +81,15 @@ define(
|
|||||||
* context.
|
* context.
|
||||||
*/
|
*/
|
||||||
PropertiesAction.appliesTo = function (context) {
|
PropertiesAction.appliesTo = function (context) {
|
||||||
|
|
||||||
var domainObject = (context || {}).domainObject,
|
var domainObject = (context || {}).domainObject,
|
||||||
type = domainObject && domainObject.getCapability('type'),
|
type = domainObject && domainObject.getCapability('type'),
|
||||||
creatable = type && type.hasFeature('creation');
|
creatable = type && type.hasFeature('creation');
|
||||||
|
|
||||||
|
if (domainObject && domainObject.model && domainObject.model.locked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Only allow creatable types to be edited
|
// Only allow creatable types to be edited
|
||||||
return domainObject && creatable;
|
return domainObject && creatable;
|
||||||
};
|
};
|
||||||
|
@ -40,7 +40,18 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
MoveAction.prototype = Object.create(AbstractComposeAction.prototype);
|
MoveAction.prototype = Object.create(AbstractComposeAction.prototype);
|
||||||
MoveAction.appliesTo = AbstractComposeAction.appliesTo;
|
|
||||||
|
MoveAction.appliesTo = function (context) {
|
||||||
|
var applicableObject =
|
||||||
|
context.selectedObject || context.domainObject;
|
||||||
|
|
||||||
|
if (applicableObject && applicableObject.model.locked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boolean(applicableObject &&
|
||||||
|
applicableObject.hasCapability('context'));
|
||||||
|
};
|
||||||
|
|
||||||
return MoveAction;
|
return MoveAction;
|
||||||
}
|
}
|
||||||
|
@ -216,8 +216,14 @@ define(['zepto', 'objectUtils'], function ($, objectUtils) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ImportAsJSONAction.appliesTo = function (context) {
|
ImportAsJSONAction.appliesTo = function (context) {
|
||||||
return context.domainObject !== undefined &&
|
let domainObject = context.domainObject;
|
||||||
context.domainObject.hasCapability("composition");
|
|
||||||
|
if (domainObject && domainObject.model.locked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainObject !== undefined &&
|
||||||
|
domainObject.hasCapability("composition");
|
||||||
};
|
};
|
||||||
|
|
||||||
return ImportAsJSONAction;
|
return ImportAsJSONAction;
|
||||||
|
@ -64,7 +64,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
formattedTimestamp() {
|
formattedTimestamp() {
|
||||||
return this.timestamp !== undefined ? this.formats[this.timestampKey].format(this.timestamp) : '---';
|
return this.timestamp !== undefined ? this.getFormattedTimestamp(this.timestamp) : '---';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -110,11 +110,11 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateValues(datum) {
|
updateValues(datum) {
|
||||||
let newTimestamp = this.formats[this.timestampKey].parse(datum),
|
let newTimestamp = this.getParsedTimestamp(datum),
|
||||||
limit;
|
limit;
|
||||||
|
|
||||||
if(this.shouldUpdate(newTimestamp)) {
|
if(this.shouldUpdate(newTimestamp)) {
|
||||||
this.timestamp = this.formats[this.timestampKey].parse(datum);
|
this.timestamp = newTimestamp;
|
||||||
this.value = this.formats[this.valueKey].format(datum);
|
this.value = this.formats[this.valueKey].format(datum);
|
||||||
limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
|
limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
|
||||||
if (limit) {
|
if (limit) {
|
||||||
@ -125,9 +125,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
shouldUpdate(newTimestamp) {
|
shouldUpdate(newTimestamp) {
|
||||||
return (this.timestamp === undefined) ||
|
let newTimestampInBounds = this.inBounds(newTimestamp),
|
||||||
(this.inBounds(newTimestamp) &&
|
noExistingTimestamp = this.timestamp === undefined,
|
||||||
newTimestamp > this.timestamp);
|
newTimestampIsLatest = newTimestamp > this.timestamp;
|
||||||
|
|
||||||
|
return newTimestampInBounds &&
|
||||||
|
(noExistingTimestamp || newTimestampIsLatest);
|
||||||
},
|
},
|
||||||
requestHistory() {
|
requestHistory() {
|
||||||
this.openmct
|
this.openmct
|
||||||
@ -146,6 +149,7 @@ export default {
|
|||||||
updateBounds(bounds, isTick) {
|
updateBounds(bounds, isTick) {
|
||||||
this.bounds = bounds;
|
this.bounds = bounds;
|
||||||
if(!isTick) {
|
if(!isTick) {
|
||||||
|
this.resetValues();
|
||||||
this.requestHistory();
|
this.requestHistory();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -153,13 +157,34 @@ export default {
|
|||||||
return timestamp >= this.bounds.start && timestamp <= this.bounds.end;
|
return timestamp >= this.bounds.start && timestamp <= this.bounds.end;
|
||||||
},
|
},
|
||||||
updateTimeSystem(timeSystem) {
|
updateTimeSystem(timeSystem) {
|
||||||
this.value = '---';
|
this.resetValues();
|
||||||
this.timestamp = '---';
|
|
||||||
this.valueClass = '';
|
|
||||||
this.timestampKey = timeSystem.key;
|
this.timestampKey = timeSystem.key;
|
||||||
},
|
},
|
||||||
showContextMenu(event) {
|
showContextMenu(event) {
|
||||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
||||||
|
},
|
||||||
|
resetValues() {
|
||||||
|
this.value = '---';
|
||||||
|
this.timestamp = undefined;
|
||||||
|
this.valueClass = '';
|
||||||
|
},
|
||||||
|
getParsedTimestamp(timestamp) {
|
||||||
|
if(this.timeSystemFormat()) {
|
||||||
|
return this.formats[this.timestampKey].parse(timestamp);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getFormattedTimestamp(timestamp) {
|
||||||
|
if(this.timeSystemFormat()) {
|
||||||
|
return this.formats[this.timestampKey].format(timestamp);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
timeSystemFormat() {
|
||||||
|
if(this.formats[this.timestampKey]) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
console.warn(`No formatter for ${this.timestampKey} time system for ${this.domainObject.name}.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,7 @@ export default class Condition extends EventEmitter {
|
|||||||
criterion = new TelemetryCriterion(criterionConfigurationWithId, this.openmct);
|
criterion = new TelemetryCriterion(criterionConfigurationWithId, this.openmct);
|
||||||
}
|
}
|
||||||
criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||||
|
criterion.on('telemetryIsStale', (obj) => this.handleStaleCriterion(obj));
|
||||||
if (!this.criteria) {
|
if (!this.criteria) {
|
||||||
this.criteria = [];
|
this.criteria = [];
|
||||||
}
|
}
|
||||||
@ -178,10 +179,12 @@ export default class Condition extends EventEmitter {
|
|||||||
const newCriterionConfiguration = this.generateCriterion(criterionConfiguration);
|
const newCriterionConfiguration = this.generateCriterion(criterionConfiguration);
|
||||||
let newCriterion = new TelemetryCriterion(newCriterionConfiguration, this.openmct);
|
let newCriterion = new TelemetryCriterion(newCriterionConfiguration, this.openmct);
|
||||||
newCriterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
newCriterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||||
|
newCriterion.on('telemetryIsStale', (obj) => this.handleStaleCriterion(obj));
|
||||||
|
|
||||||
let criterion = found.item;
|
let criterion = found.item;
|
||||||
criterion.unsubscribe();
|
criterion.unsubscribe();
|
||||||
criterion.off('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
criterion.off('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||||
|
criterion.off('telemetryIsStale', (obj) => this.handleStaleCriterion(obj));
|
||||||
this.criteria.splice(found.index, 1, newCriterion);
|
this.criteria.splice(found.index, 1, newCriterion);
|
||||||
this.updateDescription();
|
this.updateDescription();
|
||||||
}
|
}
|
||||||
@ -194,6 +197,9 @@ export default class Condition extends EventEmitter {
|
|||||||
criterion.off('criterionUpdated', (obj) => {
|
criterion.off('criterionUpdated', (obj) => {
|
||||||
this.handleCriterionUpdated(obj);
|
this.handleCriterionUpdated(obj);
|
||||||
});
|
});
|
||||||
|
criterion.off('telemetryIsStale', (obj) => {
|
||||||
|
this.handleStaleCriterion(obj);
|
||||||
|
});
|
||||||
criterion.destroy();
|
criterion.destroy();
|
||||||
this.criteria.splice(found.index, 1);
|
this.criteria.splice(found.index, 1);
|
||||||
this.updateDescription();
|
this.updateDescription();
|
||||||
@ -211,6 +217,18 @@ export default class Condition extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleStaleCriterion(updatedCriterion) {
|
||||||
|
this.result = evaluateResults(this.criteria.map(criterion => criterion.result), this.trigger);
|
||||||
|
let latestTimestamp = {};
|
||||||
|
latestTimestamp = getLatestTimestamp(
|
||||||
|
latestTimestamp,
|
||||||
|
updatedCriterion.data,
|
||||||
|
this.timeSystems,
|
||||||
|
this.openmct.time.timeSystem()
|
||||||
|
);
|
||||||
|
this.conditionManager.updateCurrentCondition(latestTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
updateDescription() {
|
updateDescription() {
|
||||||
const triggerDescription = this.getTriggerDescription();
|
const triggerDescription = this.getTriggerDescription();
|
||||||
let description = '';
|
let description = '';
|
||||||
|
@ -103,6 +103,8 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
criterion.operation = '';
|
criterion.operation = '';
|
||||||
conditionChanged = true;
|
conditionChanged = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
conditionChanged = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (conditionChanged) {
|
if (conditionChanged) {
|
||||||
@ -315,6 +317,10 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
condition.getResult(normalizedDatum);
|
condition.getResult(normalizedDatum);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.updateCurrentCondition(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCurrentCondition(timestamp) {
|
||||||
const currentCondition = this.getCurrentCondition();
|
const currentCondition = this.getCurrentCondition();
|
||||||
|
|
||||||
this.emit('conditionSetResultUpdated',
|
this.emit('conditionSetResultUpdated',
|
||||||
|
@ -27,13 +27,13 @@
|
|||||||
>
|
>
|
||||||
{{ condition.configuration.name }}
|
{{ condition.configuration.name }}
|
||||||
</span>
|
</span>
|
||||||
<span class="c-style__condition-desc__text"
|
<span v-if="!condition.isDefault"
|
||||||
v-if="!condition.isDefault"
|
class="c-style__condition-desc__text"
|
||||||
>
|
>
|
||||||
{{ description }}
|
{{ description }}
|
||||||
</span>
|
</span>
|
||||||
<span class="c-style__condition-desc__text"
|
<span v-else
|
||||||
v-else
|
class="c-style__condition-desc__text"
|
||||||
>
|
>
|
||||||
Match if no other condition is matched
|
Match if no other condition is matched
|
||||||
</span>
|
</span>
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
>
|
>
|
||||||
{{ option.name }}
|
{{ option.name }}
|
||||||
</option>
|
</option>
|
||||||
|
<option value="dataReceived">any data received</option>
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="criterion.telemetry && criterion.metadata"
|
<span v-if="criterion.telemetry && criterion.metadata"
|
||||||
@ -83,6 +84,7 @@
|
|||||||
>
|
>
|
||||||
<span v-if="inputIndex < inputCount-1">and</span>
|
<span v-if="inputIndex < inputCount-1">and</span>
|
||||||
</span>
|
</span>
|
||||||
|
<span v-if="criterion.metadata === 'dataReceived'">seconds</span>
|
||||||
</template>
|
</template>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<span v-if="inputCount && criterion.operation"
|
<span v-if="inputCount && criterion.operation"
|
||||||
@ -148,7 +150,11 @@ export default {
|
|||||||
return (this.index !== 0 ? operator : '') + ' when';
|
return (this.index !== 0 ? operator : '') + ' when';
|
||||||
},
|
},
|
||||||
filteredOps: function () {
|
filteredOps: function () {
|
||||||
return this.operations.filter(op => op.appliesTo.indexOf(this.operationFormat) !== -1);
|
if (this.criterion.metadata === 'dataReceived') {
|
||||||
|
return this.operations.filter(op => op.name === 'isStale');
|
||||||
|
} else {
|
||||||
|
return this.operations.filter(op => op.appliesTo.indexOf(this.operationFormat) !== -1);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setInputType: function () {
|
setInputType: function () {
|
||||||
let type = '';
|
let type = '';
|
||||||
@ -214,6 +220,8 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.operationFormat = 'number';
|
this.operationFormat = 'number';
|
||||||
}
|
}
|
||||||
|
} else if (this.criterion.metadata === 'dataReceived') {
|
||||||
|
this.operationFormat = 'number';
|
||||||
}
|
}
|
||||||
this.updateInputVisibilityAndValues();
|
this.updateInputVisibilityAndValues();
|
||||||
},
|
},
|
||||||
|
@ -37,12 +37,13 @@
|
|||||||
>
|
>
|
||||||
<style-editor class="c-inspect-styles__editor"
|
<style-editor class="c-inspect-styles__editor"
|
||||||
:style-item="staticStyle"
|
:style-item="staticStyle"
|
||||||
:is-editing="isEditing"
|
:is-editing="allowEditing"
|
||||||
:mixed-styles="mixedStyles"
|
:mixed-styles="mixedStyles"
|
||||||
@persist="updateStaticStyle"
|
@persist="updateStaticStyle"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
v-if="allowEditing"
|
||||||
id="addConditionSet"
|
id="addConditionSet"
|
||||||
class="c-button c-button--major c-toggle-styling-button labeled"
|
class="c-button c-button--major c-toggle-styling-button labeled"
|
||||||
@click="addConditionSet"
|
@click="addConditionSet"
|
||||||
@ -63,7 +64,7 @@
|
|||||||
>
|
>
|
||||||
<span class="c-object-label__name">{{ conditionSetDomainObject.name }}</span>
|
<span class="c-object-label__name">{{ conditionSetDomainObject.name }}</span>
|
||||||
</a>
|
</a>
|
||||||
<template v-if="isEditing">
|
<template v-if="allowEditing">
|
||||||
<button
|
<button
|
||||||
id="changeConditionSet"
|
id="changeConditionSet"
|
||||||
class="c-button labeled"
|
class="c-button labeled"
|
||||||
@ -96,7 +97,7 @@
|
|||||||
/>
|
/>
|
||||||
<style-editor class="c-inspect-styles__editor"
|
<style-editor class="c-inspect-styles__editor"
|
||||||
:style-item="conditionStyle"
|
:style-item="conditionStyle"
|
||||||
:is-editing="isEditing"
|
:is-editing="allowEditing"
|
||||||
@persist="updateConditionalStyle"
|
@persist="updateConditionalStyle"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -137,7 +138,13 @@ export default {
|
|||||||
conditions: undefined,
|
conditions: undefined,
|
||||||
conditionsLoaded: false,
|
conditionsLoaded: false,
|
||||||
navigateToPath: '',
|
navigateToPath: '',
|
||||||
selectedConditionId: ''
|
selectedConditionId: '',
|
||||||
|
locked: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
allowEditing() {
|
||||||
|
return this.isEditing && !this.locked;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
@ -224,7 +231,13 @@ export default {
|
|||||||
this.selection.forEach((selectionItem) => {
|
this.selection.forEach((selectionItem) => {
|
||||||
const item = selectionItem[0].context.item;
|
const item = selectionItem[0].context.item;
|
||||||
const layoutItem = selectionItem[0].context.layoutItem;
|
const layoutItem = selectionItem[0].context.layoutItem;
|
||||||
|
const layoutDomainObject = selectionItem[0].context.item;
|
||||||
const isChildItem = selectionItem.length > 1;
|
const isChildItem = selectionItem.length > 1;
|
||||||
|
|
||||||
|
if (layoutDomainObject && layoutDomainObject.locked) {
|
||||||
|
this.locked = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isChildItem) {
|
if (!isChildItem) {
|
||||||
domainObject = item;
|
domainObject = item;
|
||||||
itemStyle = getApplicableStylesForItem(item);
|
itemStyle = getApplicableStylesForItem(item);
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
import TelemetryCriterion from './TelemetryCriterion';
|
import TelemetryCriterion from './TelemetryCriterion';
|
||||||
import { evaluateResults } from "../utils/evaluator";
|
import { evaluateResults } from "../utils/evaluator";
|
||||||
import { getLatestTimestamp } from '../utils/time';
|
import {getLatestTimestamp, subscribeForStaleness} from '../utils/time';
|
||||||
import { getOperatorText } from "@/plugins/condition/utils/operations";
|
import { getOperatorText } from "@/plugins/condition/utils/operations";
|
||||||
|
|
||||||
export default class AllTelemetryCriterion extends TelemetryCriterion {
|
export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||||
@ -41,6 +41,32 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
|||||||
initialize() {
|
initialize() {
|
||||||
this.telemetryObjects = { ...this.telemetryDomainObjectDefinition.telemetryObjects };
|
this.telemetryObjects = { ...this.telemetryDomainObjectDefinition.telemetryObjects };
|
||||||
this.telemetryDataCache = {};
|
this.telemetryDataCache = {};
|
||||||
|
if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) {
|
||||||
|
this.subscribeForStaleData(this.telemetryObjects || {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeForStaleData(telemetryObjects) {
|
||||||
|
|
||||||
|
if (!this.stalenessSubscription) {
|
||||||
|
this.stalenessSubscription = {};
|
||||||
|
}
|
||||||
|
Object.values(telemetryObjects).forEach((telemetryObject) => {
|
||||||
|
const id = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||||
|
if (!this.stalenessSubscription[id]) {
|
||||||
|
this.stalenessSubscription[id] = subscribeForStaleness((data) => {
|
||||||
|
this.handleStaleTelemetry(id, data);
|
||||||
|
}, this.input[0]*1000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleStaleTelemetry(id, data) {
|
||||||
|
if (this.telemetryDataCache) {
|
||||||
|
this.telemetryDataCache[id] = true;
|
||||||
|
this.result = evaluateResults(Object.values(this.telemetryDataCache), this.telemetry);
|
||||||
|
}
|
||||||
|
this.emitEvent('telemetryIsStale', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid() {
|
isValid() {
|
||||||
@ -50,6 +76,9 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
|||||||
updateTelemetryObjects(telemetryObjects) {
|
updateTelemetryObjects(telemetryObjects) {
|
||||||
this.telemetryObjects = { ...telemetryObjects };
|
this.telemetryObjects = { ...telemetryObjects };
|
||||||
this.removeTelemetryDataCache();
|
this.removeTelemetryDataCache();
|
||||||
|
if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) {
|
||||||
|
this.subscribeForStaleData(this.telemetryObjects || {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTelemetryDataCache() {
|
removeTelemetryDataCache() {
|
||||||
@ -63,6 +92,7 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
|||||||
});
|
});
|
||||||
telemetryCacheIds.forEach(id => {
|
telemetryCacheIds.forEach(id => {
|
||||||
delete (this.telemetryDataCache[id]);
|
delete (this.telemetryDataCache[id]);
|
||||||
|
delete (this.stalenessSubscription[id]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +126,14 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
|||||||
const validatedData = this.isValid() ? data : {};
|
const validatedData = this.isValid() ? data : {};
|
||||||
|
|
||||||
if (validatedData) {
|
if (validatedData) {
|
||||||
this.telemetryDataCache[validatedData.id] = this.computeResult(validatedData);
|
if (this.isStalenessCheck()) {
|
||||||
|
if (this.stalenessSubscription[validatedData.id]) {
|
||||||
|
this.stalenessSubscription[validatedData.id].update(validatedData);
|
||||||
|
}
|
||||||
|
this.telemetryDataCache[validatedData.id] = false;
|
||||||
|
} else {
|
||||||
|
this.telemetryDataCache[validatedData.id] = this.computeResult(validatedData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.values(telemetryObjects).forEach(telemetryObject => {
|
Object.values(telemetryObjects).forEach(telemetryObject => {
|
||||||
@ -162,7 +199,7 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
|||||||
|
|
||||||
getDescription() {
|
getDescription() {
|
||||||
const telemetryDescription = this.telemetry === 'all' ? 'all telemetry' : 'any telemetry';
|
const telemetryDescription = this.telemetry === 'all' ? 'all telemetry' : 'any telemetry';
|
||||||
let metadataValue = this.metadata;
|
let metadataValue = (this.metadata === 'dataReceived' ? '' : this.metadata);
|
||||||
let inputValue = this.input;
|
let inputValue = this.input;
|
||||||
if (this.metadata) {
|
if (this.metadata) {
|
||||||
const telemetryObjects = Object.values(this.telemetryObjects);
|
const telemetryObjects = Object.values(this.telemetryObjects);
|
||||||
@ -182,5 +219,9 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
|||||||
destroy() {
|
destroy() {
|
||||||
delete this.telemetryObjects;
|
delete this.telemetryObjects;
|
||||||
delete this.telemetryDataCache;
|
delete this.telemetryDataCache;
|
||||||
|
if (this.stalenessSubscription) {
|
||||||
|
Object.values(this.stalenessSubscription).forEach((subscription) => subscription.clear);
|
||||||
|
delete this.stalenessSubscription;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
import EventEmitter from 'EventEmitter';
|
import EventEmitter from 'EventEmitter';
|
||||||
import { OPERATIONS, getOperatorText } from '../utils/operations';
|
import { OPERATIONS, getOperatorText } from '../utils/operations';
|
||||||
|
import { subscribeForStaleness } from "../utils/time";
|
||||||
|
|
||||||
export default class TelemetryCriterion extends EventEmitter {
|
export default class TelemetryCriterion extends EventEmitter {
|
||||||
|
|
||||||
@ -43,6 +44,7 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
this.input = telemetryDomainObjectDefinition.input;
|
this.input = telemetryDomainObjectDefinition.input;
|
||||||
this.metadata = telemetryDomainObjectDefinition.metadata;
|
this.metadata = telemetryDomainObjectDefinition.metadata;
|
||||||
this.result = undefined;
|
this.result = undefined;
|
||||||
|
this.stalenessSubscription = undefined;
|
||||||
|
|
||||||
this.initialize();
|
this.initialize();
|
||||||
this.emitEvent('criterionUpdated', this);
|
this.emitEvent('criterionUpdated', this);
|
||||||
@ -51,14 +53,40 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
initialize() {
|
initialize() {
|
||||||
this.telemetryObjectIdAsString = this.openmct.objects.makeKeyString(this.telemetryDomainObjectDefinition.telemetry);
|
this.telemetryObjectIdAsString = this.openmct.objects.makeKeyString(this.telemetryDomainObjectDefinition.telemetry);
|
||||||
this.updateTelemetryObjects(this.telemetryDomainObjectDefinition.telemetryObjects);
|
this.updateTelemetryObjects(this.telemetryDomainObjectDefinition.telemetryObjects);
|
||||||
|
if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) {
|
||||||
|
this.subscribeForStaleData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeForStaleData() {
|
||||||
|
if (this.stalenessSubscription) {
|
||||||
|
this.stalenessSubscription.clear();
|
||||||
|
}
|
||||||
|
this.stalenessSubscription = subscribeForStaleness(this.handleStaleTelemetry.bind(this), this.input[0]*1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleStaleTelemetry(data) {
|
||||||
|
this.result = true;
|
||||||
|
this.emitEvent('telemetryIsStale', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid() {
|
isValid() {
|
||||||
return this.telemetryObject && this.metadata && this.operation;
|
return this.telemetryObject && this.metadata && this.operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isStalenessCheck() {
|
||||||
|
return this.metadata && this.metadata === 'dataReceived';
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidInput() {
|
||||||
|
return this.input instanceof Array && this.input.length;
|
||||||
|
}
|
||||||
|
|
||||||
updateTelemetryObjects(telemetryObjects) {
|
updateTelemetryObjects(telemetryObjects) {
|
||||||
this.telemetryObject = telemetryObjects[this.telemetryObjectIdAsString];
|
this.telemetryObject = telemetryObjects[this.telemetryObjectIdAsString];
|
||||||
|
if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) {
|
||||||
|
this.subscribeForStaleData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createNormalizedDatum(telemetryDatum, endpoint) {
|
createNormalizedDatum(telemetryDatum, endpoint) {
|
||||||
@ -91,7 +119,14 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
|
|
||||||
getResult(data) {
|
getResult(data) {
|
||||||
const validatedData = this.isValid() ? data : {};
|
const validatedData = this.isValid() ? data : {};
|
||||||
this.result = this.computeResult(validatedData);
|
if (this.isStalenessCheck()) {
|
||||||
|
if (this.stalenessSubscription) {
|
||||||
|
this.stalenessSubscription.update(validatedData);
|
||||||
|
}
|
||||||
|
this.result = false;
|
||||||
|
} else {
|
||||||
|
this.result = this.computeResult(validatedData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requestLAD() {
|
requestLAD() {
|
||||||
@ -136,7 +171,7 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
let comparator = this.findOperation(this.operation);
|
let comparator = this.findOperation(this.operation);
|
||||||
let params = [];
|
let params = [];
|
||||||
params.push(data[this.metadata]);
|
params.push(data[this.metadata]);
|
||||||
if (this.input instanceof Array && this.input.length) {
|
if (this.isValidInput()) {
|
||||||
this.input.forEach(input => params.push(input));
|
this.input.forEach(input => params.push(input));
|
||||||
}
|
}
|
||||||
if (typeof comparator === 'function') {
|
if (typeof comparator === 'function') {
|
||||||
@ -191,7 +226,7 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
description = `Unknown ${this.metadata} ${getOperatorText(this.operation, this.input)}`;
|
description = `Unknown ${this.metadata} ${getOperatorText(this.operation, this.input)}`;
|
||||||
} else {
|
} else {
|
||||||
const metadataObject = this.getMetaDataObject(this.telemetryObject, this.metadata);
|
const metadataObject = this.getMetaDataObject(this.telemetryObject, this.metadata);
|
||||||
const metadataValue = this.getMetadataValueFromMetaData(metadataObject) || this.metadata;
|
const metadataValue = this.getMetadataValueFromMetaData(metadataObject) || (this.metadata === 'dataReceived' ? '' : this.metadata);
|
||||||
const inputValue = this.getInputValueFromMetaData(metadataObject, this.input) || this.input;
|
const inputValue = this.getInputValueFromMetaData(metadataObject, this.input) || this.input;
|
||||||
description = `${this.telemetryObject.name} ${metadataValue} ${getOperatorText(this.operation, inputValue)}`;
|
description = `${this.telemetryObject.name} ${metadataValue} ${getOperatorText(this.operation, inputValue)}`;
|
||||||
}
|
}
|
||||||
@ -202,5 +237,8 @@ export default class TelemetryCriterion extends EventEmitter {
|
|||||||
destroy() {
|
destroy() {
|
||||||
delete this.telemetryObject;
|
delete this.telemetryObject;
|
||||||
delete this.telemetryObjectIdAsString;
|
delete this.telemetryObjectIdAsString;
|
||||||
|
if (this.stalenessSubscription) {
|
||||||
|
delete this.stalenessSubscription;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,19 +25,50 @@ import ConditionPlugin from "./plugin";
|
|||||||
import StylesView from "./components/inspector/StylesView.vue";
|
import StylesView from "./components/inspector/StylesView.vue";
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import {getApplicableStylesForItem} from "./utils/styleUtils";
|
import {getApplicableStylesForItem} from "./utils/styleUtils";
|
||||||
|
import ConditionManager from "@/plugins/condition/ConditionManager";
|
||||||
|
|
||||||
describe('the plugin', function () {
|
describe('the plugin', function () {
|
||||||
let conditionSetDefinition;
|
let conditionSetDefinition;
|
||||||
let mockConditionSetDomainObject;
|
let mockConditionSetDomainObject;
|
||||||
|
let mockListener;
|
||||||
let element;
|
let element;
|
||||||
let child;
|
let child;
|
||||||
let openmct;
|
let openmct;
|
||||||
|
let testTelemetryObject;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
resetApplicationState(openmct);
|
resetApplicationState(openmct);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach((done) => {
|
beforeEach((done) => {
|
||||||
|
testTelemetryObject = {
|
||||||
|
identifier:{ namespace: "", key: "test-object"},
|
||||||
|
type: "test-object",
|
||||||
|
name: "Test Object",
|
||||||
|
telemetry: {
|
||||||
|
valueMetadatas: [{
|
||||||
|
key: "some-key",
|
||||||
|
name: "Some attribute",
|
||||||
|
hints: {
|
||||||
|
range: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "utc",
|
||||||
|
name: "Time",
|
||||||
|
format: "utc",
|
||||||
|
hints: {
|
||||||
|
domain: 1
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "testSource",
|
||||||
|
source: "value",
|
||||||
|
name: "Test",
|
||||||
|
format: "string"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
openmct = createOpenMct();
|
openmct = createOpenMct();
|
||||||
openmct.install(new ConditionPlugin());
|
openmct.install(new ConditionPlugin());
|
||||||
|
|
||||||
@ -55,6 +86,8 @@ describe('the plugin', function () {
|
|||||||
type: 'conditionSet'
|
type: 'conditionSet'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mockListener = jasmine.createSpy('mockListener');
|
||||||
|
|
||||||
conditionSetDefinition.initialize(mockConditionSetDomainObject);
|
conditionSetDefinition.initialize(mockConditionSetDomainObject);
|
||||||
|
|
||||||
openmct.on('start', done);
|
openmct.on('start', done);
|
||||||
@ -356,4 +389,113 @@ describe('the plugin', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('the condition check for staleness', () => {
|
||||||
|
let conditionSetDomainObject;
|
||||||
|
|
||||||
|
beforeEach(()=>{
|
||||||
|
conditionSetDomainObject = {
|
||||||
|
"configuration":{
|
||||||
|
"conditionTestData":[
|
||||||
|
{
|
||||||
|
"telemetry":"",
|
||||||
|
"metadata":"",
|
||||||
|
"input":""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"conditionCollection":[
|
||||||
|
{
|
||||||
|
"id":"39584410-cbf9-499e-96dc-76f27e69885d",
|
||||||
|
"configuration":{
|
||||||
|
"name":"Unnamed Condition",
|
||||||
|
"output":"Any stale telemetry",
|
||||||
|
"trigger":"all",
|
||||||
|
"criteria":[
|
||||||
|
{
|
||||||
|
"id":"35400132-63b0-425c-ac30-8197df7d5862",
|
||||||
|
"telemetry":"any",
|
||||||
|
"operation":"isStale",
|
||||||
|
"input":[
|
||||||
|
"1"
|
||||||
|
],
|
||||||
|
"metadata":"dataReceived"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"summary":"Match if all criteria are met: Any telemetry is stale after 5 seconds"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isDefault":true,
|
||||||
|
"id":"2532d90a-e0d6-4935-b546-3123522da2de",
|
||||||
|
"configuration":{
|
||||||
|
"name":"Default",
|
||||||
|
"output":"Default",
|
||||||
|
"trigger":"all",
|
||||||
|
"criteria":[
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"summary":""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"composition":[
|
||||||
|
{
|
||||||
|
"namespace":"",
|
||||||
|
"key":"test-object"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"telemetry":{
|
||||||
|
},
|
||||||
|
"name":"Condition Set",
|
||||||
|
"type":"conditionSet",
|
||||||
|
"identifier":{
|
||||||
|
"namespace":"",
|
||||||
|
"key":"cf4456a9-296a-4e6b-b182-62ed29cd15b9"
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should evaluate as stale when telemetry is not received in the allotted time', (done) => {
|
||||||
|
|
||||||
|
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
|
||||||
|
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
||||||
|
conditionMgr.telemetryObjects = {
|
||||||
|
"test-object": testTelemetryObject
|
||||||
|
};
|
||||||
|
conditionMgr.updateConditionTelemetryObjects();
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(mockListener).toHaveBeenCalledWith({
|
||||||
|
output: 'Any stale telemetry',
|
||||||
|
id: { namespace: '', key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9' },
|
||||||
|
conditionId: '39584410-cbf9-499e-96dc-76f27e69885d',
|
||||||
|
utc: undefined
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
}, 1500);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not evaluate as stale when telemetry is received in the allotted time', (done) => {
|
||||||
|
const date = Date.now();
|
||||||
|
conditionSetDomainObject.configuration.conditionCollection[0].configuration.criteria[0].input = ["2"];
|
||||||
|
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
|
||||||
|
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
||||||
|
conditionMgr.telemetryObjects = {
|
||||||
|
"test-object": testTelemetryObject
|
||||||
|
};
|
||||||
|
conditionMgr.updateConditionTelemetryObjects();
|
||||||
|
conditionMgr.telemetryReceived(testTelemetryObject, {
|
||||||
|
utc: date
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(mockListener).toHaveBeenCalledWith({
|
||||||
|
output: 'Default',
|
||||||
|
id: { namespace: '', key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9' },
|
||||||
|
conditionId: '2532d90a-e0d6-4935-b546-3123522da2de',
|
||||||
|
utc: undefined
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
}, 1500);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -283,6 +283,18 @@ export const OPERATIONS = [
|
|||||||
getDescription: function (values) {
|
getDescription: function (values) {
|
||||||
return ' is not one of ' + values[0];
|
return ' is not one of ' + values[0];
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'isStale',
|
||||||
|
operation: function () {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
text: 'is older than',
|
||||||
|
appliesTo: ["number"],
|
||||||
|
inputCount: 1,
|
||||||
|
getDescription: function (values) {
|
||||||
|
return ` is older than ${values[0] || ''} seconds`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -50,3 +50,26 @@ function updateLatestTimeStamp(timestamp, timeSystems) {
|
|||||||
|
|
||||||
return latest;
|
return latest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const subscribeForStaleness = (callback, timeout) => {
|
||||||
|
let stalenessTimer = setTimeout(() => {
|
||||||
|
clearTimeout(stalenessTimer);
|
||||||
|
callback();
|
||||||
|
}, timeout);
|
||||||
|
return {
|
||||||
|
update: (data) => {
|
||||||
|
if (stalenessTimer) {
|
||||||
|
clearTimeout(stalenessTimer);
|
||||||
|
}
|
||||||
|
stalenessTimer = setTimeout(() => {
|
||||||
|
clearTimeout(stalenessTimer);
|
||||||
|
callback(data);
|
||||||
|
}, timeout);
|
||||||
|
},
|
||||||
|
clear: () => {
|
||||||
|
if (stalenessTimer) {
|
||||||
|
clearTimeout(stalenessTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
64
src/plugins/condition/utils/timeSpec.js
Normal file
64
src/plugins/condition/utils/timeSpec.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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 { subscribeForStaleness } from "./time";
|
||||||
|
|
||||||
|
describe('time related utils', () => {
|
||||||
|
let subscription;
|
||||||
|
let mockListener;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockListener = jasmine.createSpy('listener');
|
||||||
|
subscription = subscribeForStaleness(mockListener, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('subscribe for staleness', () => {
|
||||||
|
it('should call listeners when stale', (done) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(mockListener).toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the subscription', (done) => {
|
||||||
|
function updated() {
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(mockListener).not.toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
subscription.update();
|
||||||
|
updated();
|
||||||
|
}, 50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear the subscription', (done) => {
|
||||||
|
subscription.clear();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(mockListener).not.toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -596,7 +596,7 @@ define(['lodash'], function (_) {
|
|||||||
let selectedParent = selectionPath[1].context.item;
|
let selectedParent = selectionPath[1].context.item;
|
||||||
let layoutItem = selectionPath[0].context.layoutItem;
|
let layoutItem = selectionPath[0].context.layoutItem;
|
||||||
|
|
||||||
if (!layoutItem) {
|
if (!layoutItem || selectedParent.locked) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<layout-frame
|
<layout-frame
|
||||||
:item="item"
|
:item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
|
:is-editing="isEditing"
|
||||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
@endMove="() => $emit('endMove')"
|
@endMove="() => $emit('endMove')"
|
||||||
>
|
>
|
||||||
@ -70,7 +71,11 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
initSelect: Boolean
|
initSelect: Boolean,
|
||||||
|
isEditing: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
|
@ -24,14 +24,18 @@
|
|||||||
<div
|
<div
|
||||||
class="l-layout"
|
class="l-layout"
|
||||||
:class="{
|
:class="{
|
||||||
'is-multi-selected': selectedLayoutItems.length > 1
|
'is-multi-selected': selectedLayoutItems.length > 1,
|
||||||
|
'allow-editing': isEditing
|
||||||
}"
|
}"
|
||||||
@dragover="handleDragOver"
|
@dragover="handleDragOver"
|
||||||
@click.capture="bypassSelection"
|
@click.capture="bypassSelection"
|
||||||
@drop="handleDrop"
|
@drop="handleDrop"
|
||||||
>
|
>
|
||||||
<!-- Background grid -->
|
<!-- Background grid -->
|
||||||
<div class="l-layout__grid-holder c-grid">
|
<div
|
||||||
|
v-if="isEditing"
|
||||||
|
class="l-layout__grid-holder c-grid"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-if="gridSize[0] >= 3"
|
v-if="gridSize[0] >= 3"
|
||||||
class="c-grid__x l-grid l-grid-x"
|
class="c-grid__x l-grid l-grid-x"
|
||||||
@ -53,6 +57,7 @@
|
|||||||
:init-select="initSelectIndex === index"
|
:init-select="initSelectIndex === index"
|
||||||
:index="index"
|
:index="index"
|
||||||
:multi-select="selectedLayoutItems.length > 1"
|
:multi-select="selectedLayoutItems.length > 1"
|
||||||
|
:is-editing="isEditing"
|
||||||
@move="move"
|
@move="move"
|
||||||
@endMove="endMove"
|
@endMove="endMove"
|
||||||
@endLineResize="endLineResize"
|
@endLineResize="endLineResize"
|
||||||
@ -138,6 +143,10 @@ export default {
|
|||||||
domainObject: {
|
domainObject: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
isEditing: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -164,7 +173,7 @@ export default {
|
|||||||
let selectionPath = this.selection[0];
|
let selectionPath = this.selection[0];
|
||||||
let singleSelectedLine = this.selection.length === 1 &&
|
let singleSelectedLine = this.selection.length === 1 &&
|
||||||
selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.type === 'line-view';
|
selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.type === 'line-view';
|
||||||
return selectionPath && selectionPath.length > 1 && !singleSelectedLine;
|
return this.isEditing && selectionPath && selectionPath.length > 1 && !singleSelectedLine;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'options', 'objectPath'],
|
inject: ['openmct', 'options', 'objectPath'],
|
||||||
@ -352,6 +361,9 @@ export default {
|
|||||||
.some(childId => this.openmct.objects.areIdsEqual(childId, identifier));
|
.some(childId => this.openmct.objects.areIdsEqual(childId, identifier));
|
||||||
},
|
},
|
||||||
handleDragOver($event) {
|
handleDragOver($event) {
|
||||||
|
if (this.internalDomainObject.locked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Get the ID of the dragged object
|
// Get the ID of the dragged object
|
||||||
let draggedKeyString = $event.dataTransfer.types
|
let draggedKeyString = $event.dataTransfer.types
|
||||||
.filter(type => type.startsWith(DRAG_OBJECT_TRANSFER_PREFIX))
|
.filter(type => type.startsWith(DRAG_OBJECT_TRANSFER_PREFIX))
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<layout-frame
|
<layout-frame
|
||||||
:item="item"
|
:item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
|
:is-editing="isEditing"
|
||||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
@endMove="() => $emit('endMove')"
|
@endMove="() => $emit('endMove')"
|
||||||
>
|
>
|
||||||
@ -70,7 +71,11 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
initSelect: Boolean
|
initSelect: Boolean,
|
||||||
|
isEditing: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
class="c-frame-edit__move"
|
class="c-frame-edit__move"
|
||||||
@mousedown="startMove([1,1], [0,0], $event)"
|
@mousedown="isEditing ? startMove([1,1], [0,0], $event) : null"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -54,6 +54,10 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
validator: (arr) => arr && arr.length === 2
|
validator: (arr) => arr && arr.length === 2
|
||||||
&& arr.every(el => typeof el === 'number')
|
&& arr.every(el => typeof el === 'number')
|
||||||
|
},
|
||||||
|
isEditing: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
:item="item"
|
:item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
:title="domainObject && domainObject.name"
|
:title="domainObject && domainObject.name"
|
||||||
|
:is-editing="isEditing"
|
||||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
@endMove="() => $emit('endMove')"
|
@endMove="() => $emit('endMove')"
|
||||||
>
|
>
|
||||||
@ -95,6 +96,10 @@ export default {
|
|||||||
index: {
|
index: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
isEditing: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<layout-frame
|
<layout-frame
|
||||||
:item="item"
|
:item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
|
:is-editing="isEditing"
|
||||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
@endMove="() => $emit('endMove')"
|
@endMove="() => $emit('endMove')"
|
||||||
>
|
>
|
||||||
@ -105,6 +106,10 @@ export default {
|
|||||||
index: {
|
index: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
isEditing: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<layout-frame
|
<layout-frame
|
||||||
:item="item"
|
:item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
|
:is-editing="isEditing"
|
||||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
@endMove="() => $emit('endMove')"
|
@endMove="() => $emit('endMove')"
|
||||||
>
|
>
|
||||||
@ -75,7 +76,11 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
initSelect: Boolean
|
initSelect: Boolean,
|
||||||
|
isEditing: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
|
@ -45,8 +45,7 @@
|
|||||||
&[s-selected],
|
&[s-selected],
|
||||||
&[s-selected-parent] {
|
&[s-selected-parent] {
|
||||||
// Display grid and allow edit marquee to display in nested layouts when editing
|
// Display grid and allow edit marquee to display in nested layouts when editing
|
||||||
> * > * > .l-layout {
|
> * > * > .l-layout + .allow-editing {
|
||||||
background: $editUIGridColorBg;
|
|
||||||
box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
|
box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
|
||||||
|
|
||||||
> [class*='grid-holder'] {
|
> [class*='grid-holder'] {
|
||||||
|
@ -54,10 +54,11 @@ export default function DisplayLayoutPlugin(options) {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
domainObject: domainObject
|
domainObject: domainObject,
|
||||||
|
isEditing: openmct.editor.isEditing()
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
template: '<layout ref="displayLayout" :domain-object="domainObject"></layout>'
|
template: '<layout ref="displayLayout" :domain-object="domainObject" :is-editing="isEditing"></layout>'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getSelectionContext() {
|
getSelectionContext() {
|
||||||
@ -73,6 +74,9 @@ export default function DisplayLayoutPlugin(options) {
|
|||||||
mergeMultipleOverlayPlots: component && component.$refs.displayLayout.mergeMultipleOverlayPlots
|
mergeMultipleOverlayPlots: component && component.$refs.displayLayout.mergeMultipleOverlayPlots
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
onEditModeChange: function (isEditing) {
|
||||||
|
component.isEditing = isEditing;
|
||||||
|
},
|
||||||
destroy() {
|
destroy() {
|
||||||
component.$destroy();
|
component.$destroy();
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
:index="i"
|
:index="i"
|
||||||
:container-index="index"
|
:container-index="index"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
|
:object-path="objectPath"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<drop-hint
|
<drop-hint
|
||||||
@ -105,6 +106,14 @@ export default {
|
|||||||
isEditing: {
|
isEditing: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
locked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
objectPath: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -130,6 +139,10 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
allowDrop(event, index) {
|
allowDrop(event, index) {
|
||||||
|
if (this.locked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (event.dataTransfer.types.includes('openmct/domain-object-path')) {
|
if (event.dataTransfer.types.includes('openmct/domain-object-path')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,8 @@
|
|||||||
:container="container"
|
:container="container"
|
||||||
:rows-layout="rowsLayout"
|
:rows-layout="rowsLayout"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
|
:locked="domainObject.locked"
|
||||||
|
:object-path="objectPath"
|
||||||
@move-frame="moveFrame"
|
@move-frame="moveFrame"
|
||||||
@new-frame="setFrameLocation"
|
@new-frame="setFrameLocation"
|
||||||
@persist="persist"
|
@persist="persist"
|
||||||
@ -136,7 +138,7 @@ function sizeToFill(items) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'layoutObject'],
|
inject: ['openmct', 'objectPath', 'layoutObject'],
|
||||||
components: {
|
components: {
|
||||||
ContainerComponent,
|
ContainerComponent,
|
||||||
ResizeHandle,
|
ResizeHandle,
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
v-if="domainObject"
|
v-if="domainObject"
|
||||||
ref="objectFrame"
|
ref="objectFrame"
|
||||||
:domain-object="domainObject"
|
:domain-object="domainObject"
|
||||||
:object-path="objectPath"
|
:object-path="currentObjectPath"
|
||||||
:has-frame="hasFrame"
|
:has-frame="hasFrame"
|
||||||
:show-edit-view="false"
|
:show-edit-view="false"
|
||||||
/>
|
/>
|
||||||
@ -77,12 +77,16 @@ export default {
|
|||||||
isEditing: {
|
isEditing: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
objectPath: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
domainObject: undefined,
|
domainObject: undefined,
|
||||||
objectPath: undefined
|
currentObjectPath: undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -107,7 +111,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
setDomainObject(object) {
|
setDomainObject(object) {
|
||||||
this.domainObject = object;
|
this.domainObject = object;
|
||||||
this.objectPath = [object];
|
this.currentObjectPath = [object].concat(this.objectPath);
|
||||||
this.setSelection();
|
this.setSelection();
|
||||||
},
|
},
|
||||||
setSelection() {
|
setSelection() {
|
||||||
|
@ -38,7 +38,7 @@ define([
|
|||||||
canEdit: function (domainObject) {
|
canEdit: function (domainObject) {
|
||||||
return domainObject.type === 'flexible-layout';
|
return domainObject.type === 'flexible-layout';
|
||||||
},
|
},
|
||||||
view: function (domainObject) {
|
view: function (domainObject, objectPath) {
|
||||||
let component;
|
let component;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -46,6 +46,7 @@ define([
|
|||||||
component = new Vue({
|
component = new Vue({
|
||||||
provide: {
|
provide: {
|
||||||
openmct,
|
openmct,
|
||||||
|
objectPath,
|
||||||
layoutObject: domainObject
|
layoutObject: domainObject
|
||||||
},
|
},
|
||||||
el: element,
|
el: element,
|
||||||
|
@ -70,6 +70,10 @@ function ToolbarProvider(openmct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (primary.context.type === 'frame') {
|
if (primary.context.type === 'frame') {
|
||||||
|
if (secondary.context.item.locked) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
let frameId = primary.context.frameId;
|
let frameId = primary.context.frameId;
|
||||||
let layoutObject = tertiary.context.item;
|
let layoutObject = tertiary.context.item;
|
||||||
let containers = layoutObject
|
let containers = layoutObject
|
||||||
@ -143,6 +147,9 @@ function ToolbarProvider(openmct) {
|
|||||||
toggleContainer.domainObject = secondary.context.item;
|
toggleContainer.domainObject = secondary.context.item;
|
||||||
|
|
||||||
} else if (primary.context.type === 'container') {
|
} else if (primary.context.type === 'container') {
|
||||||
|
if (primary.context.item.locked) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
deleteContainer = {
|
deleteContainer = {
|
||||||
control: "button",
|
control: "button",
|
||||||
@ -187,6 +194,9 @@ function ToolbarProvider(openmct) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
} else if (primary.context.type === 'flexible-layout') {
|
} else if (primary.context.type === 'flexible-layout') {
|
||||||
|
if (primary.context.item.locked) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
addContainer = {
|
addContainer = {
|
||||||
control: "button",
|
control: "button",
|
||||||
|
@ -41,7 +41,7 @@ define([], function () {
|
|||||||
this.timeFormat = 'local-format';
|
this.timeFormat = 'local-format';
|
||||||
this.durationFormat = 'duration';
|
this.durationFormat = 'duration';
|
||||||
|
|
||||||
this.isUTCBased = false;
|
this.isUTCBased = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LocalTimeSystem;
|
return LocalTimeSystem;
|
||||||
|
@ -24,14 +24,14 @@ import uuid from 'uuid';
|
|||||||
|
|
||||||
export default class NewFolderAction {
|
export default class NewFolderAction {
|
||||||
constructor(openmct) {
|
constructor(openmct) {
|
||||||
this.name = 'New Folder';
|
this.name = 'Add New Folder';
|
||||||
this.key = 'newFolder';
|
this.key = 'newFolder';
|
||||||
this.description = 'Create a new folder';
|
this.description = 'Create a new folder';
|
||||||
this.cssClass = 'icon-folder';
|
this.cssClass = 'icon-folder-new';
|
||||||
|
|
||||||
this._openmct = openmct;
|
this._openmct = openmct;
|
||||||
this._dialogForm = {
|
this._dialogForm = {
|
||||||
name: "New Folder Name",
|
name: "Add New Folder",
|
||||||
sections: [
|
sections: [
|
||||||
{
|
{
|
||||||
rows: [
|
rows: [
|
||||||
@ -39,7 +39,9 @@ export default class NewFolderAction {
|
|||||||
key: "name",
|
key: "name",
|
||||||
control: "textfield",
|
control: "textfield",
|
||||||
name: "Folder Name",
|
name: "Folder Name",
|
||||||
required: false
|
pattern: "\\S+",
|
||||||
|
required: true,
|
||||||
|
cssClass: "l-input-lg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -53,7 +55,7 @@ export default class NewFolderAction {
|
|||||||
dialogService = this._openmct.$injector.get('dialogService'),
|
dialogService = this._openmct.$injector.get('dialogService'),
|
||||||
folderType = this._openmct.types.get('folder');
|
folderType = this._openmct.types.get('folder');
|
||||||
|
|
||||||
dialogService.getUserInput(this._dialogForm, {}).then((userInput) => {
|
dialogService.getUserInput(this._dialogForm, {name: 'Unnamed Folder'}).then((userInput) => {
|
||||||
let name = userInput.name,
|
let name = userInput.name,
|
||||||
identifier = {
|
identifier = {
|
||||||
key: uuid(),
|
key: uuid(),
|
||||||
|
@ -60,6 +60,7 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.addPopupMenuItems();
|
this.addPopupMenuItems();
|
||||||
|
this.exportImageService = this.openmct.$injector.get('exportImageService');
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addPopupMenuItems() {
|
addPopupMenuItems() {
|
||||||
@ -205,7 +206,7 @@ export default {
|
|||||||
},
|
},
|
||||||
openSnapshot() {
|
openSnapshot() {
|
||||||
const self = this;
|
const self = this;
|
||||||
const snapshot = new Vue({
|
this.snapshot = new Vue({
|
||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
embed: self.embed
|
embed: self.embed
|
||||||
@ -213,14 +214,15 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatTime: self.formatTime,
|
formatTime: self.formatTime,
|
||||||
annotateSnapshot: self.annotateSnapshot
|
annotateSnapshot: self.annotateSnapshot,
|
||||||
|
exportImage: self.exportImage
|
||||||
},
|
},
|
||||||
template: SnapshotTemplate
|
template: SnapshotTemplate
|
||||||
});
|
});
|
||||||
|
|
||||||
const snapshotOverlay = this.openmct.overlays.overlay({
|
const snapshotOverlay = this.openmct.overlays.overlay({
|
||||||
element: snapshot.$mount().$el,
|
element: this.snapshot.$mount().$el,
|
||||||
onDestroy: () => { snapshot.$destroy(true) },
|
onDestroy: () => { this.snapshot.$destroy(true) },
|
||||||
size: 'large',
|
size: 'large',
|
||||||
dismissable: true,
|
dismissable: true,
|
||||||
buttons: [
|
buttons: [
|
||||||
@ -234,6 +236,15 @@ export default {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
exportImage(type) {
|
||||||
|
let element = this.snapshot.$refs['snapshot-image'];
|
||||||
|
|
||||||
|
if (type === 'png') {
|
||||||
|
this.exportImageService.exportPNG(element, this.embed.name);
|
||||||
|
} else {
|
||||||
|
this.exportImageService.exportJPG(element, this.embed.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
previewEmbed() {
|
previewEmbed() {
|
||||||
const self = this;
|
const self = this;
|
||||||
const previewAction = new PreviewAction(self.openmct);
|
const previewAction = new PreviewAction(self.openmct);
|
||||||
|
@ -15,14 +15,32 @@
|
|||||||
<div class="l-browse-bar__snapshot-datetime">
|
<div class="l-browse-bar__snapshot-datetime">
|
||||||
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
||||||
</div>
|
</div>
|
||||||
|
<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="exportImage('png')"
|
||||||
|
>
|
||||||
|
<span class="c-button__label">PNG</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="c-button"
|
||||||
|
title="Export This View's Data as JPG"
|
||||||
|
@click="exportImage('jpg')"
|
||||||
|
>
|
||||||
|
<span class="c-button__label">JPG</span>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
<a class="l-browse-bar__annotate-button c-button icon-pencil" title="Annotate" @click="annotateSnapshot">
|
<a class="l-browse-bar__annotate-button c-button icon-pencil" title="Annotate" @click="annotateSnapshot">
|
||||||
<span class="title-label">Annotate</span>
|
<span class="title-label">Annotate</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="c-notebook-snapshot__image"
|
<div
|
||||||
:style="{ backgroundImage: 'url(' + embed.snapshot.src + ')' }"
|
ref="snapshot-image"
|
||||||
|
class="c-notebook-snapshot__image"
|
||||||
|
:style="{ backgroundImage: 'url(' + embed.snapshot.src + ')' }"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,12 +19,12 @@
|
|||||||
this source code distribution or the Licensing information page available
|
this source code distribution or the Licensing information page available
|
||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<div ng-if="domainObject.getCapability('editor').inEditContext()">
|
<div ng-if="!domainObject.model.locked && domainObject.getCapability('editor').inEditContext()">
|
||||||
<mct-representation key="'plot-options-edit'"
|
<mct-representation key="'plot-options-edit'"
|
||||||
mct-object="domainObject">
|
mct-object="domainObject">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div>
|
</div>
|
||||||
<div ng-if="!domainObject.getCapability('editor').inEditContext()">
|
<div ng-if="domainObject.model.locked || !domainObject.getCapability('editor').inEditContext()">
|
||||||
<mct-representation key="'plot-options-browse'"
|
<mct-representation key="'plot-options-browse'"
|
||||||
mct-object="domainObject">
|
mct-object="domainObject">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
|
@ -101,6 +101,12 @@ export default class RemoveAction {
|
|||||||
appliesTo(objectPath) {
|
appliesTo(objectPath) {
|
||||||
let parent = objectPath[1];
|
let parent = objectPath[1];
|
||||||
let parentType = parent && this.openmct.types.get(parent.type);
|
let parentType = parent && this.openmct.types.get(parent.type);
|
||||||
|
let child = objectPath[0];
|
||||||
|
let locked = child.locked ? child.locked : parent && parent.locked;
|
||||||
|
|
||||||
|
if (locked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return parentType &&
|
return parentType &&
|
||||||
parentType.definition.creatable &&
|
parentType.definition.creatable &&
|
||||||
|
@ -22,7 +22,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="c-conductor"
|
class="c-conductor"
|
||||||
:class="[isFixed ? 'is-fixed-mode' : 'is-realtime-mode']"
|
:class="[
|
||||||
|
{ 'is-zooming': isZooming },
|
||||||
|
{ 'is-panning': isPanning },
|
||||||
|
{ 'alt-pressed': altPressed },
|
||||||
|
isFixed ? 'is-fixed-mode' : 'is-realtime-mode'
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<form
|
<form
|
||||||
ref="conductorForm"
|
ref="conductorForm"
|
||||||
@ -52,7 +57,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
@change="validateAllBounds(); submitForm()"
|
@change="validateAllBounds('startDate'); submitForm()"
|
||||||
>
|
>
|
||||||
<date-picker
|
<date-picker
|
||||||
v-if="isFixed && isUTCBased"
|
v-if="isFixed && isUTCBased"
|
||||||
@ -92,7 +97,7 @@
|
|||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
:disabled="!isFixed"
|
:disabled="!isFixed"
|
||||||
@change="validateAllBounds(); submitForm()"
|
@change="validateAllBounds('endDate'); submitForm()"
|
||||||
>
|
>
|
||||||
<date-picker
|
<date-picker
|
||||||
v-if="isFixed && isUTCBased"
|
v-if="isFixed && isUTCBased"
|
||||||
@ -122,14 +127,25 @@
|
|||||||
|
|
||||||
<conductor-axis
|
<conductor-axis
|
||||||
class="c-conductor__ticks"
|
class="c-conductor__ticks"
|
||||||
:bounds="rawBounds"
|
:view-bounds="viewBounds"
|
||||||
@panAxis="setViewFromBounds"
|
:is-fixed="isFixed"
|
||||||
|
:alt-pressed="altPressed"
|
||||||
|
@endPan="endPan"
|
||||||
|
@endZoom="endZoom"
|
||||||
|
@panAxis="pan"
|
||||||
|
@zoomAxis="zoom"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="c-conductor__controls">
|
<div class="c-conductor__controls">
|
||||||
<!-- Mode, time system menu buttons and duration slider -->
|
|
||||||
<ConductorMode class="c-conductor__mode-select" />
|
<ConductorMode class="c-conductor__mode-select" />
|
||||||
<ConductorTimeSystem class="c-conductor__time-system-select" />
|
<ConductorTimeSystem class="c-conductor__time-system-select" />
|
||||||
|
<ConductorHistory
|
||||||
|
v-if="isFixed"
|
||||||
|
class="c-conductor__history-select"
|
||||||
|
:bounds="openmct.time.bounds()"
|
||||||
|
:time-system="timeSystem"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
type="submit"
|
type="submit"
|
||||||
@ -145,6 +161,7 @@ import ConductorTimeSystem from './ConductorTimeSystem.vue';
|
|||||||
import DatePicker from './DatePicker.vue';
|
import DatePicker from './DatePicker.vue';
|
||||||
import ConductorAxis from './ConductorAxis.vue';
|
import ConductorAxis from './ConductorAxis.vue';
|
||||||
import ConductorModeIcon from './ConductorModeIcon.vue';
|
import ConductorModeIcon from './ConductorModeIcon.vue';
|
||||||
|
import ConductorHistory from './ConductorHistory.vue'
|
||||||
|
|
||||||
const DEFAULT_DURATION_FORMATTER = 'duration';
|
const DEFAULT_DURATION_FORMATTER = 'duration';
|
||||||
|
|
||||||
@ -155,7 +172,8 @@ export default {
|
|||||||
ConductorTimeSystem,
|
ConductorTimeSystem,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
ConductorAxis,
|
ConductorAxis,
|
||||||
ConductorModeIcon
|
ConductorModeIcon,
|
||||||
|
ConductorHistory
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
let bounds = this.openmct.time.bounds();
|
let bounds = this.openmct.time.bounds();
|
||||||
@ -165,6 +183,7 @@ export default {
|
|||||||
let durationFormatter = this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
let durationFormatter = this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
timeSystem: timeSystem,
|
||||||
timeFormatter: timeFormatter,
|
timeFormatter: timeFormatter,
|
||||||
durationFormatter: durationFormatter,
|
durationFormatter: durationFormatter,
|
||||||
offsets: {
|
offsets: {
|
||||||
@ -175,29 +194,68 @@ export default {
|
|||||||
start: timeFormatter.format(bounds.start),
|
start: timeFormatter.format(bounds.start),
|
||||||
end: timeFormatter.format(bounds.end)
|
end: timeFormatter.format(bounds.end)
|
||||||
},
|
},
|
||||||
rawBounds: {
|
viewBounds: {
|
||||||
start: bounds.start,
|
start: bounds.start,
|
||||||
end: bounds.end
|
end: bounds.end
|
||||||
},
|
},
|
||||||
isFixed: this.openmct.time.clock() === undefined,
|
isFixed: this.openmct.time.clock() === undefined,
|
||||||
isUTCBased: timeSystem.isUTCBased,
|
isUTCBased: timeSystem.isUTCBased,
|
||||||
showDatePicker: false
|
showDatePicker: false,
|
||||||
|
altPressed: false,
|
||||||
|
isPanning: false,
|
||||||
|
isZooming: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
document.addEventListener('keydown', this.handleKeyDown);
|
||||||
|
document.addEventListener('keyup', this.handleKeyUp);
|
||||||
this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem())));
|
this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem())));
|
||||||
|
|
||||||
this.openmct.time.on('bounds', this.setViewFromBounds);
|
this.openmct.time.on('bounds', this.setViewFromBounds);
|
||||||
this.openmct.time.on('timeSystem', this.setTimeSystem);
|
this.openmct.time.on('timeSystem', this.setTimeSystem);
|
||||||
this.openmct.time.on('clock', this.setViewFromClock);
|
this.openmct.time.on('clock', this.setViewFromClock);
|
||||||
this.openmct.time.on('clockOffsets', this.setViewFromOffsets)
|
this.openmct.time.on('clockOffsets', this.setViewFromOffsets)
|
||||||
},
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
document.removeEventListener('keydown', this.handleKeyDown);
|
||||||
|
document.removeEventListener('keyup', this.handleKeyUp);
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleKeyDown(event) {
|
||||||
|
if (event.key === 'Alt') {
|
||||||
|
this.altPressed = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleKeyUp(event) {
|
||||||
|
if (event.key === 'Alt') {
|
||||||
|
this.altPressed = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pan(bounds) {
|
||||||
|
this.isPanning = true;
|
||||||
|
this.setViewFromBounds(bounds);
|
||||||
|
},
|
||||||
|
endPan(bounds) {
|
||||||
|
this.isPanning = false;
|
||||||
|
if (bounds) {
|
||||||
|
this.openmct.time.bounds(bounds);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
zoom(bounds) {
|
||||||
|
this.isZooming = true;
|
||||||
|
this.formattedBounds.start = this.timeFormatter.format(bounds.start);
|
||||||
|
this.formattedBounds.end = this.timeFormatter.format(bounds.end);
|
||||||
|
},
|
||||||
|
endZoom(bounds) {
|
||||||
|
const _bounds = bounds ? bounds : this.openmct.time.bounds();
|
||||||
|
this.isZooming = false;
|
||||||
|
|
||||||
|
this.openmct.time.bounds(_bounds);
|
||||||
|
},
|
||||||
setTimeSystem(timeSystem) {
|
setTimeSystem(timeSystem) {
|
||||||
|
this.timeSystem = timeSystem
|
||||||
this.timeFormatter = this.getFormatter(timeSystem.timeFormat);
|
this.timeFormatter = this.getFormatter(timeSystem.timeFormat);
|
||||||
this.durationFormatter = this.getFormatter(
|
this.durationFormatter = this.getFormatter(
|
||||||
timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
||||||
|
|
||||||
this.isUTCBased = timeSystem.isUTCBased;
|
this.isUTCBased = timeSystem.isUTCBased;
|
||||||
},
|
},
|
||||||
setOffsetsFromView($event) {
|
setOffsetsFromView($event) {
|
||||||
@ -237,8 +295,8 @@ export default {
|
|||||||
setViewFromBounds(bounds) {
|
setViewFromBounds(bounds) {
|
||||||
this.formattedBounds.start = this.timeFormatter.format(bounds.start);
|
this.formattedBounds.start = this.timeFormatter.format(bounds.start);
|
||||||
this.formattedBounds.end = this.timeFormatter.format(bounds.end);
|
this.formattedBounds.end = this.timeFormatter.format(bounds.end);
|
||||||
this.rawBounds.start = bounds.start;
|
this.viewBounds.start = bounds.start;
|
||||||
this.rawBounds.end = bounds.end;
|
this.viewBounds.end = bounds.end;
|
||||||
},
|
},
|
||||||
setViewFromOffsets(offsets) {
|
setViewFromOffsets(offsets) {
|
||||||
this.offsets.start = this.durationFormatter.format(Math.abs(offsets.start));
|
this.offsets.start = this.durationFormatter.format(Math.abs(offsets.start));
|
||||||
@ -251,6 +309,15 @@ export default {
|
|||||||
this.setOffsetsFromView();
|
this.setOffsetsFromView();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getBoundsLimit() {
|
||||||
|
const configuration = this.configuration.menuOptions
|
||||||
|
.filter(option => option.timeSystem === this.timeSystem.key)
|
||||||
|
.find(option => option.limit);
|
||||||
|
|
||||||
|
const limit = configuration ? configuration.limit : undefined;
|
||||||
|
|
||||||
|
return limit;
|
||||||
|
},
|
||||||
clearAllValidation() {
|
clearAllValidation() {
|
||||||
if (this.isFixed) {
|
if (this.isFixed) {
|
||||||
[this.$refs.startDate, this.$refs.endDate].forEach(this.clearValidationForInput);
|
[this.$refs.startDate, this.$refs.endDate].forEach(this.clearValidationForInput);
|
||||||
@ -262,36 +329,52 @@ export default {
|
|||||||
input.setCustomValidity('');
|
input.setCustomValidity('');
|
||||||
input.title = '';
|
input.title = '';
|
||||||
},
|
},
|
||||||
validateAllBounds() {
|
validateAllBounds(ref) {
|
||||||
return [this.$refs.startDate, this.$refs.endDate].every((input) => {
|
if (!this.areBoundsFormatsValid()) {
|
||||||
let validationResult = true;
|
return false;
|
||||||
let formattedDate;
|
}
|
||||||
|
|
||||||
if (input === this.$refs.startDate) {
|
let validationResult = true;
|
||||||
formattedDate = this.formattedBounds.start;
|
const currentInput = this.$refs[ref];
|
||||||
|
|
||||||
|
return [this.$refs.startDate, this.$refs.endDate].every((input) => {
|
||||||
|
let boundsValues = {
|
||||||
|
start: this.timeFormatter.parse(this.formattedBounds.start),
|
||||||
|
end: this.timeFormatter.parse(this.formattedBounds.end)
|
||||||
|
};
|
||||||
|
const limit = this.getBoundsLimit();
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.timeSystem.isUTCBased
|
||||||
|
&& limit
|
||||||
|
&& boundsValues.end - boundsValues.start > limit
|
||||||
|
) {
|
||||||
|
if (input === currentInput) {
|
||||||
|
validationResult = "Start and end difference exceeds allowable limit";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
formattedDate = this.formattedBounds.end;
|
if (input === currentInput) {
|
||||||
|
validationResult = this.openmct.time.validateBounds(boundsValues);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.handleValidationResults(input, validationResult);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
areBoundsFormatsValid() {
|
||||||
|
let validationResult = true;
|
||||||
|
|
||||||
|
return [this.$refs.startDate, this.$refs.endDate].every((input) => {
|
||||||
|
const formattedDate = input === this.$refs.startDate
|
||||||
|
? this.formattedBounds.start
|
||||||
|
: this.formattedBounds.end
|
||||||
|
;
|
||||||
|
|
||||||
if (!this.timeFormatter.validate(formattedDate)) {
|
if (!this.timeFormatter.validate(formattedDate)) {
|
||||||
validationResult = 'Invalid date';
|
validationResult = 'Invalid date';
|
||||||
} else {
|
|
||||||
let boundsValues = {
|
|
||||||
start: this.timeFormatter.parse(this.formattedBounds.start),
|
|
||||||
end: this.timeFormatter.parse(this.formattedBounds.end)
|
|
||||||
};
|
|
||||||
validationResult = this.openmct.time.validateBounds(boundsValues);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validationResult !== true) {
|
return this.handleValidationResults(input, validationResult);
|
||||||
input.setCustomValidity(validationResult);
|
|
||||||
input.title = validationResult;
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
input.setCustomValidity('');
|
|
||||||
input.title = '';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
validateAllOffsets(event) {
|
validateAllOffsets(event) {
|
||||||
@ -315,17 +398,20 @@ export default {
|
|||||||
validationResult = this.openmct.time.validateOffsets(offsetValues);
|
validationResult = this.openmct.time.validateOffsets(offsetValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validationResult !== true) {
|
return this.handleValidationResults(input, validationResult);
|
||||||
input.setCustomValidity(validationResult);
|
|
||||||
input.title = validationResult;
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
input.setCustomValidity('');
|
|
||||||
input.title = '';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleValidationResults(input, validationResult) {
|
||||||
|
if (validationResult !== true) {
|
||||||
|
input.setCustomValidity(validationResult);
|
||||||
|
input.title = validationResult;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
input.setCustomValidity('');
|
||||||
|
input.title = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
submitForm() {
|
submitForm() {
|
||||||
// Allow Vue model to catch up to user input.
|
// Allow Vue model to catch up to user input.
|
||||||
// Submitting form will cause validation messages to display (but only if triggered by button click)
|
// Submitting form will cause validation messages to display (but only if triggered by button click)
|
||||||
@ -338,12 +424,12 @@ export default {
|
|||||||
},
|
},
|
||||||
startDateSelected(date) {
|
startDateSelected(date) {
|
||||||
this.formattedBounds.start = this.timeFormatter.format(date);
|
this.formattedBounds.start = this.timeFormatter.format(date);
|
||||||
this.validateAllBounds();
|
this.validateAllBounds('startDate');
|
||||||
this.submitForm();
|
this.submitForm();
|
||||||
},
|
},
|
||||||
endDateSelected(date) {
|
endDateSelected(date) {
|
||||||
this.formattedBounds.end = this.timeFormatter.format(date);
|
this.formattedBounds.end = this.timeFormatter.format(date);
|
||||||
this.validateAllBounds();
|
this.validateAllBounds('endDate');
|
||||||
this.submitForm();
|
this.submitForm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,12 @@
|
|||||||
ref="axisHolder"
|
ref="axisHolder"
|
||||||
class="c-conductor-axis"
|
class="c-conductor-axis"
|
||||||
@mousedown="dragStart($event)"
|
@mousedown="dragStart($event)"
|
||||||
></div>
|
>
|
||||||
|
<div
|
||||||
|
class="c-conductor-axis__zoom-indicator"
|
||||||
|
:style="zoomStyle"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -43,52 +48,81 @@ const PIXELS_PER_TICK_WIDE = 200;
|
|||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
props: {
|
props: {
|
||||||
bounds: {
|
viewBounds: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
isFixed: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
altPressed: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
inPanMode: false,
|
||||||
|
dragStartX: undefined,
|
||||||
|
dragX: undefined,
|
||||||
|
zoomStyle: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
inZoomMode() {
|
||||||
|
return !this.inPanMode;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
bounds: {
|
viewBounds: {
|
||||||
handler(bounds) {
|
handler() {
|
||||||
this.setScale();
|
this.setScale();
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
let axisHolder = this.$refs.axisHolder;
|
let vis = d3Selection.select(this.$refs.axisHolder).append("svg:svg");
|
||||||
let height = axisHolder.offsetHeight;
|
|
||||||
let vis = d3Selection.select(axisHolder)
|
|
||||||
.append("svg:svg")
|
|
||||||
.attr("width", "100%")
|
|
||||||
.attr("height", height);
|
|
||||||
|
|
||||||
this.width = this.$refs.axisHolder.clientWidth;
|
|
||||||
this.xAxis = d3Axis.axisTop();
|
this.xAxis = d3Axis.axisTop();
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
|
|
||||||
// draw x axis with labels. CSS is used to position them.
|
// draw x axis with labels. CSS is used to position them.
|
||||||
this.axisElement = vis.append("g");
|
this.axisElement = vis.append("g")
|
||||||
|
.attr("class", "axis");
|
||||||
|
|
||||||
this.setViewFromTimeSystem(this.openmct.time.timeSystem());
|
this.setViewFromTimeSystem(this.openmct.time.timeSystem());
|
||||||
|
this.setAxisDimensions();
|
||||||
this.setScale();
|
this.setScale();
|
||||||
|
|
||||||
//Respond to changes in conductor
|
//Respond to changes in conductor
|
||||||
this.openmct.time.on("timeSystem", this.setViewFromTimeSystem);
|
this.openmct.time.on("timeSystem", this.setViewFromTimeSystem);
|
||||||
setInterval(this.resize, RESIZE_POLL_INTERVAL);
|
setInterval(this.resize, RESIZE_POLL_INTERVAL);
|
||||||
},
|
},
|
||||||
destroyed() {
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
|
setAxisDimensions() {
|
||||||
|
const axisHolder = this.$refs.axisHolder;
|
||||||
|
const rect = axisHolder.getBoundingClientRect();
|
||||||
|
|
||||||
|
this.left = Math.round(rect.left);
|
||||||
|
this.width = axisHolder.clientWidth;
|
||||||
|
},
|
||||||
setScale() {
|
setScale() {
|
||||||
|
if (!this.width) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let timeSystem = this.openmct.time.timeSystem();
|
let timeSystem = this.openmct.time.timeSystem();
|
||||||
let bounds = this.bounds;
|
|
||||||
|
|
||||||
if (timeSystem.isUTCBased) {
|
if (timeSystem.isUTCBased) {
|
||||||
this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]);
|
this.xScale.domain(
|
||||||
|
[new Date(this.viewBounds.start), new Date(this.viewBounds.end)]
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.xScale.domain([bounds.start, bounds.end]);
|
this.xScale.domain(
|
||||||
|
[this.viewBounds.start, this.viewBounds.end]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.xAxis.scale(this.xScale);
|
this.xAxis.scale(this.xScale);
|
||||||
@ -102,7 +136,7 @@ export default {
|
|||||||
this.xAxis.ticks(this.width / PIXELS_PER_TICK);
|
this.xAxis.ticks(this.width / PIXELS_PER_TICK);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.msPerPixel = (bounds.end - bounds.start) / this.width;
|
this.msPerPixel = (this.viewBounds.end - this.viewBounds.start) / this.width;
|
||||||
},
|
},
|
||||||
setViewFromTimeSystem(timeSystem) {
|
setViewFromTimeSystem(timeSystem) {
|
||||||
//The D3 scale used depends on the type of time system as d3
|
//The D3 scale used depends on the type of time system as d3
|
||||||
@ -120,9 +154,8 @@ export default {
|
|||||||
},
|
},
|
||||||
getActiveFormatter() {
|
getActiveFormatter() {
|
||||||
let timeSystem = this.openmct.time.timeSystem();
|
let timeSystem = this.openmct.time.timeSystem();
|
||||||
let isFixed = this.openmct.time.clock() === undefined;
|
|
||||||
|
|
||||||
if (isFixed) {
|
if (this.isFixed) {
|
||||||
return this.getFormatter(timeSystem.timeFormat);
|
return this.getFormatter(timeSystem.timeFormat);
|
||||||
} else {
|
} else {
|
||||||
return this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
return this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
||||||
@ -134,45 +167,131 @@ export default {
|
|||||||
}).formatter;
|
}).formatter;
|
||||||
},
|
},
|
||||||
dragStart($event) {
|
dragStart($event) {
|
||||||
let isFixed = this.openmct.time.clock() === undefined;
|
if (this.isFixed) {
|
||||||
if (isFixed) {
|
|
||||||
this.dragStartX = $event.clientX;
|
this.dragStartX = $event.clientX;
|
||||||
|
|
||||||
|
if (this.altPressed) {
|
||||||
|
this.inPanMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('mousemove', this.drag);
|
document.addEventListener('mousemove', this.drag);
|
||||||
document.addEventListener('mouseup', this.dragEnd, {
|
document.addEventListener('mouseup', this.dragEnd, {
|
||||||
once: true
|
once: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.inZoomMode) {
|
||||||
|
this.startZoom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
drag($event) {
|
drag($event) {
|
||||||
if (!this.dragging) {
|
if (!this.dragging) {
|
||||||
this.dragging = true;
|
this.dragging = true;
|
||||||
requestAnimationFrame(()=>{
|
|
||||||
let deltaX = $event.clientX - this.dragStartX;
|
requestAnimationFrame(() => {
|
||||||
let percX = deltaX / this.width;
|
this.dragX = $event.clientX;
|
||||||
let bounds = this.openmct.time.bounds();
|
this.inPanMode ? this.pan() : this.zoom();
|
||||||
let deltaTime = bounds.end - bounds.start;
|
|
||||||
let newStart = bounds.start - percX * deltaTime;
|
|
||||||
this.$emit('panAxis',{
|
|
||||||
start: newStart,
|
|
||||||
end: newStart + deltaTime
|
|
||||||
});
|
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
})
|
});
|
||||||
} else {
|
|
||||||
console.log('Rejected drag due to RAF cap');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dragEnd() {
|
dragEnd() {
|
||||||
|
this.inPanMode ? this.endPan() : this.endZoom();
|
||||||
|
|
||||||
document.removeEventListener('mousemove', this.drag);
|
document.removeEventListener('mousemove', this.drag);
|
||||||
this.openmct.time.bounds({
|
this.dragStartX = undefined;
|
||||||
start: this.bounds.start,
|
this.dragX = undefined;
|
||||||
end: this.bounds.end
|
},
|
||||||
|
pan() {
|
||||||
|
const panBounds = this.getPanBounds();
|
||||||
|
this.$emit('panAxis', panBounds);
|
||||||
|
},
|
||||||
|
endPan() {
|
||||||
|
const panBounds = this.dragStartX && this.dragX && this.dragStartX !== this.dragX
|
||||||
|
? this.getPanBounds()
|
||||||
|
: undefined;
|
||||||
|
this.$emit('endPan', panBounds);
|
||||||
|
this.inPanMode = false;
|
||||||
|
},
|
||||||
|
getPanBounds() {
|
||||||
|
const bounds = this.openmct.time.bounds();
|
||||||
|
const deltaTime = bounds.end - bounds.start;
|
||||||
|
const deltaX = this.dragX - this.dragStartX;
|
||||||
|
const percX = deltaX / this.width;
|
||||||
|
const panStart = bounds.start - percX * deltaTime;
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: panStart,
|
||||||
|
end: panStart + deltaTime
|
||||||
|
};
|
||||||
|
},
|
||||||
|
startZoom() {
|
||||||
|
const x = this.scaleToBounds(this.dragStartX);
|
||||||
|
|
||||||
|
this.zoomStyle = {
|
||||||
|
left: `${this.dragStartX - this.left}px`
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('zoomAxis', {
|
||||||
|
start: x,
|
||||||
|
end: x
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
zoom() {
|
||||||
|
const zoomRange = this.getZoomRange();
|
||||||
|
|
||||||
|
this.zoomStyle = {
|
||||||
|
left: `${zoomRange.start - this.left}px`,
|
||||||
|
width: `${zoomRange.end - zoomRange.start}px`
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('zoomAxis', {
|
||||||
|
start: this.scaleToBounds(zoomRange.start),
|
||||||
|
end: this.scaleToBounds(zoomRange.end)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
endZoom() {
|
||||||
|
const zoomRange = this.dragStartX && this.dragX && this.dragStartX !== this.dragX
|
||||||
|
? this.getZoomRange()
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const zoomBounds = zoomRange
|
||||||
|
? {
|
||||||
|
start: this.scaleToBounds(zoomRange.start),
|
||||||
|
end: this.scaleToBounds(zoomRange.end)
|
||||||
|
}
|
||||||
|
: this.openmct.time.bounds();
|
||||||
|
|
||||||
|
this.zoomStyle = {};
|
||||||
|
this.$emit('endZoom', zoomBounds);
|
||||||
|
},
|
||||||
|
getZoomRange() {
|
||||||
|
const leftBound = this.left;
|
||||||
|
const rightBound = this.left + this.width;
|
||||||
|
|
||||||
|
const zoomStart = this.dragX < leftBound
|
||||||
|
? leftBound
|
||||||
|
: Math.min(this.dragX, this.dragStartX);
|
||||||
|
|
||||||
|
const zoomEnd = this.dragX > rightBound
|
||||||
|
? rightBound
|
||||||
|
: Math.max(this.dragX, this.dragStartX);
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: zoomStart,
|
||||||
|
end: zoomEnd
|
||||||
|
};
|
||||||
|
},
|
||||||
|
scaleToBounds(value) {
|
||||||
|
const bounds = this.openmct.time.bounds();
|
||||||
|
const timeDelta = bounds.end - bounds.start;
|
||||||
|
const valueDelta = value - this.left;
|
||||||
|
const offset = valueDelta / this.width * timeDelta;
|
||||||
|
return bounds.start + offset;
|
||||||
|
},
|
||||||
resize() {
|
resize() {
|
||||||
if (this.$refs.axisHolder.clientWidth !== this.width) {
|
if (this.$refs.axisHolder.clientWidth !== this.width) {
|
||||||
this.width = this.$refs.axisHolder.clientWidth;
|
this.setAxisDimensions();
|
||||||
this.setScale();
|
this.setScale();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
200
src/plugins/timeConductor/ConductorHistory.vue
Normal file
200
src/plugins/timeConductor/ConductorHistory.vue
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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-ctrl-wrapper c-ctrl-wrapper--menus-up">
|
||||||
|
<button class="c-button--menu c-history-button icon-history"
|
||||||
|
@click.prevent="toggle"
|
||||||
|
>
|
||||||
|
<span class="c-button__label">History</span>
|
||||||
|
</button>
|
||||||
|
<div v-if="open"
|
||||||
|
class="c-menu c-conductor__history-menu"
|
||||||
|
>
|
||||||
|
<ul v-if="hasHistoryPresets">
|
||||||
|
<li
|
||||||
|
v-for="preset in presets"
|
||||||
|
:key="preset.label"
|
||||||
|
class="icon-clock"
|
||||||
|
@click="selectPresetBounds(preset.bounds)"
|
||||||
|
>
|
||||||
|
{{ preset.label }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="hasHistoryPresets"
|
||||||
|
class="c-menu__section-separator"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<div class="c-menu__section-hint">
|
||||||
|
Past timeframes, ordered by latest first
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
v-for="(timespan, index) in historyForCurrentTimeSystem"
|
||||||
|
:key="index"
|
||||||
|
class="icon-history"
|
||||||
|
@click="selectTimespan(timespan)"
|
||||||
|
>
|
||||||
|
{{ formatTime(timespan.start) }} - {{ formatTime(timespan.end) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import toggleMixin from '../../ui/mixins/toggle-mixin';
|
||||||
|
|
||||||
|
const LOCAL_STORAGE_HISTORY_KEY = 'tcHistory';
|
||||||
|
const DEFAULT_RECORDS = 10;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['openmct', 'configuration'],
|
||||||
|
mixins: [toggleMixin],
|
||||||
|
props: {
|
||||||
|
bounds: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
timeSystem: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
history: {}, // contains arrays of timespans {start, end}, array key is time system key
|
||||||
|
presets: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
hasHistoryPresets() {
|
||||||
|
return this.timeSystem.isUTCBased && this.presets.length;
|
||||||
|
},
|
||||||
|
historyForCurrentTimeSystem() {
|
||||||
|
const history = this.history[this.timeSystem.key];
|
||||||
|
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
bounds: {
|
||||||
|
handler() {
|
||||||
|
this.addTimespan();
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
timeSystem: {
|
||||||
|
handler() {
|
||||||
|
this.loadConfiguration();
|
||||||
|
this.addTimespan();
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
history: {
|
||||||
|
handler() {
|
||||||
|
this.persistHistoryToLocalStorage();
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getHistoryFromLocalStorage();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getHistoryFromLocalStorage() {
|
||||||
|
if (localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY)) {
|
||||||
|
this.history = JSON.parse(localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY))
|
||||||
|
} else {
|
||||||
|
this.history = {};
|
||||||
|
this.persistHistoryToLocalStorage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
persistHistoryToLocalStorage() {
|
||||||
|
localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, JSON.stringify(this.history));
|
||||||
|
},
|
||||||
|
addTimespan() {
|
||||||
|
const key = this.timeSystem.key;
|
||||||
|
let [...currentHistory] = this.history[key] || [];
|
||||||
|
const timespan = {
|
||||||
|
start: this.bounds.start,
|
||||||
|
end: this.bounds.end
|
||||||
|
};
|
||||||
|
|
||||||
|
const isNotEqual = function (entry) {
|
||||||
|
const start = entry.start !== this.start;
|
||||||
|
const end = entry.end !== this.end;
|
||||||
|
|
||||||
|
return start || end;
|
||||||
|
};
|
||||||
|
currentHistory = currentHistory.filter(isNotEqual, timespan);
|
||||||
|
|
||||||
|
while (currentHistory.length >= this.records) {
|
||||||
|
currentHistory.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentHistory.unshift(timespan);
|
||||||
|
this.history[key] = currentHistory;
|
||||||
|
},
|
||||||
|
selectTimespan(timespan) {
|
||||||
|
this.openmct.time.bounds(timespan);
|
||||||
|
},
|
||||||
|
selectPresetBounds(bounds) {
|
||||||
|
const start = typeof bounds.start === 'function' ? bounds.start() : bounds.start;
|
||||||
|
const end = typeof bounds.end === 'function' ? bounds.end() : bounds.end;
|
||||||
|
|
||||||
|
this.selectTimespan({
|
||||||
|
start: start,
|
||||||
|
end: end
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadConfiguration() {
|
||||||
|
const configurations = this.configuration.menuOptions
|
||||||
|
.filter(option => option.timeSystem === this.timeSystem.key);
|
||||||
|
|
||||||
|
this.presets = this.loadPresets(configurations);
|
||||||
|
this.records = this.loadRecords(configurations);
|
||||||
|
},
|
||||||
|
loadPresets(configurations) {
|
||||||
|
const configuration = configurations.find(option => option.presets);
|
||||||
|
const presets = configuration ? configuration.presets : [];
|
||||||
|
|
||||||
|
return presets;
|
||||||
|
},
|
||||||
|
loadRecords(configurations) {
|
||||||
|
const configuration = configurations.find(option => option.records);
|
||||||
|
const records = configuration ? configuration.records : DEFAULT_RECORDS;
|
||||||
|
|
||||||
|
return records;
|
||||||
|
},
|
||||||
|
formatTime(time) {
|
||||||
|
const formatter = this.openmct.telemetry.getValueFormatter({
|
||||||
|
format: this.timeSystem.timeFormat
|
||||||
|
}).formatter;
|
||||||
|
|
||||||
|
return formatter.format(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -110,7 +110,7 @@ export default {
|
|||||||
if (clock === undefined) {
|
if (clock === undefined) {
|
||||||
return {
|
return {
|
||||||
key: 'fixed',
|
key: 'fixed',
|
||||||
name: 'Fixed Timespan Mode',
|
name: 'Fixed Timespan',
|
||||||
description: 'Query and explore data that falls between two fixed datetimes.',
|
description: 'Query and explore data that falls between two fixed datetimes.',
|
||||||
cssClass: 'icon-tabular'
|
cssClass: 'icon-tabular'
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
text-rendering: geometricPrecision;
|
text-rendering: geometricPrecision;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
> g {
|
> g.axis {
|
||||||
// Overall Tick holder
|
// Overall Tick holder
|
||||||
transform: translateY($tickYPos);
|
transform: translateY($tickYPos);
|
||||||
path {
|
path {
|
||||||
@ -44,7 +44,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.desktop .is-fixed-mode & {
|
body.desktop .is-fixed-mode & {
|
||||||
@include cursorGrab();
|
|
||||||
background-size: 3px 30%;
|
background-size: 3px 30%;
|
||||||
background-color: $colorBodyBgSubtle;
|
background-color: $colorBodyBgSubtle;
|
||||||
box-shadow: inset rgba(black, 0.4) 0 1px 1px;
|
box-shadow: inset rgba(black, 0.4) 0 1px 1px;
|
||||||
@ -55,17 +54,6 @@
|
|||||||
stroke: $colorBodyBgSubtle;
|
stroke: $colorBodyBgSubtle;
|
||||||
transition: $transOut;
|
transition: $transOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active {
|
|
||||||
$c: $colorKeySubtle;
|
|
||||||
background-color: $c;
|
|
||||||
transition: $transIn;
|
|
||||||
svg text {
|
|
||||||
stroke: $c;
|
|
||||||
transition: $transIn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-realtime-mode & {
|
.is-realtime-mode & {
|
||||||
|
@ -57,6 +57,65 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-fixed-mode {
|
||||||
|
.c-conductor-axis {
|
||||||
|
&__zoom-indicator {
|
||||||
|
border: 1px solid transparent;
|
||||||
|
display: none; // Hidden by default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.is-panning),
|
||||||
|
&:not(.is-zooming) {
|
||||||
|
.c-conductor-axis {
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
cursor: col-resize;
|
||||||
|
filter: $timeConductorAxisHoverFilter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-panning,
|
||||||
|
&.is-zooming {
|
||||||
|
.c-conductor-input input {
|
||||||
|
// Styles for inputs while zooming or panning
|
||||||
|
background: rgba($timeConductorActiveBg, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.alt-pressed {
|
||||||
|
.c-conductor-axis:hover {
|
||||||
|
// When alt is being pressed and user is hovering over the axis, set the cursor
|
||||||
|
@include cursorGrab();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-panning {
|
||||||
|
.c-conductor-axis {
|
||||||
|
@include cursorGrab();
|
||||||
|
background-color: $timeConductorActivePanBg;
|
||||||
|
transition: $transIn;
|
||||||
|
|
||||||
|
svg text {
|
||||||
|
stroke: $timeConductorActivePanBg;
|
||||||
|
transition: $transIn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-zooming {
|
||||||
|
.c-conductor-axis__zoom-indicator {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
background: rgba($timeConductorActiveBg, 0.4);
|
||||||
|
border-left-color: $timeConductorActiveBg;
|
||||||
|
border-right-color: $timeConductorActiveBg;
|
||||||
|
top: 0; bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.is-realtime-mode {
|
&.is-realtime-mode {
|
||||||
.c-conductor__time-bounds {
|
.c-conductor__time-bounds {
|
||||||
grid-template-columns: 20px auto 1fr auto auto;
|
grid-template-columns: 20px auto 1fr auto auto;
|
||||||
|
@ -142,6 +142,9 @@ $colorTimeHov: pullForward($colorTime, 10%);
|
|||||||
$colorTimeSubtle: pushBack($colorTime, 20%);
|
$colorTimeSubtle: pushBack($colorTime, 20%);
|
||||||
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
|
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
|
||||||
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
|
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
|
||||||
|
$timeConductorAxisHoverFilter: brightness(1.2);
|
||||||
|
$timeConductorActiveBg: $colorKey;
|
||||||
|
$timeConductorActivePanBg: #226074;
|
||||||
|
|
||||||
/************************************************** BROWSING */
|
/************************************************** BROWSING */
|
||||||
$browseFrameColor: pullForward($colorBodyBg, 10%);
|
$browseFrameColor: pullForward($colorBodyBg, 10%);
|
||||||
|
@ -146,6 +146,9 @@ $colorTimeHov: pullForward($colorTime, 10%);
|
|||||||
$colorTimeSubtle: pushBack($colorTime, 20%);
|
$colorTimeSubtle: pushBack($colorTime, 20%);
|
||||||
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
|
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
|
||||||
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
|
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
|
||||||
|
$timeConductorAxisHoverFilter: brightness(1.2);
|
||||||
|
$timeConductorActiveBg: $colorKey;
|
||||||
|
$timeConductorActivePanBg: #226074;
|
||||||
|
|
||||||
/************************************************** BROWSING */
|
/************************************************** BROWSING */
|
||||||
$browseFrameColor: pullForward($colorBodyBg, 10%);
|
$browseFrameColor: pullForward($colorBodyBg, 10%);
|
||||||
|
@ -132,7 +132,7 @@ $colorPausedFg: #fff;
|
|||||||
// Base variations
|
// Base variations
|
||||||
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
|
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
|
||||||
$colorBodyBgSubtleHov: pushBack($colorKey, 50%);
|
$colorBodyBgSubtleHov: pushBack($colorKey, 50%);
|
||||||
$colorKeySubtle: pushBack($colorKey, 10%);
|
$colorKeySubtle: pushBack($colorKey, 20%);
|
||||||
|
|
||||||
// Time Colors
|
// Time Colors
|
||||||
$colorTime: #618cff;
|
$colorTime: #618cff;
|
||||||
@ -142,6 +142,9 @@ $colorTimeHov: pushBack($colorTime, 5%);
|
|||||||
$colorTimeSubtle: pushBack($colorTime, 20%);
|
$colorTimeSubtle: pushBack($colorTime, 20%);
|
||||||
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
|
$colorTOI: $colorBodyFg; // was $timeControllerToiLineColor
|
||||||
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
|
$colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov
|
||||||
|
$timeConductorAxisHoverFilter: brightness(0.8);
|
||||||
|
$timeConductorActiveBg: $colorKey;
|
||||||
|
$timeConductorActivePanBg: #A0CDE1;
|
||||||
|
|
||||||
/************************************************** BROWSING */
|
/************************************************** BROWSING */
|
||||||
$browseFrameColor: pullForward($colorBodyBg, 10%);
|
$browseFrameColor: pullForward($colorBodyBg, 10%);
|
||||||
|
@ -148,6 +148,7 @@ $glyph-icon-cursor-lock: '\e929';
|
|||||||
$glyph-icon-flag: '\e92a';
|
$glyph-icon-flag: '\e92a';
|
||||||
$glyph-icon-eye-disabled: '\e92b';
|
$glyph-icon-eye-disabled: '\e92b';
|
||||||
$glyph-icon-notebook-page: '\e92c';
|
$glyph-icon-notebook-page: '\e92c';
|
||||||
|
$glyph-icon-unlocked: '\e92d';
|
||||||
$glyph-icon-arrows-right-left: '\ea00';
|
$glyph-icon-arrows-right-left: '\ea00';
|
||||||
$glyph-icon-arrows-up-down: '\ea01';
|
$glyph-icon-arrows-up-down: '\ea01';
|
||||||
$glyph-icon-bullet: '\ea02';
|
$glyph-icon-bullet: '\ea02';
|
||||||
@ -198,6 +199,11 @@ $glyph-icon-export: '\ea2e';
|
|||||||
$glyph-icon-font-size: '\ea2f';
|
$glyph-icon-font-size: '\ea2f';
|
||||||
$glyph-icon-clear-data: '\ea30';
|
$glyph-icon-clear-data: '\ea30';
|
||||||
$glyph-icon-history: '\ea31';
|
$glyph-icon-history: '\ea31';
|
||||||
|
$glyph-icon-arrow-nav-to-parent: '\ea32';
|
||||||
|
$glyph-icon-crosshair-in-circle: '\ea33';
|
||||||
|
$glyph-icon-target: '\ea34';
|
||||||
|
$glyph-icon-items-collapse: '\ea35';
|
||||||
|
$glyph-icon-items-expand: '\ea36';
|
||||||
$glyph-icon-activity: '\eb00';
|
$glyph-icon-activity: '\eb00';
|
||||||
$glyph-icon-activity-mode: '\eb01';
|
$glyph-icon-activity-mode: '\eb01';
|
||||||
$glyph-icon-autoflow-tabular: '\eb02';
|
$glyph-icon-autoflow-tabular: '\eb02';
|
||||||
@ -240,6 +246,7 @@ $glyph-icon-command: '\eb26';
|
|||||||
$glyph-icon-conditional: '\eb27';
|
$glyph-icon-conditional: '\eb27';
|
||||||
$glyph-icon-condition-widget: '\eb28';
|
$glyph-icon-condition-widget: '\eb28';
|
||||||
$glyph-icon-alphanumeric: '\eb29';
|
$glyph-icon-alphanumeric: '\eb29';
|
||||||
|
$glyph-icon-image-telemetry: '\eb2a';
|
||||||
|
|
||||||
/************************** GLYPHS AS DATA URI */
|
/************************** GLYPHS AS DATA URI */
|
||||||
// Only objects have been converted, for use in Create menu and folder views
|
// Only objects have been converted, for use in Create menu and folder views
|
||||||
|
@ -462,9 +462,17 @@ select {
|
|||||||
text-shadow: $shdwMenuText;
|
text-shadow: $shdwMenuText;
|
||||||
padding: $interiorMarginSm;
|
padding: $interiorMarginSm;
|
||||||
box-shadow: $shdwMenu;
|
box-shadow: $shdwMenu;
|
||||||
display: block;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
//+ * {
|
||||||
|
// margin-top: $interiorMarginSm;
|
||||||
|
//}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin menuInner() {
|
@mixin menuInner() {
|
||||||
@ -502,6 +510,23 @@ select {
|
|||||||
.c-menu {
|
.c-menu {
|
||||||
@include menuOuter();
|
@include menuOuter();
|
||||||
@include menuInner();
|
@include menuInner();
|
||||||
|
|
||||||
|
&__section-hint {
|
||||||
|
$m: $interiorMargin;
|
||||||
|
margin: $m 0;
|
||||||
|
padding: $m nth($menuItemPad, 2) 0 nth($menuItemPad, 2);
|
||||||
|
|
||||||
|
opacity: 0.6;
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__section-separator {
|
||||||
|
$m: $interiorMargin;
|
||||||
|
border-top: 1px solid $colorInteriorBorder;
|
||||||
|
margin: $m 0;
|
||||||
|
padding: $m nth($menuItemPad, 2) 0 nth($menuItemPad, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-super-menu {
|
.c-super-menu {
|
||||||
|
@ -84,6 +84,7 @@
|
|||||||
.icon-flag { @include glyphBefore($glyph-icon-flag); }
|
.icon-flag { @include glyphBefore($glyph-icon-flag); }
|
||||||
.icon-eye-disabled { @include glyphBefore($glyph-icon-eye-disabled); }
|
.icon-eye-disabled { @include glyphBefore($glyph-icon-eye-disabled); }
|
||||||
.icon-notebook-page { @include glyphBefore($glyph-icon-notebook-page); }
|
.icon-notebook-page { @include glyphBefore($glyph-icon-notebook-page); }
|
||||||
|
.icon-unlocked { @include glyphBefore($glyph-icon-unlocked); }
|
||||||
.icon-arrows-right-left { @include glyphBefore($glyph-icon-arrows-right-left); }
|
.icon-arrows-right-left { @include glyphBefore($glyph-icon-arrows-right-left); }
|
||||||
.icon-arrows-up-down { @include glyphBefore($glyph-icon-arrows-up-down); }
|
.icon-arrows-up-down { @include glyphBefore($glyph-icon-arrows-up-down); }
|
||||||
.icon-bullet { @include glyphBefore($glyph-icon-bullet); }
|
.icon-bullet { @include glyphBefore($glyph-icon-bullet); }
|
||||||
@ -134,6 +135,11 @@
|
|||||||
.icon-font-size { @include glyphBefore($glyph-icon-font-size); }
|
.icon-font-size { @include glyphBefore($glyph-icon-font-size); }
|
||||||
.icon-clear-data { @include glyphBefore($glyph-icon-clear-data); }
|
.icon-clear-data { @include glyphBefore($glyph-icon-clear-data); }
|
||||||
.icon-history { @include glyphBefore($glyph-icon-history); }
|
.icon-history { @include glyphBefore($glyph-icon-history); }
|
||||||
|
.icon-arrow-nav-to-parent { @include glyphBefore($glyph-icon-arrow-nav-to-parent); }
|
||||||
|
.icon-crosshair-in-circle { @include glyphBefore($glyph-icon-crosshair-in-circle); }
|
||||||
|
.icon-target { @include glyphBefore($glyph-icon-target); }
|
||||||
|
.icon-items-collapse { @include glyphBefore($glyph-icon-items-collapse); }
|
||||||
|
.icon-items-expand { @include glyphBefore($glyph-icon-items-expand); }
|
||||||
.icon-activity { @include glyphBefore($glyph-icon-activity); }
|
.icon-activity { @include glyphBefore($glyph-icon-activity); }
|
||||||
.icon-activity-mode { @include glyphBefore($glyph-icon-activity-mode); }
|
.icon-activity-mode { @include glyphBefore($glyph-icon-activity-mode); }
|
||||||
.icon-autoflow-tabular { @include glyphBefore($glyph-icon-autoflow-tabular); }
|
.icon-autoflow-tabular { @include glyphBefore($glyph-icon-autoflow-tabular); }
|
||||||
@ -176,6 +182,7 @@
|
|||||||
.icon-conditional { @include glyphBefore($glyph-icon-conditional); }
|
.icon-conditional { @include glyphBefore($glyph-icon-conditional); }
|
||||||
.icon-condition-widget { @include glyphBefore($glyph-icon-condition-widget); }
|
.icon-condition-widget { @include glyphBefore($glyph-icon-condition-widget); }
|
||||||
.icon-alphanumeric { @include glyphBefore($glyph-icon-alphanumeric); }
|
.icon-alphanumeric { @include glyphBefore($glyph-icon-alphanumeric); }
|
||||||
|
.icon-image-telemetry { @include glyphBefore($glyph-icon-image-telemetry); }
|
||||||
|
|
||||||
/************************** 12 PX CLASSES */
|
/************************** 12 PX CLASSES */
|
||||||
// TODO: sync with 16px redo as of 10/25/18
|
// TODO: sync with 16px redo as of 10/25/18
|
||||||
|
@ -114,25 +114,6 @@ mct-plot {
|
|||||||
.plot-wrapper-axis-and-display-area {
|
.plot-wrapper-axis-and-display-area {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|
||||||
.l-state-indicators {
|
|
||||||
color: $colorPausedBg;
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
font-size: 1.5em;
|
|
||||||
pointer-events: none;
|
|
||||||
top: $interiorMarginSm;
|
|
||||||
left: $interiorMarginSm;
|
|
||||||
z-index: 2;
|
|
||||||
|
|
||||||
> * + * {
|
|
||||||
margin-left: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
|
|
||||||
.t-alert-unsynced {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.gl-plot-wrapper-display-area-and-x-axis {
|
.gl-plot-wrapper-display-area-and-x-axis {
|
||||||
@ -294,6 +275,25 @@ mct-plot {
|
|||||||
right: $m;
|
right: $m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.l-state-indicators {
|
||||||
|
color: $colorPausedBg;
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
font-size: 1.5em;
|
||||||
|
pointer-events: none;
|
||||||
|
top: $interiorMarginSm;
|
||||||
|
left: $interiorMarginSm;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-left: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-alert-unsynced {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.gl-plot-display-area,
|
.gl-plot-display-area,
|
||||||
@ -432,6 +432,7 @@ mct-plot {
|
|||||||
&__wrapper {
|
&__wrapper {
|
||||||
// Holds view-control and both collapsed and expanded legends
|
// Holds view-control and both collapsed and expanded legends
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
overflow: auto; // Prevents collapsed legend from forcing scrollbars on higher parent containers
|
||||||
}
|
}
|
||||||
|
|
||||||
&__view-control {
|
&__view-control {
|
||||||
|
@ -893,7 +893,7 @@ body.desktop {
|
|||||||
.grid-row {
|
.grid-row {
|
||||||
.grid-cell {
|
.grid-cell {
|
||||||
padding: 3px $interiorMarginLg 3px 0;
|
padding: 3px $interiorMarginLg 3px 0;
|
||||||
&[title] {
|
&[title]:not([title=""]) {
|
||||||
// When a cell has a title, assume it's helpful text
|
// When a cell has a title, assume it's helpful text
|
||||||
cursor: help;
|
cursor: help;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@
|
|||||||
<glyph unicode="" glyph-name="icon-hourglass" d="M1024 832h-1024c0-282.8 229.2-512 512-512s512 229.2 512 512zM512 448c-102.6 0-199 40-271.6 112.4-41.2 41.2-72 90.2-90.8 143.6h724.6c-18.8-53.4-49.6-102.4-90.8-143.6-72.4-72.4-168.8-112.4-271.4-112.4zM512 320c-282.8 0-512-229.2-512-512h1024c0 282.8-229.2 512-512 512z" />
|
<glyph unicode="" glyph-name="icon-hourglass" d="M1024 832h-1024c0-282.8 229.2-512 512-512s512 229.2 512 512zM512 448c-102.6 0-199 40-271.6 112.4-41.2 41.2-72 90.2-90.8 143.6h724.6c-18.8-53.4-49.6-102.4-90.8-143.6-72.4-72.4-168.8-112.4-271.4-112.4zM512 320c-282.8 0-512-229.2-512-512h1024c0 282.8-229.2 512-512 512z" />
|
||||||
<glyph unicode="" glyph-name="icon-info" d="M512 832c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM512 704c70.6 0 128-57.4 128-128s-57.4-128-128-128c-70.6 0-128 57.4-128 128s57.4 128 128 128zM704 0h-384v128h64v256h256v-256h64v-128z" />
|
<glyph unicode="" glyph-name="icon-info" d="M512 832c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM512 704c70.6 0 128-57.4 128-128s-57.4-128-128-128c-70.6 0-128 57.4-128 128s57.4 128 128 128zM704 0h-384v128h64v256h256v-256h64v-128z" />
|
||||||
<glyph unicode="" glyph-name="icon-link" d="M1024 320l-512 512v-307.2l-512-204.8v-256h512v-256z" />
|
<glyph unicode="" glyph-name="icon-link" d="M1024 320l-512 512v-307.2l-512-204.8v-256h512v-256z" />
|
||||||
<glyph unicode="" glyph-name="icon-lock" d="M832 448h-32v96c0 158.8-129.2 288-288 288s-288-129.2-288-288v-96h-32c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h640c70.4 0 128 57.6 128 128v384c0 70.4-57.6 128-128 128zM416 544c0 53 43 96 96 96s96-43 96-96v-96h-192v96z" />
|
<glyph unicode="" glyph-name="icon-lock" horiz-adv-x="768" d="M702 448h-62v128c0 141.385-114.615 256-256 256s-256-114.615-256-256v0-128h-64c-35.301-0.113-63.887-28.699-64-63.989v-512.011c0.113-35.301 28.699-63.887 63.989-64h638.011c35.301 0.113 63.887 28.699 64 63.989v512.011c-0.113 35.301-28.699 63.887-63.989 64h-0.011zM256 448v128c0 70.692 57.308 128 128 128s128-57.308 128-128v0-128z" />
|
||||||
<glyph unicode="" glyph-name="icon-minus" d="M960 192c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64h-896c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h896z" />
|
<glyph unicode="" glyph-name="icon-minus" d="M960 192c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64h-896c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h896z" />
|
||||||
<glyph unicode="" glyph-name="icon-people" d="M704 512h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM256 512h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM832 448h-192c-34.908 0-67.716-9.448-96-25.904 57.278-33.324 96-95.404 96-166.096v-448h384v448c0 105.6-86.4 192-192 192zM384 448h-192c-105.6 0-192-86.4-192-192v-448h576v448c0 105.6-86.4 192-192 192z" />
|
<glyph unicode="" glyph-name="icon-people" d="M704 512h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM256 512h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM832 448h-192c-34.908 0-67.716-9.448-96-25.904 57.278-33.324 96-95.404 96-166.096v-448h384v448c0 105.6-86.4 192-192 192zM384 448h-192c-105.6 0-192-86.4-192-192v-448h576v448c0 105.6-86.4 192-192 192z" />
|
||||||
<glyph unicode="" glyph-name="icon-person" d="M768 576c0-105.6-86.4-192-192-192h-128c-105.6 0-192 86.4-192 192v64c0 105.6 86.4 192 192 192h128c105.6 0 192-86.4 192-192v-64zM64-192v192c0 140.8 115.2 256 256 256h384c140.8 0 256-115.2 256-256v-192z" />
|
<glyph unicode="" glyph-name="icon-person" d="M768 576c0-105.6-86.4-192-192-192h-128c-105.6 0-192 86.4-192 192v64c0 105.6 86.4 192 192 192h128c105.6 0 192-86.4 192-192v-64zM64-192v192c0 140.8 115.2 256 256 256h384c140.8 0 256-115.2 256-256v-192z" />
|
||||||
@ -52,6 +52,7 @@
|
|||||||
<glyph unicode="" glyph-name="icon-flag" d="M192 192h832l-192 320 192 320h-896c-70.606-0.215-127.785-57.394-128-127.979v-896.021h192z" />
|
<glyph unicode="" glyph-name="icon-flag" d="M192 192h832l-192 320 192 320h-896c-70.606-0.215-127.785-57.394-128-127.979v-896.021h192z" />
|
||||||
<glyph unicode="" glyph-name="icon-eye-disabled" d="M209.46 223.32q-7.46 9.86-14.26 20.28c-14.737 21.984-27.741 47.184-37.759 73.847l-0.841 2.553c11.078 29.259 24.068 54.443 39.51 77.869l-0.91-1.469c23.221 34.963 50.705 64.8 82.207 89.793l0.793 0.607c57.663 45.719 130.179 75.053 209.311 79.947l1.069 0.053 114.48 140.88c-27.366 5.017-58.869 7.898-91.041 7.92h-0.019c-245.8 0-452.2-168-510.8-395.6 21.856-82.93 60.906-154.847 113.325-214.773l-0.525 0.613zM814.76 416.92q7.52-10 14.44-20.52c14.737-21.984 27.741-47.184 37.759-73.847l0.841-2.553c-10.859-29.216-23.863-54.416-39.447-77.748l0.847 1.348c-23.221-34.963-50.705-64.8-82.207-89.793l-0.793-0.607c-57.762-45.834-130.437-75.216-209.743-80.049l-1.057-0.051-114.46-140.86c27.346-4.988 58.817-7.84 90.955-7.84 0.037 0 0.074 0 0.111 0h-0.005c245.8 0 452.2 168 510.8 395.6-21.856 82.93-60.906 154.847-113.325 214.773l0.525-0.613zM832 832l-832-1024h192l832 1024h-192z" />
|
<glyph unicode="" glyph-name="icon-eye-disabled" d="M209.46 223.32q-7.46 9.86-14.26 20.28c-14.737 21.984-27.741 47.184-37.759 73.847l-0.841 2.553c11.078 29.259 24.068 54.443 39.51 77.869l-0.91-1.469c23.221 34.963 50.705 64.8 82.207 89.793l0.793 0.607c57.663 45.719 130.179 75.053 209.311 79.947l1.069 0.053 114.48 140.88c-27.366 5.017-58.869 7.898-91.041 7.92h-0.019c-245.8 0-452.2-168-510.8-395.6 21.856-82.93 60.906-154.847 113.325-214.773l-0.525 0.613zM814.76 416.92q7.52-10 14.44-20.52c14.737-21.984 27.741-47.184 37.759-73.847l0.841-2.553c-10.859-29.216-23.863-54.416-39.447-77.748l0.847 1.348c-23.221-34.963-50.705-64.8-82.207-89.793l-0.793-0.607c-57.762-45.834-130.437-75.216-209.743-80.049l-1.057-0.051-114.46-140.86c27.346-4.988 58.817-7.84 90.955-7.84 0.037 0 0.074 0 0.111 0h-0.005c245.8 0 452.2 168 510.8 395.6-21.856 82.93-60.906 154.847-113.325 214.773l0.525-0.613zM832 832l-832-1024h192l832 1024h-192z" />
|
||||||
<glyph unicode="" glyph-name="icon-notebook-page" d="M830 770h-830l-4-702c0-106.6 87.4-194 194-194h640c106.6 0 194 87.4 194 194v508c0 106.8-87.4 194-194 194zM832 386l-384-384-192 192v256l192-192 384 384v-256z" />
|
<glyph unicode="" glyph-name="icon-notebook-page" d="M830 770h-830l-4-702c0-106.6 87.4-194 194-194h640c106.6 0 194 87.4 194 194v508c0 106.8-87.4 194-194 194zM832 386l-384-384-192 192v256l192-192 384 384v-256z" />
|
||||||
|
<glyph unicode="" glyph-name="icon-unlocked" d="M768 832c-141.339-0.114-255.886-114.661-256-255.989v-128.011h-448c-35.301-0.113-63.887-28.699-64-63.989v-512.011c0.113-35.301 28.699-63.887 63.989-64h638.011c35.301 0.113 63.887 28.699 64 63.989v512.011c-0.113 35.301-28.699 63.887-63.989 64h-62.011v128c0 70.692 57.308 128 128 128s128-57.308 128-128v0-128h128v128c-0.114 141.339-114.661 255.886-255.989 256h-0.011z" />
|
||||||
<glyph unicode="" glyph-name="icon-arrows-right-left" d="M1024 320l-448-512v1024zM448 832l-448-512 448-512z" />
|
<glyph unicode="" glyph-name="icon-arrows-right-left" d="M1024 320l-448-512v1024zM448 832l-448-512 448-512z" />
|
||||||
<glyph unicode="" glyph-name="icon-arrows-up-down" d="M512 832l512-448h-1024zM0 256l512-448 512 448z" />
|
<glyph unicode="" glyph-name="icon-arrows-up-down" d="M512 832l512-448h-1024zM0 256l512-448 512 448z" />
|
||||||
<glyph unicode="" glyph-name="icon-bullet" d="M832 80c0-44-36-80-80-80h-480c-44 0-80 36-80 80v480c0 44 36 80 80 80h480c44 0 80-36 80-80v-480z" />
|
<glyph unicode="" glyph-name="icon-bullet" d="M832 80c0-44-36-80-80-80h-480c-44 0-80 36-80 80v480c0 44 36 80 80 80h480c44 0 80-36 80-80v-480z" />
|
||||||
@ -102,6 +103,11 @@
|
|||||||
<glyph unicode="" glyph-name="icon-font-size" d="M842.841 451.952h-120.956l-52.382-139.676 52.918-141.12 59.942 159.84 62.361-166.314h-119.884l34.019-90.717h119.884l39.695-105.836h105.836l-181.434 483.823zM263.903 671.871l-263.903-703.742h153.944l57.729 153.944h280.397l57.729-153.944h153.944l-263.903 703.742zM261.154 254.024l90.717 241.911 90.717-241.911z" />
|
<glyph unicode="" glyph-name="icon-font-size" d="M842.841 451.952h-120.956l-52.382-139.676 52.918-141.12 59.942 159.84 62.361-166.314h-119.884l34.019-90.717h119.884l39.695-105.836h105.836l-181.434 483.823zM263.903 671.871l-263.903-703.742h153.944l57.729 153.944h280.397l57.729-153.944h153.944l-263.903 703.742zM261.154 254.024l90.717 241.911 90.717-241.911z" />
|
||||||
<glyph unicode="" glyph-name="icon-clear-data" d="M632 520l-120-120-120 120-80-80 120-120-120-120 80-80 120 120 120-120 80 80-120 120 120 120-80 80zM512 832c-282.76 0-512-86-512-192v-640c0-106 229.24-192 512-192s512 86 512 192v640c0 106-229.24 192-512 192zM512 0c-176.731 0-320 143.269-320 320s143.269 320 320 320c176.731 0 320-143.269 320-320v0c0-176.731-143.269-320-320-320v0z" />
|
<glyph unicode="" glyph-name="icon-clear-data" d="M632 520l-120-120-120 120-80-80 120-120-120-120 80-80 120 120 120-120 80 80-120 120 120 120-80 80zM512 832c-282.76 0-512-86-512-192v-640c0-106 229.24-192 512-192s512 86 512 192v640c0 106-229.24 192-512 192zM512 0c-176.731 0-320 143.269-320 320s143.269 320 320 320c176.731 0 320-143.269 320-320v0c0-176.731-143.269-320-320-320v0z" />
|
||||||
<glyph unicode="" glyph-name="icon-history" d="M576 768c-247.4 0-448-200.6-448-448h-128l192-192 192 192h-128c0 85.4 33.2 165.8 93.8 226.2 60.4 60.6 140.8 93.8 226.2 93.8s165.8-33.2 226.2-93.8c60.6-60.4 93.8-140.8 93.8-226.2s-33.2-165.8-93.8-226.2c-60.4-60.6-140.8-93.8-226.2-93.8s-165.8 33.2-226.2 93.8l-90.6-90.6c81-81 193-131.2 316.8-131.2 247.4 0 448 200.6 448 448s-200.6 448-448 448zM576 560c-26.6 0-48-21.4-48-48v-211.8l142-142c9.4-9.4 21.6-14 34-14s24.6 4.6 34 14c18.8 18.8 18.8 49.2 0 67.8l-114 114v172c0 26.6-21.4 48-48 48z" />
|
<glyph unicode="" glyph-name="icon-history" d="M576 768c-247.4 0-448-200.6-448-448h-128l192-192 192 192h-128c0 85.4 33.2 165.8 93.8 226.2 60.4 60.6 140.8 93.8 226.2 93.8s165.8-33.2 226.2-93.8c60.6-60.4 93.8-140.8 93.8-226.2s-33.2-165.8-93.8-226.2c-60.4-60.6-140.8-93.8-226.2-93.8s-165.8 33.2-226.2 93.8l-90.6-90.6c81-81 193-131.2 316.8-131.2 247.4 0 448 200.6 448 448s-200.6 448-448 448zM576 560c-26.6 0-48-21.4-48-48v-211.8l142-142c9.4-9.4 21.6-14 34-14s24.6 4.6 34 14c18.8 18.8 18.8 49.2 0 67.8l-114 114v172c0 26.6-21.4 48-48 48z" />
|
||||||
|
<glyph unicode="" glyph-name="icon-arrow-up-to-parent" horiz-adv-x="1056" d="M643.427 6.739c-81.955 0.697-148.179 67.065-148.642 149.010v395.872l296.871-247.393v197.914l-395.828 329.857-395.828-328.62v-197.502l296.871 246.156v-396.241c0-190.905 155.239-346.556 346.144-346.968l412.321-0.825 0.412 197.914z" />
|
||||||
|
<glyph unicode="" glyph-name="icon-crosshair-in-circle" d="M512 832c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM783.6 48.4c-54.634-54.8-125.77-93.12-205.322-106.874l-2.278-0.326v250.8h-128v-250.8c-161.302 28.062-286.738 153.497-314.468 312.5l-0.332 2.3h250.8v128h-250.8c28.062 161.302 153.497 286.738 312.5 314.468l2.3 0.332v-250.8h128v250.8c161.302-28.062 286.738-153.497 314.468-312.5l0.332-2.3h-250.8v-128h250.8c-14.080-81.83-52.4-152.966-107.191-207.591l-0.009-0.009z" />
|
||||||
|
<glyph unicode="" glyph-name="icon-target" d="M512 448c70.692 0 128-57.308 128-128s-57.308-128-128-128c-70.692 0-128 57.308-128 128v0c0.114 70.647 57.353 127.886 127.989 128h0.011zM512 576c-141.385 0-256-114.615-256-256s114.615-256 256-256c141.385 0 256 114.615 256 256v0c-0.114 141.339-114.661 255.886-255.989 256h-0.011zM512 704c211.87-0.128 383.575-171.912 383.575-383.8 0-211.967-171.833-383.8-383.8-383.8s-383.8 171.833-383.8 383.8c0 105.99 42.963 201.945 112.425 271.4v0c69.21 69.437 164.944 112.401 270.713 112.401 0.312 0 0.624 0 0.936-0.001h-0.048zM512 832c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512z" />
|
||||||
|
<glyph unicode="" glyph-name="icon-items-collapse" d="M45.2 173.2h229.6l-274.8-274.6 90.6-90.6 274.6 274.8v-229.6h128v448h-448v-128zM1024 741.4l-90.6 90.6-274.6-274.8v229.6h-128v-448h448v128h-229.6l274.8 274.6z" />
|
||||||
|
<glyph unicode="" glyph-name="icon-items-expand" d="M448-64h-229.4l274.6 274.8-90.4 90.4-274.8-274.6v229.4h-128v-448h448v128zM530.8 429.2l90.4-90.4 274.8 274.6v-229.4h128v448h-448v-128h229.4l-274.6-274.8z" />
|
||||||
<glyph unicode="" glyph-name="icon-activity" d="M576 768h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
|
<glyph unicode="" glyph-name="icon-activity" d="M576 768h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
|
||||||
<glyph unicode="" glyph-name="icon-activity-mode" d="M512 832c-214.8 0-398.8-132.4-474.8-320h90.8c56.8 0 108-24.8 143-64h241l-192 192h256l320-320-320-320h-256l192 192h-241c-35-39.2-86.2-64-143-64h-90.8c76-187.6 259.8-320 474.8-320 282.8 0 512 229.2 512 512s-229.2 512-512 512z" />
|
<glyph unicode="" glyph-name="icon-activity-mode" d="M512 832c-214.8 0-398.8-132.4-474.8-320h90.8c56.8 0 108-24.8 143-64h241l-192 192h256l320-320-320-320h-256l192 192h-241c-35-39.2-86.2-64-143-64h-90.8c76-187.6 259.8-320 474.8-320 282.8 0 512 229.2 512 512s-229.2 512-512 512z" />
|
||||||
<glyph unicode="" glyph-name="icon-autoflow-tabular" d="M192 832c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 832h256v-1024h-256v1024zM832 832h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
|
<glyph unicode="" glyph-name="icon-autoflow-tabular" d="M192 832c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 832h256v-1024h-256v1024zM832 832h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
|
||||||
@ -144,4 +150,5 @@
|
|||||||
<glyph unicode="" glyph-name="icon-conditional" d="M512 832c-282.76 0-512-229.24-512-512s229.24-512 512-512 512 229.24 512 512-229.24 512-512 512zM512 64l-384 256 384 256 384-256z" />
|
<glyph unicode="" glyph-name="icon-conditional" d="M512 832c-282.76 0-512-229.24-512-512s229.24-512 512-512 512 229.24 512 512-229.24 512-512 512zM512 64l-384 256 384 256 384-256z" />
|
||||||
<glyph unicode="" glyph-name="icon-condition-widget" d="M832 832h-640c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM512 64l-384 256 384 256 384-256z" />
|
<glyph unicode="" glyph-name="icon-condition-widget" d="M832 832h-640c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM512 64l-384 256 384 256 384-256z" />
|
||||||
<glyph unicode="" glyph-name="icon-alphanumeric" d="M535.6 301.4c-8.4-1.6-17.2-3-26.2-4s-18.2-2.4-27.2-4c-10.196-1.861-18.808-4.010-27.21-6.633l1.61 0.433c-8.609-2.674-16.105-6.348-22.89-10.987l0.29 0.187c-6.693-4.517-12.283-10.107-16.663-16.585l-0.137-0.215c-4.6-6.8-7.4-15.6-8.8-26s-0.4-18.4 2.4-25.2c2.746-6.688 7.224-12.195 12.881-16.122l0.119-0.078c5.967-4.053 13.057-6.94 20.704-8.161l0.296-0.039c7.592-1.527 16.319-2.4 25.25-2.4 0.123 0 0.246 0 0.369 0h-0.019c22.2 0 39.6 3.6 52.6 11s23.2 16.2 30.2 26.4c6.273 8.873 11.271 19.191 14.426 30.285l0.174 0.715c1.853 6.809 3.601 15.41 4.855 24.169l0.145 1.231 5.2 41.6c-5.4-4.217-11.723-7.564-18.583-9.689l-0.417-0.111c-6.489-2.241-14.362-4.255-22.444-5.662l-0.956-0.138zM1024 448v192h-152l24 192h-192l-24-192h-256l24 192h-192l-24-192h-232v-192h208l-32-256h-176v-192h152l-24-192h192l24 192h256l-24-192h192l24 192h232v192h-208l32 256zM702.8 420.2l-26.4-211.8c-2.231-15.809-3.537-34.122-3.6-52.727v-0.073c0-16.8 2.2-29.4 6.4-37.8h-113.4c-1.342 5.556-2.338 12.122-2.781 18.84l-0.019 0.36c-0.261 3.524-0.409 7.634-0.409 11.778 0 2.962 0.076 5.907 0.226 8.832l-0.017-0.41c-18.663-17.401-41.395-30.694-66.597-38.289l-1.203-0.311c-22.627-6.956-48.639-10.974-75.586-11h-0.014c-0.764-0.011-1.666-0.018-2.569-0.018-18.098 0-35.598 2.563-52.156 7.345l1.325-0.328c-15.991 4.512-29.851 12.090-41.545 22.122l0.145-0.122c-11.233 9.982-19.792 22.733-24.624 37.192l-0.176 0.608c-5.2 15.2-6.4 33.4-3.8 54.4s9.4 42.2 19.4 57.2c9.524 14.399 21.535 26.346 35.532 35.512l0.468 0.288c13.387 8.662 28.922 15.533 45.512 19.765l1.088 0.235c13.436 3.792 30.801 7.554 48.47 10.41l2.93 0.39c17 2.6 33.8 4.6 50.4 6.2 16.628 1.527 31.69 4.070 46.349 7.643l-2.149-0.443c13 3 23.6 7.6 31.6 13.6s12.6 15 13.6 26.4 0.8 21.8-2.4 28.8c-2.849 6.902-7.542 12.56-13.468 16.517l-0.132 0.083c-6.217 4.011-13.604 6.78-21.543 7.774l-0.257 0.026c-7.897 1.277-17 2.007-26.274 2.007-0.537 0-1.073-0.002-1.609-0.007l0.082 0.001c-22 0-40-4.6-53.8-14.2s-23-25.2-28-47.2h-111.8c4.8 26.2 14.2 48 27.8 65.4 13.475 16.978 29.89 30.968 48.574 41.377l0.826 0.423c18.192 10.038 39.297 17.806 61.619 22.175l1.381 0.225c20.488 4.162 44.053 6.563 68.171 6.6h0.029c21.8-0.005 43.239-1.532 64.222-4.479l-2.422 0.279c20.641-2.809 39.324-8.783 56.401-17.461l-1.001 0.461c15.909-8.108 28.858-20.031 37.967-34.601l0.233-0.399c9-15 12.2-34.8 9-59.6z" />
|
<glyph unicode="" glyph-name="icon-alphanumeric" d="M535.6 301.4c-8.4-1.6-17.2-3-26.2-4s-18.2-2.4-27.2-4c-10.196-1.861-18.808-4.010-27.21-6.633l1.61 0.433c-8.609-2.674-16.105-6.348-22.89-10.987l0.29 0.187c-6.693-4.517-12.283-10.107-16.663-16.585l-0.137-0.215c-4.6-6.8-7.4-15.6-8.8-26s-0.4-18.4 2.4-25.2c2.746-6.688 7.224-12.195 12.881-16.122l0.119-0.078c5.967-4.053 13.057-6.94 20.704-8.161l0.296-0.039c7.592-1.527 16.319-2.4 25.25-2.4 0.123 0 0.246 0 0.369 0h-0.019c22.2 0 39.6 3.6 52.6 11s23.2 16.2 30.2 26.4c6.273 8.873 11.271 19.191 14.426 30.285l0.174 0.715c1.853 6.809 3.601 15.41 4.855 24.169l0.145 1.231 5.2 41.6c-5.4-4.217-11.723-7.564-18.583-9.689l-0.417-0.111c-6.489-2.241-14.362-4.255-22.444-5.662l-0.956-0.138zM1024 448v192h-152l24 192h-192l-24-192h-256l24 192h-192l-24-192h-232v-192h208l-32-256h-176v-192h152l-24-192h192l24 192h256l-24-192h192l24 192h232v192h-208l32 256zM702.8 420.2l-26.4-211.8c-2.231-15.809-3.537-34.122-3.6-52.727v-0.073c0-16.8 2.2-29.4 6.4-37.8h-113.4c-1.342 5.556-2.338 12.122-2.781 18.84l-0.019 0.36c-0.261 3.524-0.409 7.634-0.409 11.778 0 2.962 0.076 5.907 0.226 8.832l-0.017-0.41c-18.663-17.401-41.395-30.694-66.597-38.289l-1.203-0.311c-22.627-6.956-48.639-10.974-75.586-11h-0.014c-0.764-0.011-1.666-0.018-2.569-0.018-18.098 0-35.598 2.563-52.156 7.345l1.325-0.328c-15.991 4.512-29.851 12.090-41.545 22.122l0.145-0.122c-11.233 9.982-19.792 22.733-24.624 37.192l-0.176 0.608c-5.2 15.2-6.4 33.4-3.8 54.4s9.4 42.2 19.4 57.2c9.524 14.399 21.535 26.346 35.532 35.512l0.468 0.288c13.387 8.662 28.922 15.533 45.512 19.765l1.088 0.235c13.436 3.792 30.801 7.554 48.47 10.41l2.93 0.39c17 2.6 33.8 4.6 50.4 6.2 16.628 1.527 31.69 4.070 46.349 7.643l-2.149-0.443c13 3 23.6 7.6 31.6 13.6s12.6 15 13.6 26.4 0.8 21.8-2.4 28.8c-2.849 6.902-7.542 12.56-13.468 16.517l-0.132 0.083c-6.217 4.011-13.604 6.78-21.543 7.774l-0.257 0.026c-7.897 1.277-17 2.007-26.274 2.007-0.537 0-1.073-0.002-1.609-0.007l0.082 0.001c-22 0-40-4.6-53.8-14.2s-23-25.2-28-47.2h-111.8c4.8 26.2 14.2 48 27.8 65.4 13.475 16.978 29.89 30.968 48.574 41.377l0.826 0.423c18.192 10.038 39.297 17.806 61.619 22.175l1.381 0.225c20.488 4.162 44.053 6.563 68.171 6.6h0.029c21.8-0.005 43.239-1.532 64.222-4.479l-2.422 0.279c20.641-2.809 39.324-8.783 56.401-17.461l-1.001 0.461c15.909-8.108 28.858-20.031 37.967-34.601l0.233-0.399c9-15 12.2-34.8 9-59.6z" />
|
||||||
|
<glyph unicode="" glyph-name="icon-image-telemetry" d="M512 832c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM783.6 48.4c-69.581-69.675-165.757-112.776-272-112.776-212.298 0-384.4 172.102-384.4 384.4s172.102 384.4 384.4 384.4c212.298 0 384.4-172.102 384.4-384.4 0-0.008 0-0.017 0-0.025v0.001c0.001-0.264 0.001-0.575 0.001-0.887 0-105.769-42.964-201.503-112.391-270.703l-0.010-0.010zM704 448l-128-128-192 192-192-192c0-176.731 143.269-320 320-320s320 143.269 320 320v0z" />
|
||||||
</font></defs></svg>
|
</font></defs></svg>
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 57 KiB |
Binary file not shown.
Binary file not shown.
@ -90,7 +90,15 @@ export default {
|
|||||||
this.openmct.objectViews.off('clearData', this.clearData);
|
this.openmct.objectViews.off('clearData', this.clearData);
|
||||||
},
|
},
|
||||||
invokeEditModeHandler(editMode) {
|
invokeEditModeHandler(editMode) {
|
||||||
this.currentView.onEditModeChange(editMode);
|
let edit;
|
||||||
|
|
||||||
|
if (this.currentObject.locked) {
|
||||||
|
edit = false;
|
||||||
|
} else {
|
||||||
|
edit = editMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentView.onEditModeChange(edit);
|
||||||
},
|
},
|
||||||
toggleEditView(editMode) {
|
toggleEditView(editMode) {
|
||||||
this.clear();
|
this.clear();
|
||||||
@ -227,7 +235,11 @@ export default {
|
|||||||
},
|
},
|
||||||
onDragOver(event) {
|
onDragOver(event) {
|
||||||
if (this.hasComposableDomainObject(event)) {
|
if (this.hasComposableDomainObject(event)) {
|
||||||
event.preventDefault();
|
if (this.isEditingAllowed()) {
|
||||||
|
event.preventDefault();
|
||||||
|
} else {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addObjectToParent(event) {
|
addObjectToParent(event) {
|
||||||
@ -283,6 +295,13 @@ export default {
|
|||||||
this.currentView.onClearData();
|
this.currentView.onClearData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
isEditingAllowed() {
|
||||||
|
let browseObject = this.openmct.layout.$refs.browseObject.currentObject,
|
||||||
|
objectPath= this.currentObjectPath || this.objectPath,
|
||||||
|
parentObject = objectPath[1];
|
||||||
|
|
||||||
|
return [browseObject, parentObject, this.currentObject].every(object => !object.locked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,6 @@
|
|||||||
|
|
||||||
&__label {
|
&__label {
|
||||||
margin-left: $interiorMarginSm;
|
margin-left: $interiorMarginSm;
|
||||||
margin-right: $interiorMargin;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,6 @@ export default {
|
|||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
components: {
|
components: {
|
||||||
StylesInspectorView,
|
StylesInspectorView,
|
||||||
// StylesInspectorView,
|
|
||||||
multipane,
|
multipane,
|
||||||
pane,
|
pane,
|
||||||
Elements,
|
Elements,
|
||||||
|
@ -143,7 +143,7 @@
|
|||||||
&__label {
|
&__label {
|
||||||
color: $colorInspectorPropName;
|
color: $colorInspectorPropName;
|
||||||
|
|
||||||
&[title] {
|
&[title]:not([title=""]) {
|
||||||
// When a cell has a title, assume it's helpful text
|
// When a cell has a title, assume it's helpful text
|
||||||
cursor: help;
|
cursor: help;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,17 @@
|
|||||||
/>
|
/>
|
||||||
<div class="l-browse-bar__actions">
|
<div class="l-browse-bar__actions">
|
||||||
<button
|
<button
|
||||||
v-if="isViewEditable & !isEditing"
|
v-if="isViewEditable && !isEditing"
|
||||||
|
:title="lockedOrUnlocked"
|
||||||
|
class="c-button"
|
||||||
|
:class="{
|
||||||
|
'icon-lock': domainObject.locked,
|
||||||
|
'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"
|
class="l-browse-bar__actions__edit c-button c-button--major icon-pencil"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
@click="edit()"
|
@click="edit()"
|
||||||
@ -161,6 +171,13 @@ export default {
|
|||||||
return currentViewProvider.canEdit && currentViewProvider.canEdit(this.domainObject);
|
return currentViewProvider.canEdit && currentViewProvider.canEdit(this.domainObject);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
},
|
||||||
|
lockedOrUnlocked() {
|
||||||
|
if (this.domainObject.locked) {
|
||||||
|
return 'Locked for editing - click to unlock.';
|
||||||
|
} else {
|
||||||
|
return 'Unlocked for editing - click to lock.';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -271,6 +288,9 @@ export default {
|
|||||||
},
|
},
|
||||||
goToParent() {
|
goToParent() {
|
||||||
window.location.hash = this.parentUrl;
|
window.location.hash = this.parentUrl;
|
||||||
|
},
|
||||||
|
toggleLock(flag) {
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'locked', flag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,7 @@
|
|||||||
&__actions,
|
&__actions,
|
||||||
&__end {
|
&__end {
|
||||||
> * + * {
|
> * + * {
|
||||||
margin-left: $interiorMarginSm;
|
margin-left: $interiorMargin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user