Compare commits
29 Commits
joel-condi
...
conditiona
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9e2125bbc | ||
|
|
43a82ec05f | ||
|
|
fe2e29d69b | ||
|
|
5d21a8b6fe | ||
|
|
500ab52476 | ||
|
|
c7b326e3f2 | ||
|
|
e339d743ed | ||
|
|
6ab60ab52e | ||
|
|
55e5c49f6e | ||
|
|
f090f7ffe7 | ||
|
|
94b5617e63 | ||
|
|
41c79c6032 | ||
|
|
83c648cc26 | ||
|
|
76e7fec1a0 | ||
|
|
09bfd80f69 | ||
|
|
8f05c57d1a | ||
|
|
81caa27cba | ||
|
|
74a7ef2565 | ||
|
|
649575fd2d | ||
|
|
625b39d722 | ||
|
|
65f80f4c45 | ||
|
|
02cd3048c8 | ||
|
|
f6d2f9f578 | ||
|
|
408e27c796 | ||
|
|
a7e57c62f4 | ||
|
|
5fcc4eebe1 | ||
|
|
27a09239e3 | ||
|
|
8d86c914a1 | ||
|
|
fab04519c6 |
@@ -28,10 +28,7 @@ import {computeCondition} from "./utils/evaluator";
|
||||
|
||||
/*
|
||||
* conditionConfiguration = {
|
||||
* identifier: {
|
||||
* key: '',
|
||||
* namespace: ''
|
||||
* },
|
||||
* id: uuid,
|
||||
* trigger: 'any'/'all',
|
||||
* criteria: [
|
||||
* {
|
||||
@@ -48,14 +45,14 @@ export default class ConditionClass extends EventEmitter {
|
||||
/**
|
||||
* Manages criteria and emits the result of - true or false - based on criteria evaluated.
|
||||
* @constructor
|
||||
* @param conditionConfiguration: {identifier: {domainObject.identifier},trigger: enum, criteria: Array of {id: uuid, operation: enum, input: Array, metaDataKey: string, key: {domainObject.identifier} }
|
||||
* @param conditionConfiguration: {id: uuid,trigger: enum, criteria: Array of {id: uuid, operation: enum, input: Array, metaDataKey: string, key: {domainObject.identifier} }
|
||||
* @param openmct
|
||||
*/
|
||||
constructor(conditionConfiguration, openmct) {
|
||||
super();
|
||||
|
||||
this.openmct = openmct;
|
||||
this.id = this.openmct.objects.makeKeyString(conditionConfiguration.identifier);
|
||||
this.id = conditionConfiguration.id;
|
||||
this.criteria = [];
|
||||
this.criteriaResults = {};
|
||||
this.result = undefined;
|
||||
@@ -63,16 +60,11 @@ export default class ConditionClass extends EventEmitter {
|
||||
this.createCriteria(conditionConfiguration.configuration.criteria);
|
||||
}
|
||||
this.trigger = conditionConfiguration.configuration.trigger;
|
||||
this.openmct.objects.get(this.id).then(obj => this.observeForChanges(obj));
|
||||
}
|
||||
|
||||
observeForChanges(conditionDO) {
|
||||
this.stopObservingForChanges = this.openmct.objects.observe(conditionDO, '*', this.update.bind(this));
|
||||
}
|
||||
|
||||
update(newDomainObject) {
|
||||
this.updateTrigger(newDomainObject.configuration.trigger);
|
||||
this.updateCriteria(newDomainObject.configuration.criteria);
|
||||
update(conditionConfiguration) {
|
||||
this.updateTrigger(conditionConfiguration.configuration.trigger);
|
||||
this.updateCriteria(conditionConfiguration.configuration.criteria);
|
||||
}
|
||||
|
||||
updateTrigger(trigger) {
|
||||
|
||||
@@ -25,71 +25,43 @@ import uuid from "uuid";
|
||||
import EventEmitter from 'EventEmitter';
|
||||
|
||||
export default class ConditionManager extends EventEmitter {
|
||||
constructor(domainObject, openmct) {
|
||||
constructor(conditionSetDomainObject, openmct) {
|
||||
super();
|
||||
this.openmct = openmct;
|
||||
this.domainObject = domainObject;
|
||||
this.conditionSetDomainObject = conditionSetDomainObject;
|
||||
this.timeAPI = this.openmct.time;
|
||||
this.latestTimestamp = {};
|
||||
this.instantiate = this.openmct.$injector.get('instantiate');
|
||||
this.initialize();
|
||||
|
||||
this.stopObservingForChanges = this.openmct.objects.observe(this.conditionSetDomainObject, '*', (newDomainObject) => {
|
||||
this.conditionSetDomainObject = newDomainObject;
|
||||
});
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.conditionResults = {};
|
||||
this.observeForChanges(this.domainObject);
|
||||
this.conditionCollection = [];
|
||||
if (this.domainObject.configuration.conditionCollection.length) {
|
||||
this.domainObject.configuration.conditionCollection.forEach((conditionConfigurationId, index) => {
|
||||
this.openmct.objects.get(conditionConfigurationId).then((conditionConfiguration) => {
|
||||
this.initCondition(conditionConfiguration, index)
|
||||
});
|
||||
this.conditionClassCollection = [];
|
||||
if (this.conditionSetDomainObject.configuration.conditionCollection.length) {
|
||||
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
|
||||
this.initCondition(conditionConfiguration, index);
|
||||
});
|
||||
} else {
|
||||
this.addCondition(true);
|
||||
}
|
||||
}
|
||||
|
||||
observeForChanges(domainObject) {
|
||||
//TODO: Observe only the conditionCollection property instead of the whole domainObject
|
||||
this.stopObservingForChanges = this.openmct.objects.observe(domainObject, '*', this.handleConditionCollectionUpdated.bind(this));
|
||||
}
|
||||
|
||||
handleConditionCollectionUpdated(newDomainObject) {
|
||||
let oldConditionIdentifiers = this.domainObject.configuration.conditionCollection.map((conditionConfigurationId) => {
|
||||
return this.openmct.objects.makeKeyString(conditionConfigurationId);
|
||||
});
|
||||
let newConditionIdentifiers = newDomainObject.configuration.conditionCollection.map((conditionConfigurationId) => {
|
||||
return this.openmct.objects.makeKeyString(conditionConfigurationId);
|
||||
});
|
||||
|
||||
this.domainObject = newDomainObject;
|
||||
|
||||
//check for removed conditions
|
||||
oldConditionIdentifiers.forEach((identifier, index) => {
|
||||
if (newConditionIdentifiers.indexOf(identifier) < 0) {
|
||||
this.removeCondition(identifier);
|
||||
}
|
||||
});
|
||||
|
||||
let newConditionCount = this.domainObject.configuration.conditionCollection.length - this.conditionCollection.length;
|
||||
|
||||
for (let i = 0; i < newConditionCount; i++) {
|
||||
let conditionConfigurationId = this.domainObject.configuration.conditionCollection[i];
|
||||
this.openmct.objects.get(conditionConfigurationId).then((conditionConfiguration) => {
|
||||
this.initCondition(conditionConfiguration, i);
|
||||
});
|
||||
}
|
||||
|
||||
updateCondition(conditionConfiguration, index) {
|
||||
let condition = this.conditionClassCollection[index];
|
||||
condition.update(conditionConfiguration);
|
||||
this.conditionSetDomainObject.configuration.conditionCollection[index] = conditionConfiguration;
|
||||
this.persistConditions();
|
||||
}
|
||||
|
||||
initCondition(conditionConfiguration, index) {
|
||||
let condition = new Condition(conditionConfiguration, this.openmct);
|
||||
condition.on('conditionResultUpdated', this.handleConditionResult.bind(this));
|
||||
if (index !== undefined) {
|
||||
this.conditionCollection.splice(index + 1, 0, condition);
|
||||
this.conditionClassCollection.splice(index + 1, 0, condition);
|
||||
} else {
|
||||
this.conditionCollection.unshift(condition);
|
||||
this.conditionClassCollection.unshift(condition);
|
||||
}
|
||||
//There are no criteria for a default condition and hence no subscriptions.
|
||||
//Hence the conditionResult must be manually triggered for it.
|
||||
@@ -98,30 +70,25 @@ export default class ConditionManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
createConditionDomainObject(isDefault, conditionConfiguration) {
|
||||
createCondition(conditionConfiguration) {
|
||||
let conditionObj;
|
||||
if (conditionConfiguration) {
|
||||
conditionObj = {
|
||||
...conditionConfiguration,
|
||||
name: `Copy of ${conditionConfiguration.name}`,
|
||||
identifier: {
|
||||
...this.domainObject.identifier,
|
||||
key: uuid()
|
||||
id: uuid(),
|
||||
configuration: {
|
||||
...conditionConfiguration.configuration,
|
||||
name: `Copy of ${conditionConfiguration.configuration.name}`
|
||||
}
|
||||
};
|
||||
} else {
|
||||
conditionObj = {
|
||||
isDefault: isDefault,
|
||||
type: 'condition',
|
||||
identifier: {
|
||||
...this.domainObject.identifier,
|
||||
key: uuid()
|
||||
},
|
||||
id: uuid(),
|
||||
configuration: {
|
||||
name: isDefault ? 'Default' : 'Unnamed Condition',
|
||||
name: 'Unnamed Condition',
|
||||
output: 'false',
|
||||
trigger: 'all',
|
||||
criteria: isDefault ? [] : [{
|
||||
criteria: [{
|
||||
telemetry: '',
|
||||
operation: '',
|
||||
input: [],
|
||||
@@ -131,112 +98,88 @@ export default class ConditionManager extends EventEmitter {
|
||||
summary: ''
|
||||
};
|
||||
}
|
||||
let conditionDomainObjectKeyString = this.openmct.objects.makeKeyString(conditionObj.identifier);
|
||||
let newDomainObject = this.instantiate(conditionObj, conditionDomainObjectKeyString);
|
||||
|
||||
return newDomainObject.useCapability('adapter');
|
||||
return conditionObj;
|
||||
}
|
||||
|
||||
addCondition(isDefault, index) {
|
||||
this.createAndSaveConditionDomainObject(!!isDefault, index);
|
||||
addCondition() {
|
||||
this.createAndSaveCondition();
|
||||
}
|
||||
|
||||
cloneCondition(conditionConfigurationId, index) {
|
||||
this.openmct.objects.get(conditionConfigurationId).then((conditionConfiguration) => {
|
||||
this.createAndSaveConditionDomainObject(false, index, conditionConfiguration);
|
||||
});
|
||||
cloneCondition(conditionConfiguration, index) {
|
||||
this.createAndSaveCondition(index, conditionConfiguration);
|
||||
}
|
||||
|
||||
createAndSaveConditionDomainObject(isDefault, index, conditionConfiguration) {
|
||||
let newConditionDomainObject = this.createConditionDomainObject(isDefault, conditionConfiguration);
|
||||
//persist the condition domain object so that we can do an openmct.objects.get on it and only persist the identifier in the conditionCollection of conditionSet
|
||||
this.openmct.objects.mutate(newConditionDomainObject, 'created', new Date());
|
||||
createAndSaveCondition(index, conditionConfiguration) {
|
||||
let newCondition = this.createCondition(conditionConfiguration);
|
||||
if (index !== undefined) {
|
||||
this.domainObject.configuration.conditionCollection.splice(index + 1, 0, newConditionDomainObject.identifier);
|
||||
this.conditionSetDomainObject.configuration.conditionCollection.splice(index + 1, 0, newCondition);
|
||||
} else {
|
||||
this.domainObject.configuration.conditionCollection.unshift(newConditionDomainObject.identifier);
|
||||
this.conditionSetDomainObject.configuration.conditionCollection.unshift(newCondition);
|
||||
}
|
||||
this.persist();
|
||||
this.initCondition(newCondition, index);
|
||||
this.persistConditions();
|
||||
}
|
||||
|
||||
removeCondition(identifier) {
|
||||
let found = this.findConditionById(identifier);
|
||||
if (found) {
|
||||
let index = found.index;
|
||||
let condition = this.conditionCollection[index];
|
||||
let conditionIdAsString = condition.id;
|
||||
condition.destroyCriteria();
|
||||
condition.off('conditionResultUpdated', this.handleConditionResult.bind(this));
|
||||
this.conditionCollection.splice(index, 1);
|
||||
this.domainObject.configuration.conditionCollection.splice(index, 1);
|
||||
if (this.conditionResults[conditionIdAsString] !== undefined) {
|
||||
delete this.conditionResults[conditionIdAsString];
|
||||
}
|
||||
this.persist();
|
||||
this.handleConditionResult();
|
||||
removeCondition(index) {
|
||||
let condition = this.conditionClassCollection[index];
|
||||
condition.destroyCriteria();
|
||||
condition.off('conditionResultUpdated', this.handleConditionResult.bind(this));
|
||||
this.conditionClassCollection.splice(index, 1);
|
||||
this.conditionSetDomainObject.configuration.conditionCollection.splice(index, 1);
|
||||
if (this.conditionResults[condition.id] !== undefined) {
|
||||
delete this.conditionResults[condition.id];
|
||||
}
|
||||
this.persistConditions();
|
||||
this.handleConditionResult();
|
||||
}
|
||||
|
||||
findConditionById(identifier) {
|
||||
let found;
|
||||
for (let i=0, ii=this.conditionCollection.length; i < ii; i++) {
|
||||
if (this.conditionCollection[i].id === this.openmct.objects.makeKeyString(identifier)) {
|
||||
found = {
|
||||
item: this.conditionCollection[i],
|
||||
index: i
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
findConditionById(id) {
|
||||
return this.conditionClassCollection.find(conditionClass => conditionClass.id === id);
|
||||
}
|
||||
|
||||
//this.$set(this.conditionCollection, reorderEvent.newIndex, oldConditions[reorderEvent.oldIndex]);
|
||||
//this.$set(this.conditionClassCollection, reorderEvent.newIndex, oldConditions[reorderEvent.oldIndex]);
|
||||
reorderConditions(reorderPlan) {
|
||||
let oldConditions = Array.from(this.domainObject.configuration.conditionCollection);
|
||||
let oldConditions = Array.from(this.conditionSetDomainObject.configuration.conditionCollection);
|
||||
let newCollection = [];
|
||||
reorderPlan.forEach((reorderEvent) => {
|
||||
let item = oldConditions[reorderEvent.oldIndex];
|
||||
newCollection.push(item);
|
||||
this.domainObject.configuration.conditionCollection = newCollection;
|
||||
this.conditionSetDomainObject.configuration.conditionCollection = newCollection;
|
||||
});
|
||||
this.persist();
|
||||
this.persistConditions();
|
||||
}
|
||||
|
||||
handleConditionResult(resultObj) {
|
||||
let conditionCollection = this.domainObject.configuration.conditionCollection;
|
||||
let currentConditionIdentifier = conditionCollection[conditionCollection.length-1];
|
||||
const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection;
|
||||
let currentCondition = conditionCollection[conditionCollection.length-1];
|
||||
|
||||
if (resultObj) {
|
||||
let idAsString = this.openmct.objects.makeKeyString(resultObj.id);
|
||||
if (this.findConditionById(idAsString)) {
|
||||
this.conditionResults[idAsString] = resultObj.data.result;
|
||||
const id = resultObj.id;
|
||||
if (this.findConditionById(id)) {
|
||||
this.conditionResults[id] = resultObj.data.result;
|
||||
}
|
||||
this.updateTimestamp(resultObj.data);
|
||||
}
|
||||
|
||||
for (let i = 0; i < conditionCollection.length - 1; i++) {
|
||||
let conditionIdAsString = this.openmct.objects.makeKeyString(conditionCollection[i]);
|
||||
if (this.conditionResults[conditionIdAsString]) {
|
||||
if (this.conditionResults[conditionCollection[i].id]) {
|
||||
//first condition to be true wins
|
||||
currentConditionIdentifier = conditionCollection[i];
|
||||
currentCondition = conditionCollection[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.openmct.objects.get(currentConditionIdentifier).then((obj) => {
|
||||
this.emit('conditionSetResultUpdated',
|
||||
Object.assign(
|
||||
{
|
||||
output: obj.configuration.output,
|
||||
id: this.domainObject.identifier,
|
||||
conditionId: currentConditionIdentifier
|
||||
},
|
||||
this.latestTimestamp
|
||||
)
|
||||
this.emit('conditionSetResultUpdated',
|
||||
Object.assign(
|
||||
{
|
||||
output: currentCondition.configuration.output,
|
||||
id: this.conditionSetDomainObject.identifier,
|
||||
conditionId: currentCondition.id
|
||||
},
|
||||
this.latestTimestamp
|
||||
)
|
||||
});
|
||||
)
|
||||
}
|
||||
|
||||
updateTimestamp(timestamp) {
|
||||
@@ -249,15 +192,15 @@ export default class ConditionManager extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
persist() {
|
||||
this.openmct.objects.mutate(this.domainObject, 'configuration.conditionCollection', this.domainObject.configuration.conditionCollection);
|
||||
persistConditions() {
|
||||
this.openmct.objects.mutate(this.conditionSetDomainObject, 'configuration.conditionCollection', this.conditionSetDomainObject.configuration.conditionCollection);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (typeof this.stopObservingForChanges === 'function') {
|
||||
if(this.stopObservingForChanges) {
|
||||
this.stopObservingForChanges();
|
||||
}
|
||||
this.conditionCollection.forEach((condition) => {
|
||||
this.conditionClassCollection.forEach((condition) => {
|
||||
condition.off('conditionResultUpdated', this.handleConditionResult);
|
||||
condition.destroy();
|
||||
})
|
||||
|
||||
@@ -27,6 +27,13 @@ describe('ConditionManager', () => {
|
||||
let conditionMgr;
|
||||
let mockListener;
|
||||
let openmct = {};
|
||||
let mockCondition = {
|
||||
isDefault: true,
|
||||
id: '1234-5678',
|
||||
configuration: {
|
||||
criteria: []
|
||||
}
|
||||
};
|
||||
let conditionSetDomainObject = {
|
||||
identifier: {
|
||||
namespace: "",
|
||||
@@ -35,15 +42,9 @@ describe('ConditionManager', () => {
|
||||
type: "conditionSet",
|
||||
location: "mine",
|
||||
configuration: {
|
||||
conditionCollection: []
|
||||
}
|
||||
};
|
||||
let mockConditionDomainObject = {
|
||||
isDefault: true,
|
||||
type: 'condition',
|
||||
identifier: {
|
||||
namespace: '',
|
||||
key: '1234-5678'
|
||||
conditionCollection: [
|
||||
mockCondition
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,7 +56,7 @@ describe('ConditionManager', () => {
|
||||
|
||||
let mockDomainObject = {
|
||||
useCapability: function () {
|
||||
return mockConditionDomainObject;
|
||||
return mockCondition;
|
||||
}
|
||||
};
|
||||
mockInstantiate.and.callFake(function () {
|
||||
@@ -78,7 +79,7 @@ describe('ConditionManager', () => {
|
||||
openmct.objects.get.and.returnValues(new Promise(function (resolve, reject) {
|
||||
resolve(conditionSetDomainObject);
|
||||
}), new Promise(function (resolve, reject) {
|
||||
resolve(mockConditionDomainObject);
|
||||
resolve(mockCondition);
|
||||
}));
|
||||
openmct.objects.makeKeyString.and.returnValue(conditionSetDomainObject.identifier.key);
|
||||
openmct.objects.observe.and.returnValue(function () {});
|
||||
@@ -90,9 +91,9 @@ describe('ConditionManager', () => {
|
||||
});
|
||||
|
||||
it('creates a conditionCollection with a default condition', function () {
|
||||
expect(conditionMgr.domainObject.configuration.conditionCollection.length).toEqual(1);
|
||||
let defaultConditionIdentifier = conditionMgr.domainObject.configuration.conditionCollection[0];
|
||||
expect(defaultConditionIdentifier).toEqual(mockConditionDomainObject.identifier);
|
||||
expect(conditionMgr.conditionSetDomainObject.configuration.conditionCollection.length).toEqual(1);
|
||||
let defaultConditionId = conditionMgr.conditionClassCollection[0].id;
|
||||
expect(defaultConditionId).toEqual(mockCondition.id);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
/*****************************************************************************
|
||||
* 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 ConditionManager from './ConditionManager'
|
||||
|
||||
export default class ConditionSetTelemetryProvider {
|
||||
|
||||
@@ -64,6 +64,7 @@ describe("The condition", function () {
|
||||
openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry.values);
|
||||
|
||||
testConditionDefinition = {
|
||||
id: '123-456',
|
||||
configuration: {
|
||||
trigger: TRIGGER.ANY,
|
||||
criteria: [
|
||||
|
||||
@@ -34,7 +34,6 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
|
||||
initialize(conditionalStyleConfiguration) {
|
||||
this.conditionSetIdentifier = conditionalStyleConfiguration.conditionSetIdentifier;
|
||||
this.defaultStyle = conditionalStyleConfiguration.defaultStyle;
|
||||
this.updateConditionStylesMap(conditionalStyleConfiguration.styles || []);
|
||||
}
|
||||
|
||||
@@ -64,15 +63,13 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
updateConditionStylesMap(conditionStyles) {
|
||||
let conditionStyleMap = {};
|
||||
conditionStyles.forEach((conditionStyle) => {
|
||||
const identifier = this.openmct.objects.makeKeyString(conditionStyle.conditionIdentifier);
|
||||
conditionStyleMap[identifier] = conditionStyle.style;
|
||||
conditionStyleMap[conditionStyle.conditionId] = conditionStyle.style;
|
||||
});
|
||||
this.conditionalStyleMap = conditionStyleMap;
|
||||
}
|
||||
|
||||
handleConditionSetResultUpdated(resultData) {
|
||||
let identifier = this.openmct.objects.makeKeyString(resultData.conditionId);
|
||||
let foundStyle = this.conditionalStyleMap[identifier];
|
||||
let foundStyle = this.conditionalStyleMap[resultData.conditionId];
|
||||
if (foundStyle) {
|
||||
if (foundStyle !== this.currentStyle) {
|
||||
this.currentStyle = foundStyle;
|
||||
@@ -91,7 +88,11 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.currentStyle = this.defaultStyle;
|
||||
if (this.currentStyle) {
|
||||
Object.keys(this.currentStyle).forEach(key => {
|
||||
this.currentStyle[key] = 'inherit';
|
||||
});
|
||||
}
|
||||
this.updateDomainObjectStyle();
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
|
||||
@@ -1,178 +1,166 @@
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div v-if="isEditing">
|
||||
<div v-if="domainObject"
|
||||
class="c-c-editui__conditions c-c-container__container c-c__drag-wrapper"
|
||||
:class="['widget-condition', { 'widget-condition--current': currentConditionIdentifier && (currentConditionIdentifier.key === conditionIdentifier.key) }]"
|
||||
>
|
||||
<div class="title-bar">
|
||||
<span class="c-c__menu-hamburger"
|
||||
:class="{ 'is-enabled': !domainObject.isDefault }"
|
||||
:draggable="!domainObject.isDefault"
|
||||
@dragstart="dragStart"
|
||||
@dragstop="dragStop"
|
||||
@dragover.stop
|
||||
></span>
|
||||
<span
|
||||
class="is-enabled flex-elem"
|
||||
:class="['c-c__disclosure-triangle', { 'c-c__disclosure-triangle--expanded': expanded }]"
|
||||
@click="expanded = !expanded"
|
||||
></span>
|
||||
<div class="condition-summary">
|
||||
<span class="condition-name">{{ domainObject.configuration.name }}</span>
|
||||
<!-- TODO: description should be derived from criteria -->
|
||||
<span class="condition-description">{{ domainObject.configuration.name }}</span>
|
||||
</div>
|
||||
<span v-if="!domainObject.isDefault"
|
||||
class="is-enabled c-c__duplicate"
|
||||
@click="cloneCondition"
|
||||
></span>
|
||||
<span v-if="!domainObject.isDefault"
|
||||
class="is-enabled c-c__trash"
|
||||
@click="removeCondition"
|
||||
></span>
|
||||
<div v-if="isEditing"
|
||||
class="c-condition c-condition--edit js-condition-drag-wrapper"
|
||||
>
|
||||
<!-- Edit view -->
|
||||
<div class="c-condition__header">
|
||||
<span class="c-condition__drag-grippy c-grippy c-grippy--vertical-drag"
|
||||
title="Drag to reorder conditions"
|
||||
:class="[{ 'is-enabled': !condition.isDefault }, { 'hide-nice': condition.isDefault }]"
|
||||
:draggable="!condition.isDefault"
|
||||
@dragstart="dragStart"
|
||||
@dragstop="dragStop"
|
||||
@dragover.stop
|
||||
></span>
|
||||
|
||||
<span class="c-condition__disclosure c-disclosure-triangle c-tree__item__view-control is-enabled"
|
||||
:class="{ 'c-disclosure-triangle--expanded': expanded }"
|
||||
@click="expanded = !expanded"
|
||||
></span>
|
||||
|
||||
<span class="c-condition__name">{{ condition.configuration.name }}</span>
|
||||
<!-- TODO: description should be derived from criteria -->
|
||||
<span class="c-condition__summary">
|
||||
Description/summary goes here {{ condition.configuration.description }}
|
||||
</span>
|
||||
|
||||
<div class="c-condition__buttons">
|
||||
<button v-if="!condition.isDefault"
|
||||
class="c-click-icon c-condition__duplicate-button icon-duplicate"
|
||||
title="Duplicate this condition"
|
||||
@click="cloneCondition"
|
||||
></button>
|
||||
|
||||
<button v-if="!condition.isDefault"
|
||||
class="c-click-icon c-condition__delete-button icon-trash"
|
||||
title="Delete this condition"
|
||||
@click="removeCondition"
|
||||
></button>
|
||||
</div>
|
||||
<div v-if="expanded"
|
||||
class="condition-config-edit widget-condition-content c-sw-editui__conditions-wrapper holder widget-conditions-wrapper flex-elem expanded"
|
||||
>
|
||||
<div id="conditionArea"
|
||||
class="c-c-editui__condition widget-conditions"
|
||||
</div>
|
||||
<div v-if="expanded"
|
||||
class="c-condition__definition c-cdef"
|
||||
>
|
||||
<span class="c-cdef__separator c-row-separator"></span>
|
||||
<span class="c-cdef__label">Condition Name</span>
|
||||
<span class="c-cdef__controls">
|
||||
<input v-model="condition.configuration.name"
|
||||
class="t-condition-input__name"
|
||||
type="text"
|
||||
@blur="persist"
|
||||
>
|
||||
<div class="c-c-condition">
|
||||
<div class="c-c-condition__ui l-compact-form l-widget-condition has-local-controls">
|
||||
<div>
|
||||
<ul class="t-widget-condition-config">
|
||||
<li>
|
||||
<label>Condition Name</label>
|
||||
<span class="controls">
|
||||
<input v-model="domainObject.configuration.name"
|
||||
class="t-condition-input__name"
|
||||
type="text"
|
||||
@blur="persist"
|
||||
>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<label>Output</label>
|
||||
<span class="controls">
|
||||
<select v-model="selectedOutputSelection"
|
||||
@change="setOutputValue"
|
||||
>
|
||||
<option value="">- Select Output -</option>
|
||||
<option v-for="option in outputOptions"
|
||||
:key="option"
|
||||
:value="option"
|
||||
>
|
||||
{{ initCap(option) }}
|
||||
</option>
|
||||
</select>
|
||||
<input v-if="selectedOutputSelection === outputOptions[2]"
|
||||
v-model="domainObject.configuration.output"
|
||||
class="t-condition-name-input"
|
||||
type="text"
|
||||
@blur="persist"
|
||||
>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="!domainObject.isDefault"
|
||||
class="widget-condition-content expanded"
|
||||
>
|
||||
<ul class="t-widget-condition-config">
|
||||
<li class="has-local-controls t-condition">
|
||||
<label>Match when</label>
|
||||
<span class="controls">
|
||||
<select v-model="domainObject.configuration.trigger"
|
||||
@change="persist"
|
||||
>
|
||||
<option value="all">all criteria are met</option>
|
||||
<option value="any">any criteria are met</option>
|
||||
</select>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<ul v-if="telemetry.length"
|
||||
class="t-widget-condition-config"
|
||||
>
|
||||
<li v-for="(criterion, index) in domainObject.configuration.criteria"
|
||||
:key="index"
|
||||
class="has-local-controls t-condition"
|
||||
>
|
||||
<Criterion :telemetry="telemetry"
|
||||
:criterion="criterion"
|
||||
:index="index"
|
||||
:trigger="domainObject.configuration.trigger"
|
||||
:is-default="domainObject.configuration.criteria.length === 1"
|
||||
@persist="persist"
|
||||
/>
|
||||
<div class="c-c__criterion-controls">
|
||||
<span class="is-enabled c-c__duplicate"
|
||||
@click="cloneCriterion(index)"
|
||||
></span>
|
||||
<span v-if="!(domainObject.configuration.criteria.length === 1)"
|
||||
class="is-enabled c-c__trash"
|
||||
@click="removeCriterion(index)"
|
||||
></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="holder c-c-button-wrapper align-left">
|
||||
<span class="c-c-label-spacer"></span>
|
||||
<button
|
||||
class="c-c-button c-c-button--minor add-criteria-button"
|
||||
@click="addCriteria"
|
||||
>
|
||||
<span class="c-c-button__label">Add Criteria</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<span class="c-cdef__label">Output</span>
|
||||
<span class="c-cdef__controls">
|
||||
<select v-model="selectedOutputSelection"
|
||||
@change="setOutputValue"
|
||||
>
|
||||
<option value="">- Select Output -</option>
|
||||
<option v-for="option in outputOptions"
|
||||
:key="option"
|
||||
:value="option"
|
||||
>
|
||||
{{ initCap(option) }}
|
||||
</option>
|
||||
</select>
|
||||
<input v-if="selectedOutputSelection === outputOptions[2]"
|
||||
v-model="condition.configuration.output"
|
||||
class="t-condition-name-input"
|
||||
type="text"
|
||||
@blur="persist"
|
||||
>
|
||||
</span>
|
||||
|
||||
<div v-if="!condition.isDefault"
|
||||
class="c-cdef__match-and-criteria"
|
||||
>
|
||||
<span class="c-cdef__separator c-row-separator"></span>
|
||||
<span class="c-cdef__label">Match</span>
|
||||
<span class="c-cdef__controls">
|
||||
<select v-model="condition.configuration.trigger"
|
||||
@change="persist"
|
||||
>
|
||||
<option value="all">when all criteria are met</option>
|
||||
<option value="any">when any criteria are met</option>
|
||||
</select>
|
||||
</span>
|
||||
|
||||
<template v-if="telemetry.length">
|
||||
<div v-for="(criterion, index) in condition.configuration.criteria"
|
||||
:key="index"
|
||||
class="c-cdef__criteria"
|
||||
>
|
||||
<Criterion :telemetry="telemetry"
|
||||
:criterion="criterion"
|
||||
:index="index"
|
||||
:trigger="condition.configuration.trigger"
|
||||
:is-default="condition.configuration.criteria.length === 1"
|
||||
@persist="persist"
|
||||
/>
|
||||
<div class="c-cdef__criteria__buttons">
|
||||
<button class="c-click-icon c-cdef__criteria-duplicate-button icon-duplicate"
|
||||
title="Duplicate this criteria"
|
||||
@click="cloneCriterion(index)"
|
||||
></button>
|
||||
<button v-if="!(condition.configuration.criteria.length === 1)"
|
||||
class="c-click-icon c-cdef__criteria-duplicate-button icon-trash"
|
||||
title="Delete this criteria"
|
||||
@click="removeCriterion(index)"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="c-cdef__separator c-row-separator"></div>
|
||||
<div class="c-cdef__controls"
|
||||
:disabled="!telemetry.length"
|
||||
>
|
||||
<button
|
||||
class="c-cdef__add-criteria-button c-button c-button--labeled icon-plus"
|
||||
@click="addCriteria"
|
||||
>
|
||||
<span class="c-button__label">Add Criteria</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="domainObject"
|
||||
id="conditionArea"
|
||||
class="c-cs-ui__conditions"
|
||||
:class="['widget-condition', { 'widget-condition--current': currentConditionIdentifier && (currentConditionIdentifier.key === conditionIdentifier.key) }]"
|
||||
>
|
||||
<div class="title-bar">
|
||||
<span class="condition-name">
|
||||
{{ domainObject.configuration.name }}
|
||||
</span>
|
||||
<span class="condition-output">
|
||||
Output: {{ domainObject.configuration.output }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="condition-config">
|
||||
<span class="condition-description">
|
||||
{{ domainObject.configuration.description }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else
|
||||
class="c-condition c-condition--browse"
|
||||
>
|
||||
<!-- Browse view -->
|
||||
<div class="c-condition__header">
|
||||
<span class="c-condition__name">
|
||||
{{ condition.configuration.name }}
|
||||
</span>
|
||||
<span class="c-condition__output">
|
||||
Output: {{ condition.configuration.output }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="c-condition__summary">
|
||||
Description/summary goes here {{ condition.configuration.description }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -186,11 +174,7 @@ export default {
|
||||
Criterion
|
||||
},
|
||||
props: {
|
||||
conditionIdentifier: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
currentConditionIdentifier: {
|
||||
condition: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
@@ -210,7 +194,6 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
domainObject: this.domainObject,
|
||||
currentCriteria: this.currentCriteria,
|
||||
expanded: true,
|
||||
trigger: 'all',
|
||||
@@ -223,17 +206,11 @@ export default {
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.objects.get(this.conditionIdentifier).then((domainObject => {
|
||||
this.domainObject = domainObject;
|
||||
this.initialize();
|
||||
}));
|
||||
this.setOutputSelection();
|
||||
},
|
||||
methods: {
|
||||
initialize() {
|
||||
this.setOutputSelection();
|
||||
},
|
||||
setOutputSelection() {
|
||||
let conditionOutput = this.domainObject.configuration.output;
|
||||
let conditionOutput = this.condition.configuration.output;
|
||||
if (conditionOutput) {
|
||||
if (conditionOutput !== 'false' && conditionOutput !== 'true') {
|
||||
this.selectedOutputSelection = 'string';
|
||||
@@ -244,9 +221,9 @@ export default {
|
||||
},
|
||||
setOutputValue() {
|
||||
if (this.selectedOutputSelection === 'string') {
|
||||
this.domainObject.configuration.output = '';
|
||||
this.condition.configuration.output = '';
|
||||
} else {
|
||||
this.domainObject.configuration.output = this.selectedOutputSelection;
|
||||
this.condition.configuration.output = this.selectedOutputSelection;
|
||||
}
|
||||
this.persist();
|
||||
},
|
||||
@@ -257,12 +234,12 @@ export default {
|
||||
input: '',
|
||||
metadata: ''
|
||||
};
|
||||
this.domainObject.configuration.criteria.push(criteriaObject);
|
||||
this.condition.configuration.criteria.push(criteriaObject);
|
||||
},
|
||||
dragStart(e) {
|
||||
e.dataTransfer.setData('dragging', e.target); // required for FF to initiate drag
|
||||
e.dataTransfer.effectAllowed = "copyMove";
|
||||
e.dataTransfer.setDragImage(e.target.closest('.c-c-container__container'), 0, 0);
|
||||
e.dataTransfer.setDragImage(e.target.closest('.js-condition-drag-wrapper'), 0, 0);
|
||||
this.$emit('setMoveIndex', this.conditionIndex);
|
||||
},
|
||||
dragStop(e) {
|
||||
@@ -271,35 +248,36 @@ export default {
|
||||
destroy() {
|
||||
},
|
||||
removeCondition(ev) {
|
||||
this.$emit('removeCondition', this.conditionIdentifier);
|
||||
this.$emit('removeCondition', this.conditionIndex);
|
||||
},
|
||||
cloneCondition(ev) {
|
||||
this.$emit('cloneCondition', {
|
||||
identifier: this.conditionIdentifier,
|
||||
index: Number(ev.target.closest('.widget-condition').getAttribute('data-condition-index'))
|
||||
condition: this.condition,
|
||||
index: this.conditionIndex
|
||||
});
|
||||
},
|
||||
removeCriterion(index) {
|
||||
this.domainObject.configuration.criteria.splice(index, 1);
|
||||
this.condition.configuration.criteria.splice(index, 1);
|
||||
this.persist()
|
||||
},
|
||||
cloneCriterion(index) {
|
||||
const clonedCriterion = {...this.domainObject.configuration.criteria[index]};
|
||||
this.domainObject.configuration.criteria.splice(index + 1, 0, clonedCriterion);
|
||||
const clonedCriterion = {...this.condition.configuration.criteria[index]};
|
||||
this.condition.configuration.criteria.splice(index + 1, 0, clonedCriterion);
|
||||
this.persist()
|
||||
},
|
||||
hasTelemetry(identifier) {
|
||||
// TODO: check parent domainObject.composition.hasTelemetry
|
||||
// TODO: check parent condition.composition.hasTelemetry
|
||||
return this.currentCriteria && identifier;
|
||||
},
|
||||
persist() {
|
||||
this.openmct.objects.mutate(this.domainObject, 'configuration', this.domainObject.configuration);
|
||||
this.$emit('updateCondition', {
|
||||
condition: this.condition,
|
||||
index: this.conditionIndex
|
||||
});
|
||||
},
|
||||
initCap: function (string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1)
|
||||
initCap: function (str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@@ -22,60 +22,59 @@
|
||||
|
||||
<template>
|
||||
<section id="conditionCollection"
|
||||
class="c-cs__ui_section"
|
||||
class="c-cs__conditions"
|
||||
:class="{ 'is-expanded': expanded }"
|
||||
>
|
||||
<div class="c-cs__ui__header">
|
||||
<span class="c-cs__ui__header-label">Conditions</span>
|
||||
<div class="c-cs__header c-section__header">
|
||||
<span
|
||||
class="is-enabled flex-elem"
|
||||
:class="['c-cs__disclosure-triangle', { 'c-cs__disclosure-triangle--expanded': expanded }]"
|
||||
class="c-disclosure-triangle c-tree__item__view-control is-enabled"
|
||||
:class="{ 'c-disclosure-triangle--expanded': expanded }"
|
||||
@click="expanded = !expanded"
|
||||
></span>
|
||||
<div class="c-cs__header-label c-section__label">Conditions</div>
|
||||
</div>
|
||||
<div v-if="expanded"
|
||||
class="c-cs__ui_content"
|
||||
class="c-cs__content"
|
||||
>
|
||||
<div v-show="isEditing"
|
||||
class="help"
|
||||
class="hint"
|
||||
:class="{ 's-status-icon-warning-lo': !telemetryObjs.length }"
|
||||
>
|
||||
<span v-if="!telemetryObjs.length">Drag telemetry into Condition Set in order to add conditions.</span>
|
||||
<span v-else>The first condition to match is the one that wins. Drag conditions to rearrange.</span>
|
||||
<template v-if="!telemetryObjs.length">Drag telemetry into this Condition Set to configure Conditions and add criteria.</template>
|
||||
<template v-else>The first condition to match is the one that is applied. Drag conditions to reorder.</template>
|
||||
</div>
|
||||
<div class="holder add-condition-button-wrapper align-left">
|
||||
<button
|
||||
v-show="isEditing"
|
||||
id="addCondition"
|
||||
class="c-cs-button c-cs-button--major add-condition-button"
|
||||
:class="{ 'is-disabled': !telemetryObjs.length}"
|
||||
:disabled="!telemetryObjs.length"
|
||||
@click="addCondition"
|
||||
|
||||
<button
|
||||
v-show="isEditing"
|
||||
id="addCondition"
|
||||
class="c-button c-button--major icon-plus labeled"
|
||||
@click="addCondition"
|
||||
>
|
||||
<span class="c-cs-button__label">Add Condition</span>
|
||||
</button>
|
||||
|
||||
<div class="c-cs__conditions-h">
|
||||
<div v-for="(condition, index) in conditionCollection"
|
||||
:key="condition.id"
|
||||
class="c-condition-h"
|
||||
>
|
||||
<span class="c-cs-button__label">Add Condition</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="c-c__condition-collection">
|
||||
<ul class="c-c__container-holder">
|
||||
<li v-for="(conditionIdentifier, index) in conditionCollection"
|
||||
:key="conditionIdentifier.key"
|
||||
>
|
||||
<div v-if="isEditing"
|
||||
class="c-c__drag-ghost"
|
||||
@drop.prevent="dropCondition"
|
||||
@dragenter="dragEnter"
|
||||
@dragleave="dragLeave"
|
||||
@dragover.prevent
|
||||
></div>
|
||||
<Condition :condition-identifier="conditionIdentifier"
|
||||
:current-condition-identifier="currentConditionIdentifier"
|
||||
:condition-index="index"
|
||||
:telemetry="telemetryObjs"
|
||||
:is-editing="isEditing"
|
||||
@removeCondition="removeCondition"
|
||||
@cloneCondition="cloneCondition"
|
||||
@setMoveIndex="setMoveIndex"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="isEditing"
|
||||
class="c-c__drag-ghost"
|
||||
@drop.prevent="dropCondition"
|
||||
@dragenter="dragEnter"
|
||||
@dragleave="dragLeave"
|
||||
@dragover.prevent
|
||||
></div>
|
||||
<Condition :condition="condition"
|
||||
:condition-index="index"
|
||||
:telemetry="telemetryObjs"
|
||||
:is-editing="isEditing"
|
||||
@updateCondition="updateCondition"
|
||||
@removeCondition="removeCondition"
|
||||
@cloneCondition="cloneCondition"
|
||||
@setMoveIndex="setMoveIndex"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -96,11 +95,9 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
expanded: true,
|
||||
parentKeyString: this.openmct.objects.makeKeyString(this.domainObject.identifier),
|
||||
conditionCollection: [],
|
||||
conditionResults: {},
|
||||
conditions: [],
|
||||
currentConditionIdentifier: this.currentConditionIdentifier || {},
|
||||
telemetryObjs: [],
|
||||
moveIndex: Number,
|
||||
isDragging: false
|
||||
@@ -112,7 +109,7 @@ export default {
|
||||
if(this.conditionManager) {
|
||||
this.conditionManager.destroy();
|
||||
}
|
||||
if (typeof this.stopObservingForChanges === 'function') {
|
||||
if (this.stopObservingForChanges) {
|
||||
this.stopObservingForChanges();
|
||||
}
|
||||
},
|
||||
@@ -122,13 +119,16 @@ export default {
|
||||
this.composition.on('remove', this.removeTelemetryObject);
|
||||
this.composition.load();
|
||||
this.conditionCollection = this.domainObject.configuration.conditionCollection;
|
||||
this.conditionManager = new ConditionManager(this.domainObject, this.openmct);
|
||||
this.observeForChanges();
|
||||
this.conditionManager = new ConditionManager(this.domainObject, this.openmct);
|
||||
this.conditionManager.on('conditionSetResultUpdated', (data) => {
|
||||
this.$emit('conditionSetResultUpdated', data);
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
observeForChanges() {
|
||||
this.stopObservingForChanges = this.openmct.objects.observe(this.domainObject, '*', (newDomainObject) => {
|
||||
this.conditionCollection = newDomainObject.configuration.conditionCollection;
|
||||
this.stopObservingForChanges = this.openmct.objects.observe(this.domainObject, 'configuration.conditionCollection', (newConditionCollection) => {
|
||||
this.conditionCollection = newConditionCollection;
|
||||
});
|
||||
},
|
||||
setMoveIndex(index) {
|
||||
@@ -190,20 +190,20 @@ export default {
|
||||
this.telemetryObjs.splice(index, 1);
|
||||
}
|
||||
},
|
||||
addCondition(event, isDefault, index) {
|
||||
this.conditionManager.addCondition(!!isDefault, index);
|
||||
addCondition() {
|
||||
this.conditionManager.addCondition();
|
||||
},
|
||||
updateCurrentCondition(identifier) {
|
||||
this.currentConditionIdentifier = identifier;
|
||||
updateCondition(data) {
|
||||
this.conditionManager.updateCondition(data.condition, data.index);
|
||||
},
|
||||
removeCondition(identifier) {
|
||||
this.conditionManager.removeCondition(identifier);
|
||||
removeCondition(index) {
|
||||
this.conditionManager.removeCondition(index);
|
||||
},
|
||||
reorder(reorderPlan) {
|
||||
this.conditionManager.reorderConditions(reorderPlan);
|
||||
},
|
||||
cloneCondition(condition) {
|
||||
this.conditionManager.cloneCondition(condition.identifier, condition.index);
|
||||
cloneCondition(data) {
|
||||
this.conditionManager.cloneCondition(data.condition, data.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,24 +21,21 @@
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="c-cs-edit w-condition-set">
|
||||
<div class="c-sw-edit__ui holder">
|
||||
<section id="current-output">
|
||||
<div class="c-cs__ui__header">
|
||||
<span class="c-cs__ui__header-label">Current Output</span>
|
||||
</div>
|
||||
<div class="c-cs__ui_content">
|
||||
<span v-if="currentConditionOutput"
|
||||
class="current-output"
|
||||
>
|
||||
{{ currentConditionOutput }}
|
||||
</span>
|
||||
<span v-else>No output selected</span>
|
||||
</div>
|
||||
</section>
|
||||
<TestData :is-editing="isEditing" />
|
||||
<ConditionCollection :is-editing="isEditing" />
|
||||
</div>
|
||||
<div class="c-cs">
|
||||
<section class="c-cs__current-output c-section">
|
||||
<div class="c-cs__header c-section__header">
|
||||
<span class="c-cs__header-label c-section__label">Current Output</span>
|
||||
</div>
|
||||
<div class="c-cs__content c-cs__current-output-value">
|
||||
<template v-if="currentConditionOutput">
|
||||
{{ currentConditionOutput }}
|
||||
</template>
|
||||
<template v-else>No output selected</template>
|
||||
</div>
|
||||
</section>
|
||||
<TestData :is-editing="isEditing" />
|
||||
<ConditionCollection :is-editing="isEditing"
|
||||
@conditionSetResultUpdated="updateCurrentOutput" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -62,7 +59,6 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.conditionSetIdentifier = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
this.provideTelemetry();
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
@@ -72,10 +68,6 @@ export default {
|
||||
methods: {
|
||||
updateCurrentOutput(currentConditionResult) {
|
||||
this.currentConditionOutput = currentConditionResult.output;
|
||||
},
|
||||
provideTelemetry() {
|
||||
this.stopProvidingTelemetry = this.openmct.telemetry
|
||||
.subscribe(this.domainObject, output => { this.updateCurrentOutput(output); });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<label>{{ setRowLabel }}</label>
|
||||
<span class="t-configuration">
|
||||
<span class="controls">
|
||||
<div class="u-contents">
|
||||
<div class="c-cdef__separator c-row-separator"></div>
|
||||
<span class="c-cdef__label">{{ setRowLabel }}</span>
|
||||
<span class="c-cdef__controls">
|
||||
<span class="c-cdef__control">
|
||||
<select v-model="criterion.telemetry"
|
||||
@change="updateMetadataOptions"
|
||||
>
|
||||
@@ -16,7 +17,7 @@
|
||||
</select>
|
||||
</span>
|
||||
<span v-if="criterion.telemetry"
|
||||
class="controls"
|
||||
class="c-cdef__control"
|
||||
>
|
||||
<select v-model="criterion.metadata"
|
||||
@change="updateOperations"
|
||||
@@ -31,7 +32,7 @@
|
||||
</select>
|
||||
</span>
|
||||
<span v-if="criterion.telemetry && criterion.metadata"
|
||||
class="controls"
|
||||
class="c-cdef__control"
|
||||
>
|
||||
<select v-model="criterion.operation"
|
||||
@change="updateOperationInputVisibility"
|
||||
@@ -46,11 +47,12 @@
|
||||
</select>
|
||||
<span v-for="(item, inputIndex) in inputCount"
|
||||
:key="inputIndex"
|
||||
class="c-cdef__control__inputs"
|
||||
>
|
||||
<input v-model="criterion.input[inputIndex]"
|
||||
class="t-condition-name-input"
|
||||
class="c-cdef__control__input"
|
||||
type="text"
|
||||
@blur="persist"
|
||||
@change="persist"
|
||||
>
|
||||
<span v-if="inputIndex < inputCount-1">and</span>
|
||||
</span>
|
||||
|
||||
0
src/plugins/condition/components/CurrentOutput.vue
Normal file
0
src/plugins/condition/components/CurrentOutput.vue
Normal file
@@ -23,18 +23,19 @@
|
||||
<template>
|
||||
<section v-show="isEditing"
|
||||
id="test-data"
|
||||
class="test-data"
|
||||
class="c-cs__test-data"
|
||||
:class="{ 'is-expanded': expanded }"
|
||||
>
|
||||
<div class="c-cs__ui__header">
|
||||
<span class="c-cs__ui__header-label">Test Data</span>
|
||||
<div class="c-cs__header c-section__header">
|
||||
<span
|
||||
class="is-enabled flex-elem"
|
||||
:class="['c-cs__disclosure-triangle', { 'c-cs__disclosure-triangle--expanded': expanded }]"
|
||||
class="c-disclosure-triangle c-tree__item__view-control is-enabled"
|
||||
:class="{ 'c-disclosure-triangle--expanded': expanded }"
|
||||
@click="expanded = !expanded"
|
||||
></span>
|
||||
<div class="c-cs__header-label c-section__label">Test Data</div>
|
||||
</div>
|
||||
<div v-if="expanded"
|
||||
class="c-cs__ui_content"
|
||||
class="c-cs__content"
|
||||
>
|
||||
<label class="c-toggle-switch">
|
||||
<input
|
||||
@@ -43,32 +44,27 @@
|
||||
@change="applyTestData"
|
||||
>
|
||||
<span class="c-toggle-switch__slider"></span>
|
||||
<span>Apply Test Data</span>
|
||||
<span class="c-toggle-switch__label">Apply Test Data</span>
|
||||
</label>
|
||||
<div class="t-test-data-config">
|
||||
<div class="c-cs-editui__conditions widget-condition">
|
||||
<form>
|
||||
<label>
|
||||
<span>Set</span>
|
||||
<select>
|
||||
<option>- Select Input -</option>
|
||||
</select>
|
||||
</label>
|
||||
<span class="is-enabled flex-elem c-cs__duplicate"></span>
|
||||
<span class="is-enabled flex-elem c-cs__trash"></span>
|
||||
</form>
|
||||
</div>
|
||||
<div class="c-cs-editui__conditions widget-condition">
|
||||
<form>
|
||||
<label>
|
||||
<span>Set</span>
|
||||
<select>
|
||||
<option>- Select Input -</option>
|
||||
</select>
|
||||
</label>
|
||||
<span class="is-enabled c-cs__duplicate"></span>
|
||||
<span class="is-enabled c-cs__trash"></span>
|
||||
</form>
|
||||
<div class="c-cs-test-h">
|
||||
<div v-for="n in 5"
|
||||
:key="n"
|
||||
class="c-test-datum"
|
||||
>
|
||||
<span class="c-test-datum__label">Set</span>
|
||||
<div class="c-test-datum__controls">
|
||||
<select>
|
||||
<option>- Select Input -</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="c-test-datum__buttons">
|
||||
<button class="c-click-icon c-test-data__duplicate-button icon-duplicate"
|
||||
title="Duplicate this test data value"
|
||||
></button>
|
||||
<button class="c-click-icon c-test-data__delete-button icon-trash"
|
||||
title="Delete this test data value"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,155 +1,89 @@
|
||||
.c-cs-edit {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
section {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.c-cs__ui__header {
|
||||
background-color: #D0D1D3;
|
||||
padding: 0.4em 0.6em;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
color: #7C7D80;
|
||||
.c-cs {
|
||||
display: flex;
|
||||
justify-content: stretch;
|
||||
align-items: center;
|
||||
}
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.c-cs__ui__header-label {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
&__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
|
||||
.c-cs__ui_content {
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
.c-cs-ui__label {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.c-cs__ui_content .help {
|
||||
font-style: italic;
|
||||
padding: 0.4em 0;
|
||||
}
|
||||
|
||||
.current-output {
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
margin: 0.4em 0.6em;
|
||||
}
|
||||
|
||||
.condition-output {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.condition-description {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.checkbox.custom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 0.6em;
|
||||
}
|
||||
.checkbox.custom span {
|
||||
display: inline-block;
|
||||
margin-left: 0.6em;
|
||||
}
|
||||
|
||||
.t-test-data-config {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.c-c__condition-collection.is-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.widget-condition form {
|
||||
padding: 0.5em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: stretch;
|
||||
}
|
||||
|
||||
.widget-condition form label {
|
||||
flex-grow: 1;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.widget-condition form input {
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
.c-cs-button[class*="--major"],
|
||||
.c-cs-button[class*='is-active'],
|
||||
.c-cs-button--menu[class*="--major"],
|
||||
.c-cs-button--menu[class*='is-active'] {
|
||||
border: solid 1px #0B427C;
|
||||
background-color: #4778A3;
|
||||
padding: 0.2em 0.6em;
|
||||
margin: 0.4em;
|
||||
font-weight: bold;
|
||||
color: #eee;
|
||||
border-radius: 6px;
|
||||
|
||||
&.is-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.c-cs__disclosure-triangle,
|
||||
.c-cs__menu-hamburger,
|
||||
.c-cs__duplicate,
|
||||
.c-cs__trash {
|
||||
$d: 8px;
|
||||
color: $colorDisclosureCtrl;
|
||||
width: $d;
|
||||
visibility: hidden;
|
||||
|
||||
&.is-enabled {
|
||||
cursor: pointer;
|
||||
visibility: visible;
|
||||
|
||||
&:hover {
|
||||
color: $colorDisclosureCtrlHov;
|
||||
> * {
|
||||
flex: 0 0 auto;
|
||||
overflow: hidden;
|
||||
+ * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
&:before {
|
||||
$s: .5;
|
||||
display: block;
|
||||
font-family: symbolsfont;
|
||||
font-size: 1rem * $s;
|
||||
.c-button {
|
||||
align-self: start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-cs__disclosure-triangle {
|
||||
&:before {
|
||||
content: $glyph-icon-arrow-right;
|
||||
.is-editing & {
|
||||
// Add some space to kick away from blue editing border indication
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
|
||||
&--expanded {
|
||||
&:before {
|
||||
transform: rotate(90deg);
|
||||
section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__conditions-h {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
padding-right: $interiorMarginSm;
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-cs__duplicate {
|
||||
margin-right: 0.3em;
|
||||
&:before {
|
||||
content: $glyph-icon-duplicate;
|
||||
&__conditions {
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.hint {
|
||||
padding: $interiorMarginSm;
|
||||
}
|
||||
|
||||
/************************** SPECIFIC ITEMS */
|
||||
&__current-output-value {
|
||||
font-size: 1.25em;
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
.c-cs__trash {
|
||||
&:before {
|
||||
content: $glyph-icon-trash;
|
||||
/***************************** TEST DATA */
|
||||
.c-cs-test-h {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
padding-right: $interiorMarginSm;
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.c-test-datum {
|
||||
> * {
|
||||
flex: 0 0 auto;
|
||||
+ * {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
&__controls {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,208 +1,120 @@
|
||||
.widget-condition {
|
||||
background-color: #eee;
|
||||
margin: 0 0 0.33em;
|
||||
border-radius: 3px;
|
||||
|
||||
&--current {
|
||||
background-color: #DEECFA;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.c-c-editui__conditions.widget-condition {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.c-c-button-wrapper {
|
||||
border-top: solid 1px #ccc;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.c-c-label-spacer {
|
||||
display: inline-block;
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.c-c-button[class*="--minor"],
|
||||
.c-c-button[class*='is-active'],
|
||||
.c-c-button--menu[class*="--minor"],
|
||||
.c-c-button--menu[class*='is-active'] {
|
||||
border: solid 1px #666;
|
||||
background-color: #fff;
|
||||
padding: 0.1em 0.4em;
|
||||
margin: 0.4em;
|
||||
font-weight: normal;
|
||||
color: #666;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.title-bar {
|
||||
.c-condition,
|
||||
.c-test-datum {
|
||||
@include discreteItem();
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: stretch;
|
||||
padding: 0.4em 0;
|
||||
padding: $interiorMargin;
|
||||
|
||||
&--edit {
|
||||
line-height: 160%; // For layout when inputs wrap, like in criteria
|
||||
}
|
||||
}
|
||||
|
||||
.title-bar span {
|
||||
margin-right: 0.6em;
|
||||
}
|
||||
.c-condition {
|
||||
flex-direction: column;
|
||||
min-width: 400px;
|
||||
|
||||
.title-bar span.c-c__duplicate,
|
||||
.title-bar span.c-c__trash{
|
||||
margin-right: 0;
|
||||
margin-left: 0.3em;
|
||||
}
|
||||
|
||||
.widget-condition > div {
|
||||
margin: 0 0.4em;
|
||||
}
|
||||
|
||||
.condition-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.condition-summary .condition-description {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.condition-summary {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.condition-config {
|
||||
padding: 0.3em 0;
|
||||
}
|
||||
|
||||
.widget-condition form label {
|
||||
flex-grow: 1;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.l-widget-condition {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.l-compact-form ul li {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.widget-condition-content.expanded {
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.widget-condition-content.expanded ul li {
|
||||
border-top: solid 1px #ccc;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.l-compact-form ul li .controls {
|
||||
display: inline-flex;
|
||||
flex-grow: inherit;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.l-compact-form ul li > label {
|
||||
display: block;
|
||||
width: 90px;
|
||||
min-width: 90px;
|
||||
text-align: right;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.l-compact-form ul li .controls input[type="text"],
|
||||
.l-compact-form ul li .controls input[type="search"],
|
||||
.l-compact-form ul li .controls input[type="number"],
|
||||
.l-compact-form ul li .controls button,
|
||||
.l-compact-form ul li .controls select {
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.condition-config-edit {
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
|
||||
.c-c__disclosure-triangle,
|
||||
.c-c__menu-hamburger,
|
||||
.c-c__duplicate,
|
||||
.c-c__trash {
|
||||
$d: 8px;
|
||||
color: $colorDisclosureCtrl;
|
||||
width: $d;
|
||||
visibility: hidden;
|
||||
|
||||
&.is-enabled {
|
||||
cursor: pointer;
|
||||
visibility: visible;
|
||||
|
||||
&:hover {
|
||||
color: $colorDisclosureCtrlHov;
|
||||
}
|
||||
|
||||
&:before {
|
||||
$s: .5;
|
||||
display: block;
|
||||
font-family: symbolsfont;
|
||||
font-size: 1rem * $s;
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
&--browse {
|
||||
.c-condition__summary {
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
padding-top: $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-c__disclosure-triangle {
|
||||
&:before {
|
||||
content: $glyph-icon-arrow-right;
|
||||
}
|
||||
/***************************** HEADER */
|
||||
&__header {
|
||||
$h: 22px;
|
||||
display: flex;
|
||||
align-items: start;
|
||||
align-content: stretch;
|
||||
overflow: hidden;
|
||||
min-height: $h;
|
||||
line-height: $h;
|
||||
|
||||
&--expanded {
|
||||
&:before {
|
||||
transform: rotate(90deg);
|
||||
> * {
|
||||
flex: 0 0 auto;
|
||||
+ * {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.c-c__menu-hamburger {
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: -webkit-grabbing;
|
||||
&__drag-grippy {
|
||||
transform: translateY(50%);
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: $glyph-icon-menu-hamburger;
|
||||
&__name {
|
||||
font-weight: bold;
|
||||
align-self: baseline; // Fixes bold line-height offset problem
|
||||
}
|
||||
|
||||
&__output,
|
||||
&__summary {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.c-c__duplicate {
|
||||
&:before {
|
||||
content: $glyph-icon-duplicate;
|
||||
}
|
||||
}
|
||||
/***************************** CONDITION DEFINITION, EDITING */
|
||||
.c-cdef {
|
||||
display: grid;
|
||||
grid-row-gap: $interiorMarginSm;
|
||||
grid-column-gap: $interiorMargin;
|
||||
grid-auto-columns: min-content 1fr max-content;
|
||||
align-items: start;
|
||||
min-width: 150px;
|
||||
margin-left: 29px;
|
||||
overflow: hidden;
|
||||
|
||||
.c-c__trash {
|
||||
&:before {
|
||||
content: $glyph-icon-trash;
|
||||
&__criteria,
|
||||
&__match-and-criteria {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
&__label {
|
||||
grid-column: 1;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__separator {
|
||||
grid-column: 1 / span 3;
|
||||
}
|
||||
|
||||
&__controls {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
//line-height: 200%;
|
||||
grid-column: 2;
|
||||
|
||||
> * > * {
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
grid-column: 3;
|
||||
}
|
||||
}
|
||||
|
||||
.c-c__drag-ghost {
|
||||
width: 100%;
|
||||
min-height: 0.33em;
|
||||
min-height: $interiorMarginSm;
|
||||
|
||||
//&:before {
|
||||
// @include test();
|
||||
// content: '';
|
||||
// display: block;
|
||||
// z-index: 2;
|
||||
//}
|
||||
|
||||
&.dragging {
|
||||
min-height: 2em;
|
||||
border: solid 1px blue;
|
||||
min-height: 5em;
|
||||
//border: solid 1px blue;
|
||||
background-color: lightblue;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.c-c__criterion-controls {
|
||||
width: 28px;
|
||||
|
||||
.c-c__duplicate,
|
||||
.c-c__trash {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,34 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="condition"
|
||||
<div v-if="conditionStyle"
|
||||
class="holder c-c-button-wrapper align-left"
|
||||
>
|
||||
<div>{{ condition.configuration.name }}</div>
|
||||
<div>{{ conditionStyle.conditionName }}</div>
|
||||
<span :style="conditionStyle.style">ABC</span>
|
||||
<toolbar-color-picker v-if="conditionStyle.style.border"
|
||||
:options="borderColorOption"
|
||||
@change="updateStyleValue"
|
||||
/>
|
||||
<toolbar-color-picker v-if="conditionStyle.style.backgroundColor"
|
||||
:options="backgroundColorOption"
|
||||
@change="updateStyleValue"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import ToolbarColorPicker from "@/ui/toolbar/components/toolbar-color-picker.vue";
|
||||
export default {
|
||||
components: {
|
||||
ToolbarColorPicker
|
||||
},
|
||||
inject: [
|
||||
'openmct'
|
||||
],
|
||||
props: {
|
||||
conditionIdentifier: {
|
||||
conditionStyle: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
@@ -27,12 +38,32 @@ export default {
|
||||
condition: null
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
computed: {
|
||||
borderColorOption() {
|
||||
return {
|
||||
icon: 'icon-line-horz',
|
||||
title: 'Set border color',
|
||||
value: this.conditionStyle.style.border.replace('1px solid ', ''),
|
||||
property: 'border'
|
||||
}
|
||||
},
|
||||
backgroundColorOption() {
|
||||
return {
|
||||
icon: 'icon-paint-bucket',
|
||||
title: 'Set background color',
|
||||
value: this.conditionStyle.style.backgroundColor,
|
||||
property: 'backgroundColor'
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.objects.get(this.conditionIdentifier).then((conditionDomainObject) => {
|
||||
this.condition = conditionDomainObject;
|
||||
});
|
||||
methods: {
|
||||
updateStyleValue(value, item) {
|
||||
if (item.property === 'border') {
|
||||
value = '1px solid ' + value;
|
||||
}
|
||||
this.conditionStyle.style[item.property] = value;
|
||||
this.$emit('persist', this.conditionStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="!conditionalStyles.length"
|
||||
class="holder c-c-button-wrapper align-left">
|
||||
class="holder c-c-button-wrapper align-left"
|
||||
>
|
||||
<button
|
||||
class="c-c-button c-c-button--minor add-criteria-button"
|
||||
@click="addConditionSet">
|
||||
@click="addConditionSet"
|
||||
>
|
||||
<span class="c-c-button__label">Use conditional styling</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -12,15 +14,18 @@
|
||||
<div class="holder c-c-button-wrapper align-left">
|
||||
<button
|
||||
class="c-c-button c-c-button--minor add-criteria-button"
|
||||
@click="removeConditionSet">
|
||||
@click="removeConditionSet"
|
||||
>
|
||||
<span class="c-c-button__label">Remove conditional styling</span>
|
||||
</button>
|
||||
</div>
|
||||
<ul>
|
||||
<li v-for="conditionStyle in conditionalStyles"
|
||||
:key="conditionStyle.conditionIdentifier.key">
|
||||
<conditional-style :condition-identifier="conditionStyle.conditionIdentifier"
|
||||
:condition-style="conditionStyle.style"/>
|
||||
:key="conditionStyle.conditionId"
|
||||
>
|
||||
<conditional-style :condition-style="conditionStyle"
|
||||
@persist="updateConditionalStyle"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -36,21 +41,33 @@ export default {
|
||||
},
|
||||
inject: [
|
||||
'openmct',
|
||||
'domainObject',
|
||||
'layoutItem'
|
||||
'domainObject'
|
||||
],
|
||||
props: {
|
||||
itemId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
initialStyles: {
|
||||
type: Object,
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
conditionalStyles: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.layoutItem) {
|
||||
//TODO: Handle layout items
|
||||
}
|
||||
if (this.domainObject.configuration) {
|
||||
this.defautStyle = this.domainObject.configuration.defaultStyle;
|
||||
if (this.domainObject.configuration.conditionalStyle) {
|
||||
if (this.domainObject.configuration && this.domainObject.configuration.conditionalStyle) {
|
||||
if (this.itemId) {
|
||||
let conditionalStyle = this.domainObject.configuration.conditionalStyle[this.itemId];
|
||||
if (conditionalStyle) {
|
||||
this.conditionalStyles = conditionalStyle.styles || [];
|
||||
}
|
||||
} else {
|
||||
this.conditionalStyles = this.domainObject.configuration.conditionalStyle.styles || [];
|
||||
}
|
||||
}
|
||||
@@ -60,48 +77,86 @@ export default {
|
||||
//TODO: this.conditionSetIdentifier will be set by the UI before calling this
|
||||
this.conditionSetIdentifier = {
|
||||
namespace: '',
|
||||
key: 'bb0f61ad-268d-4d3e-bb30-90ca4a2053c4'
|
||||
key: "81088c8a-4b80-41fe-9d07-fda8b22d6f5f"
|
||||
};
|
||||
this.initializeConditionalStyles();
|
||||
},
|
||||
removeConditionSet() {
|
||||
//TODO: Handle the case where domainObject has items with styles but we're trying to remove the styles on the domainObject itself
|
||||
this.conditionSetIdentifier = '';
|
||||
this.conditionalStyles = [];
|
||||
this.persist(undefined);
|
||||
let domainObjectConditionalStyle = (this.domainObject.configuration && this.domainObject.configuration.conditionalStyle) || {};
|
||||
if (domainObjectConditionalStyle) {
|
||||
if (this.itemId) {
|
||||
domainObjectConditionalStyle[this.itemId] = undefined;
|
||||
delete domainObjectConditionalStyle[this.itemId];
|
||||
} else {
|
||||
domainObjectConditionalStyle.conditionSetIdentifier = undefined;
|
||||
delete domainObjectConditionalStyle.conditionSetIdentifier;
|
||||
domainObjectConditionalStyle.styles = undefined;
|
||||
delete domainObjectConditionalStyle.styles;
|
||||
}
|
||||
if (_.isEmpty(domainObjectConditionalStyle)) {
|
||||
domainObjectConditionalStyle = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
this.persist(domainObjectConditionalStyle);
|
||||
|
||||
},
|
||||
initializeConditionalStyles() {
|
||||
const backgroundColors = [{backgroundColor: 'red'},{backgroundColor: 'orange'}, {backgroundColor: 'blue'}];
|
||||
this.openmct.objects.get(this.conditionSetIdentifier).then((conditionSetDomainObject) => {
|
||||
conditionSetDomainObject.configuration.conditionCollection.forEach((identifier, index) => {
|
||||
conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
|
||||
this.conditionalStyles.push({
|
||||
conditionIdentifier: identifier,
|
||||
style: backgroundColors[index]
|
||||
conditionId: conditionConfiguration.id,
|
||||
conditionName: conditionConfiguration.name,
|
||||
style: Object.assign({}, this.initialStyles)
|
||||
});
|
||||
});
|
||||
this.persist({
|
||||
defaultStyle: this.defaultStyle || {backgroundColor: 'inherit'},
|
||||
let domainObjectConditionalStyle = (this.domainObject.configuration && this.domainObject.configuration.conditionalStyle) || {};
|
||||
let conditionalStyle = {
|
||||
conditionSetIdentifier: this.conditionSetIdentifier,
|
||||
styles: this.conditionalStyles
|
||||
});
|
||||
};
|
||||
if (this.itemId) {
|
||||
this.persist({
|
||||
...domainObjectConditionalStyle,
|
||||
[this.itemId]: conditionalStyle
|
||||
});
|
||||
} else {
|
||||
this.persist({
|
||||
...domainObjectConditionalStyle,
|
||||
...conditionalStyle
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
findStyleByConditionId(id) {
|
||||
for(let i=0, ii=this.conditionalStyles.length; i < ii; i++) {
|
||||
if (this.openmct.objects.makeKeyString(this.conditionalStyles[i].conditionIdentifier) === this.openmct.objects.makeKeyString(id)) {
|
||||
return {
|
||||
index: i,
|
||||
item: this.conditionalStyles[i]
|
||||
};
|
||||
return this.conditionalStyles.find(conditionalStyle => conditionalStyle.conditionId === id);
|
||||
},
|
||||
updateConditionalStyle(conditionStyle) {
|
||||
let found = this.findStyleByConditionId(conditionStyle.conditionId);
|
||||
if (found) {
|
||||
found.style = conditionStyle.style;
|
||||
let domainObjectConditionalStyle = this.domainObject.configuration.conditionalStyle || {};
|
||||
|
||||
if (this.itemId) {
|
||||
let itemConditionalStyle = domainObjectConditionalStyle[this.itemId];
|
||||
if (itemConditionalStyle) {
|
||||
this.persist({
|
||||
...domainObjectConditionalStyle,
|
||||
[this.itemId]: {
|
||||
...itemConditionalStyle,
|
||||
styles: this.conditionalStyles
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
domainObjectConditionalStyle.styles = this.conditionalStyles;
|
||||
this.persist(domainObjectConditionalStyle);
|
||||
}
|
||||
}
|
||||
},
|
||||
updateConditionalStyle(conditionIdentifier, style) {
|
||||
let found = this.findStyleByConditionId(conditionIdentifier);
|
||||
if (found) {
|
||||
this.conditionalStyles[found.index].style = style;
|
||||
}
|
||||
this.persist(undefined);
|
||||
},
|
||||
persist(conditionalStyle) {
|
||||
this.openmct.objects.mutate(this.domainObject, 'configuration.conditionalStyle', conditionalStyle);
|
||||
}
|
||||
|
||||
@@ -23,19 +23,11 @@ import ConditionSetViewProvider from './ConditionSetViewProvider.js';
|
||||
import ConditionSetCompositionPolicy from "./ConditionSetCompositionPolicy";
|
||||
import ConditionSetMetadataProvider from './ConditionSetMetadataProvider';
|
||||
import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider';
|
||||
import uuid from "uuid";
|
||||
|
||||
export default function ConditionPlugin() {
|
||||
|
||||
return function install(openmct) {
|
||||
openmct.types.addType('condition', {
|
||||
name: 'Condition',
|
||||
key: 'condition',
|
||||
description: 'A list of criteria which will be evaluated based on a trigger',
|
||||
creatable: false,
|
||||
initialize: function (domainObject) {
|
||||
domainObject.composition = [];
|
||||
}
|
||||
});
|
||||
|
||||
openmct.types.addType('conditionSet', {
|
||||
name: 'Condition Set',
|
||||
@@ -45,7 +37,17 @@ export default function ConditionPlugin() {
|
||||
cssClass: 'icon-conditional', // TODO: replace with class for new icon
|
||||
initialize: function (domainObject) {
|
||||
domainObject.configuration = {
|
||||
conditionCollection: []
|
||||
conditionCollection: [{
|
||||
isDefault: true,
|
||||
id: uuid(),
|
||||
configuration: {
|
||||
name: 'Default',
|
||||
output: 'false',
|
||||
trigger: 'all',
|
||||
criteria: []
|
||||
},
|
||||
summary: 'Default condition'
|
||||
}]
|
||||
};
|
||||
domainObject.composition = [];
|
||||
domainObject.telemetry = {};
|
||||
|
||||
@@ -26,26 +26,14 @@ import ConditionPlugin from "./plugin";
|
||||
let openmct = createOpenMct();
|
||||
openmct.install(new ConditionPlugin());
|
||||
|
||||
let conditionDefinition;
|
||||
let conditionSetDefinition;
|
||||
let mockDomainObject;
|
||||
let mockDomainObject2;
|
||||
let mockConditionSetDomainObject;
|
||||
let element;
|
||||
let child;
|
||||
|
||||
describe('the plugin', function () {
|
||||
|
||||
beforeAll((done) => {
|
||||
conditionDefinition = openmct.types.get('condition').definition;
|
||||
mockDomainObject = {
|
||||
identifier: {
|
||||
key: 'testConditionKey',
|
||||
namespace: ''
|
||||
},
|
||||
type: 'condition'
|
||||
};
|
||||
|
||||
conditionDefinition.initialize(mockDomainObject);
|
||||
|
||||
conditionSetDefinition = openmct.types.get('conditionSet').definition;
|
||||
const appHolder = document.createElement('div');
|
||||
@@ -56,7 +44,7 @@ describe('the plugin', function () {
|
||||
child = document.createElement('div');
|
||||
element.appendChild(child);
|
||||
|
||||
mockDomainObject2 = {
|
||||
mockConditionSetDomainObject = {
|
||||
identifier: {
|
||||
key: 'testConditionSetKey',
|
||||
namespace: ''
|
||||
@@ -64,22 +52,12 @@ describe('the plugin', function () {
|
||||
type: 'conditionSet'
|
||||
};
|
||||
|
||||
conditionSetDefinition.initialize(mockDomainObject2);
|
||||
conditionSetDefinition.initialize(mockConditionSetDomainObject);
|
||||
|
||||
openmct.on('start', done);
|
||||
openmct.start(appHolder);
|
||||
});
|
||||
|
||||
let mockConditionObject = {
|
||||
name: 'Condition',
|
||||
key: 'condition',
|
||||
creatable: false
|
||||
};
|
||||
|
||||
it('defines a condition object type with the correct key', () => {
|
||||
expect(conditionDefinition.key).toEqual(mockConditionObject.key);
|
||||
});
|
||||
|
||||
let mockConditionSetObject = {
|
||||
name: 'Condition Set',
|
||||
key: 'conditionSet',
|
||||
@@ -90,18 +68,6 @@ describe('the plugin', function () {
|
||||
expect(conditionSetDefinition.key).toEqual(mockConditionSetObject.key);
|
||||
});
|
||||
|
||||
describe('the condition object', () => {
|
||||
|
||||
it('is not creatable', () => {
|
||||
expect(conditionDefinition.creatable).toEqual(mockConditionObject.creatable);
|
||||
});
|
||||
|
||||
it('initializes with an empty composition list', () => {
|
||||
expect(mockDomainObject.composition instanceof Array).toBeTrue();
|
||||
expect(mockDomainObject.composition.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('the conditionSet object', () => {
|
||||
|
||||
it('is creatable', () => {
|
||||
@@ -109,8 +75,8 @@ describe('the plugin', function () {
|
||||
});
|
||||
|
||||
it('initializes with an empty composition list', () => {
|
||||
expect(mockDomainObject2.composition instanceof Array).toBeTrue();
|
||||
expect(mockDomainObject2.composition.length).toEqual(0);
|
||||
expect(mockConditionSetDomainObject.composition instanceof Array).toBeTrue();
|
||||
expect(mockConditionSetDomainObject.composition.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('provides a view', () => {
|
||||
|
||||
19
src/plugins/condition/utils/styleUtils.js
Normal file
19
src/plugins/condition/utils/styleUtils.js
Normal file
@@ -0,0 +1,19 @@
|
||||
export const getStyleProp = (key, defaultValue) => {
|
||||
let styleProp = undefined;
|
||||
switch(key) {
|
||||
case 'fill': styleProp = {
|
||||
backgroundColor: defaultValue || 'none'
|
||||
};
|
||||
break;
|
||||
case 'stroke': styleProp = {
|
||||
border: '1px solid ' + defaultValue || 'none'
|
||||
};
|
||||
break;
|
||||
case 'color': styleProp = {
|
||||
color: defaultValue || 'inherit'
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
return styleProp;
|
||||
};
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
<script>
|
||||
import LayoutFrame from './LayoutFrame.vue'
|
||||
import conditionalStylesMixin from '../mixins/conditionalStyles-mixin';
|
||||
|
||||
export default {
|
||||
makeDefinition() {
|
||||
@@ -52,6 +53,7 @@ export default {
|
||||
components: {
|
||||
LayoutFrame
|
||||
},
|
||||
mixins: [conditionalStylesMixin],
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
@@ -71,10 +73,14 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
return {
|
||||
backgroundColor: this.item.fill,
|
||||
border: '1px solid ' + this.item.stroke
|
||||
};
|
||||
if (this.itemStyle) {
|
||||
return this.itemStyle;
|
||||
} else {
|
||||
return {
|
||||
backgroundColor: this.item.fill,
|
||||
border: '1px solid ' + this.item.stroke
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
<script>
|
||||
import LayoutFrame from './LayoutFrame.vue'
|
||||
import conditionalStylesMixin from "../mixins/conditionalStyles-mixin";
|
||||
|
||||
export default {
|
||||
makeDefinition(openmct, gridSize, element) {
|
||||
@@ -52,6 +53,7 @@ export default {
|
||||
components: {
|
||||
LayoutFrame
|
||||
},
|
||||
mixins: [conditionalStylesMixin],
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
@@ -73,7 +75,7 @@ export default {
|
||||
style() {
|
||||
return {
|
||||
backgroundImage: 'url(' + this.item.url + ')',
|
||||
border: '1px solid ' + this.item.stroke
|
||||
border: this.itemStyle ? this.itemStyle.border : '1px solid ' + this.item.stroke
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
>
|
||||
<line
|
||||
v-bind="linePosition"
|
||||
:stroke="item.stroke"
|
||||
:stroke="stroke"
|
||||
stroke-width="2"
|
||||
/>
|
||||
</svg>
|
||||
@@ -60,6 +60,8 @@
|
||||
|
||||
<script>
|
||||
|
||||
import conditionalStylesMixin from "../mixins/conditionalStyles-mixin";
|
||||
|
||||
const START_HANDLE_QUADRANTS = {
|
||||
1: 'c-frame-edit__handle--sw',
|
||||
2: 'c-frame-edit__handle--se',
|
||||
@@ -85,6 +87,7 @@ export default {
|
||||
};
|
||||
},
|
||||
inject: ['openmct'],
|
||||
mixins: [conditionalStylesMixin],
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
@@ -122,6 +125,13 @@ export default {
|
||||
}
|
||||
return {x, y, x2, y2};
|
||||
},
|
||||
stroke() {
|
||||
if (this.itemStyle && this.itemStyle.border) {
|
||||
return this.itemStyle.border.replace('1px solid ', '');
|
||||
} else {
|
||||
return this.item.stroke;
|
||||
}
|
||||
},
|
||||
style() {
|
||||
let {x, y, x2, y2} = this.position;
|
||||
let width = Math.max(this.gridSize[0] * Math.abs(x - x2), 1);
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
<script>
|
||||
import LayoutFrame from './LayoutFrame.vue'
|
||||
import conditionalStylesMixin from "../mixins/conditionalStyles-mixin";
|
||||
|
||||
export default {
|
||||
makeDefinition(openmct, gridSize, element) {
|
||||
@@ -57,6 +58,7 @@ export default {
|
||||
components: {
|
||||
LayoutFrame
|
||||
},
|
||||
mixins: [conditionalStylesMixin],
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
@@ -76,12 +78,16 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
return {
|
||||
backgroundColor: this.item.fill,
|
||||
borderColor: this.item.stroke,
|
||||
color: this.item.color,
|
||||
fontSize: this.item.size
|
||||
};
|
||||
if (this.itemStyle) {
|
||||
return this.itemStyle;
|
||||
} else {
|
||||
return {
|
||||
backgroundColor: this.item.fill,
|
||||
borderColor: this.item.stroke,
|
||||
color: this.item.color,
|
||||
fontSize: this.item.size
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
54
src/plugins/displayLayout/mixins/conditionalStyles-mixin.js
Normal file
54
src/plugins/displayLayout/mixins/conditionalStyles-mixin.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import StyleRuleManager from "@/plugins/condition/StyleRuleManager";
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
data() {
|
||||
return {
|
||||
itemStyle: this.itemStyle
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.domainObject = this.$parent.domainObject;
|
||||
this.itemId = this.item.id;
|
||||
this.conditionalStyle = this.getConditionalStyleForItem(this.domainObject.configuration.conditionalStyle);
|
||||
this.initConditionalStyles();
|
||||
},
|
||||
destroyed() {
|
||||
if (this.stopListeningConditionalStyles) {
|
||||
this.stopListeningConditionalStyles();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getConditionalStyleForItem(conditionalStyle) {
|
||||
if (conditionalStyle) {
|
||||
return conditionalStyle[this.itemId];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
initConditionalStyles() {
|
||||
if (!this.styleRuleManager) {
|
||||
this.styleRuleManager = new StyleRuleManager(this.conditionalStyle, this.openmct);
|
||||
this.styleRuleManager.on('conditionalStyleUpdated', this.updateStyle.bind(this));
|
||||
} else {
|
||||
this.styleRuleManager.updateConditionalStyleConfig(this.conditionalStyle);
|
||||
}
|
||||
|
||||
if (this.stopListeningConditionalStyles) {
|
||||
this.stopListeningConditionalStyles();
|
||||
}
|
||||
|
||||
this.stopListeningConditionalStyles = this.openmct.objects.observe(this.domainObject, 'configuration.conditionalStyle', (newConditionalStyle) => {
|
||||
//Updating conditional styles in the inspector view will trigger this so that the changes are reflected immediately
|
||||
let newItemConditionalStyle = this.getConditionalStyleForItem(newConditionalStyle);
|
||||
if (this.conditionalStyle !== newItemConditionalStyle) {
|
||||
this.conditionalStyle = newItemConditionalStyle;
|
||||
this.styleRuleManager.updateConditionalStyleConfig(this.conditionalStyle);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateStyle(style) {
|
||||
this.itemStyle = style;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -143,7 +143,7 @@ define([
|
||||
let strategy;
|
||||
|
||||
if (this.model.interpolate !== 'none') {
|
||||
strategy = 'minMax';
|
||||
strategy = 'minmax';
|
||||
}
|
||||
|
||||
options = _.extend({}, { size: 1000, strategy, filters: this.filters }, options || {});
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<button
|
||||
v-if="allowExport"
|
||||
class="c-button icon-download labeled"
|
||||
title="Export This View's Data"
|
||||
title="Export this view's data"
|
||||
@click="exportAllDataAsCSV()"
|
||||
>
|
||||
<span class="c-button__label">Export Table Data</span>
|
||||
@@ -37,7 +37,7 @@
|
||||
v-if="allowExport"
|
||||
v-show="markedRows.length"
|
||||
class="c-button icon-download labeled"
|
||||
title="Export Marked Rows As CSV"
|
||||
title="Export marked rows as CSV"
|
||||
@click="exportMarkedDataAsCSV()"
|
||||
>
|
||||
<span class="c-button__label">Export Marked Rows</span>
|
||||
@@ -45,7 +45,7 @@
|
||||
<button
|
||||
v-show="markedRows.length"
|
||||
class="c-button icon-x labeled"
|
||||
title="Unmark All Rows"
|
||||
title="Unmark all rows"
|
||||
@click="unmarkAllRows()"
|
||||
>
|
||||
<span class="c-button__label">Unmark All Rows</span>
|
||||
@@ -58,7 +58,7 @@
|
||||
v-if="marking.enable"
|
||||
class="c-button icon-pause pause-play labeled"
|
||||
:class=" paused ? 'icon-play is-paused' : 'icon-pause'"
|
||||
:title="paused ? 'Continue Data Flow' : 'Pause Data Flow'"
|
||||
:title="paused ? 'Continue real-time data flow' : 'Pause real-time data flow'"
|
||||
@click="togglePauseByButton()"
|
||||
>
|
||||
<span class="c-button__label">
|
||||
@@ -66,6 +66,29 @@
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<template v-if="!isEditing">
|
||||
<div
|
||||
class="c-separator"
|
||||
>
|
||||
</div>
|
||||
<button
|
||||
v-if="isAutosizeEnabled"
|
||||
class="c-button icon-arrows-right-left labeled"
|
||||
title="Increase column widths to fit currently available data."
|
||||
@click="recalculateColumnWidths"
|
||||
>
|
||||
<span class="c-button__label">Expand Columns</span>
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="c-button icon-expand labeled"
|
||||
title="Automatically size columns to fit the table into the available space."
|
||||
@click="autosizeColumns"
|
||||
>
|
||||
<span class="c-button__label">Autosize Columns</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<slot name="buttons"></slot>
|
||||
</div>
|
||||
<!-- main controlbar end -->
|
||||
@@ -461,17 +484,20 @@ export default {
|
||||
this.scrollW = (this.scrollable.offsetWidth - this.scrollable.clientWidth) + 1;
|
||||
},
|
||||
calculateColumnWidths() {
|
||||
let columnWidths = {};
|
||||
let totalWidth = 0;
|
||||
let sizingRowEl = this.sizingTable.children[0];
|
||||
let sizingCells = Array.from(sizingRowEl.children);
|
||||
let headerKeys = Object.keys(this.headers);
|
||||
let columnWidths = {},
|
||||
totalWidth = 0,
|
||||
headerKeys = Object.keys(this.headers),
|
||||
sizingTableRow = this.sizingTable.children[0],
|
||||
sizingCells = sizingTableRow.children;
|
||||
|
||||
headerKeys.forEach((headerKey, headerIndex)=>{
|
||||
let cell = sizingCells[headerIndex];
|
||||
let columnWidth = cell.offsetWidth;
|
||||
columnWidths[headerKey] = columnWidth;
|
||||
totalWidth += columnWidth;
|
||||
headerKeys.forEach((headerKey, headerIndex, array)=>{
|
||||
if (this.isAutosizeEnabled) {
|
||||
columnWidths[headerKey] = this.sizingTable.clientWidth / array.length;
|
||||
} else {
|
||||
let cell = sizingCells[headerIndex];
|
||||
columnWidths[headerKey] = cell.offsetWidth;
|
||||
}
|
||||
totalWidth += columnWidths[headerKey];
|
||||
});
|
||||
|
||||
this.columnWidths = columnWidths;
|
||||
@@ -818,6 +844,31 @@ export default {
|
||||
this.setHeight();
|
||||
this.scrollable.scrollTop = this.userScroll;
|
||||
}
|
||||
},
|
||||
updateWidthsAndClearSizingTable() {
|
||||
this.calculateColumnWidths();
|
||||
this.configuredColumnWidths = this.columnWidths;
|
||||
|
||||
this.visibleRows.forEach((row, i) => {
|
||||
this.$set(this.sizingRows, i, undefined);
|
||||
delete this.sizingRows[i];
|
||||
});
|
||||
},
|
||||
recalculateColumnWidths() {
|
||||
this.visibleRows.forEach((row,i) => {
|
||||
this.$set(this.sizingRows, i, row);
|
||||
});
|
||||
|
||||
this.configuredColumnWidths = {};
|
||||
this.isAutosizeEnabled = false;
|
||||
|
||||
this.$nextTick()
|
||||
.then(this.updateWidthsAndClearSizingTable);
|
||||
},
|
||||
autosizeColumns() {
|
||||
this.isAutosizeEnabled = true;
|
||||
|
||||
this.$nextTick().then(this.calculateColumnWidths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,6 @@ $colorFilter: $colorFilterFg; // Standalone against $colorBodyBg
|
||||
// States
|
||||
$colorPausedBg: #ff9900;
|
||||
$colorPausedFg: #333;
|
||||
$colorOk: #33cc33;
|
||||
|
||||
// Base variations
|
||||
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
|
||||
@@ -411,15 +410,21 @@ $transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
||||
|
||||
// Discrete items, like Notebook entries, Widget rules
|
||||
$createBtnTextTransform: uppercase;
|
||||
$colorDiscreteItemBg: rgba($colorBodyFg,0.1);
|
||||
$colorDiscreteItemCurrentBg: rgba($colorOk,0.3);
|
||||
|
||||
@mixin discreteItem() {
|
||||
background: rgba($colorBodyFg,0.1);
|
||||
background: $colorDiscreteItemBg;
|
||||
border: none;
|
||||
border-radius: $controlCr;
|
||||
|
||||
.c-input-inline:hover {
|
||||
background: $colorBodyBg;
|
||||
}
|
||||
|
||||
&--current-match {
|
||||
background: $colorDiscreteItemCurrentBg;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin discreteItemInnerElem() {
|
||||
|
||||
@@ -125,7 +125,6 @@ $colorFilter: $colorFilterFg; // Standalone against $colorBodyBg
|
||||
// States
|
||||
$colorPausedBg: #ff9900;
|
||||
$colorPausedFg: #333;
|
||||
$colorOk: #33cc33;
|
||||
|
||||
// Base variations
|
||||
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
|
||||
@@ -415,14 +414,16 @@ $transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
||||
|
||||
// Discrete items, like Notebook entries, Widget rules
|
||||
$createBtnTextTransform: uppercase;
|
||||
$colorDiscreteItemBg: rgba($colorBodyFg,0.1);
|
||||
$colorDiscreteItemCurrentBg: rgba($colorOk,0.3);
|
||||
|
||||
@mixin discreteItem() {
|
||||
background: rgba($colorBodyFg,0.1);
|
||||
border: none;
|
||||
border-radius: $controlCr;
|
||||
|
||||
.c-input-inline:hover {
|
||||
background: $colorBodyBg;
|
||||
&--current-match {
|
||||
background: $colorDiscreteItemCurrentBg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,6 @@ $colorFilter: $colorFilterBg; // Standalone against $colorBodyBg
|
||||
// States
|
||||
$colorPausedBg: #ff9900;
|
||||
$colorPausedFg: #fff;
|
||||
$colorOk: #33cc33;
|
||||
|
||||
// Base variations
|
||||
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
|
||||
@@ -411,12 +410,18 @@ $transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
||||
|
||||
// Discrete items, like Notebook entries, Widget rules
|
||||
$createBtnTextTransform: uppercase;
|
||||
$colorDiscreteItemBg: rgba($colorBodyFg,0.1);
|
||||
$colorDiscreteItemCurrentBg: rgba($colorOk,0.3);
|
||||
|
||||
@mixin discreteItem() {
|
||||
background: rgba($colorBodyFg,0.1);
|
||||
background: $colorDiscreteItemBg;
|
||||
border: 1px solid $colorInteriorBorder;
|
||||
border-radius: $controlCr;
|
||||
|
||||
&--current-match {
|
||||
background: $colorDiscreteItemCurrentBg;
|
||||
}
|
||||
|
||||
.c-input-inline:hover {
|
||||
background: $colorBodyBg;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,11 @@ button {
|
||||
background: $colorBtnBgHov;
|
||||
color: $colorBtnFgHov;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: $glyph-icon-arrow-down;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
@@ -78,6 +83,20 @@ button {
|
||||
/********* Icon Buttons and Links */
|
||||
.c-click-icon {
|
||||
@include cClickIcon();
|
||||
|
||||
&--section-collapse {
|
||||
color: inherit;
|
||||
display: block;
|
||||
transition: transform $transOutTime;
|
||||
&:before {
|
||||
content: $glyph-icon-arrow-down;
|
||||
font-family: symbolsfont;
|
||||
}
|
||||
|
||||
&.is-collapsed {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-click-link {
|
||||
@@ -189,6 +208,45 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** DRAG AFFORDANCES */
|
||||
.c-grippy {
|
||||
$d: 10px;
|
||||
@include grippy($c: $colorItemTreeVC, $dir: 'y');
|
||||
width: $d; height: $d;
|
||||
|
||||
&--vertical-drag {
|
||||
cursor: ns-resize;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** SECTION */
|
||||
section {
|
||||
flex: 0 0 auto;
|
||||
overflow: hidden;
|
||||
+ section {
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
|
||||
&.is-expanded {
|
||||
flex: 1 1 100%;
|
||||
max-height: max-content;
|
||||
}
|
||||
|
||||
.c-section__header {
|
||||
@include propertiesHeader();
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: $interiorMargin;
|
||||
|
||||
> * + * { margin-left: $interiorMarginSm; }
|
||||
}
|
||||
|
||||
> [class*='__label'] {
|
||||
flex: 1 1 auto;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** FORM ELEMENTS */
|
||||
input, textarea {
|
||||
font-family: inherit;
|
||||
@@ -619,6 +677,12 @@ select {
|
||||
|
||||
.c-separator {
|
||||
@include cToolbarSeparator();
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.c-row-separator {
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.c-toolbar {
|
||||
|
||||
@@ -108,8 +108,9 @@ tr {
|
||||
}
|
||||
|
||||
/*************************************************** STATUS */
|
||||
[class*='s-status'] {
|
||||
[class*='s-status-icon'] {
|
||||
&:before {
|
||||
font-family: symbolsfont;
|
||||
margin-right: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,8 @@ export default {
|
||||
this.openmct.objectViews.on('clearData', this.clearData);
|
||||
},
|
||||
show(object, viewKey, immediatelySelect, currentObjectPath) {
|
||||
this.updateStyle();
|
||||
|
||||
if (this.unlisten) {
|
||||
this.unlisten();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
$d: 12px;
|
||||
$m: 2px;
|
||||
$br: $d/1.5;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
@@ -39,7 +40,6 @@
|
||||
display: inline-block;
|
||||
height: $d + ($m*2);
|
||||
position: relative;
|
||||
transform: translateY(2px); // TODO: get this to work without this kind of hack!
|
||||
width: $d*2 + $m*2;
|
||||
|
||||
&:before {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
>
|
||||
<span
|
||||
v-if="elements.length > 1 && isEditing"
|
||||
class="c-elements-pool__grippy"
|
||||
class="c-elements-pool__grippy c-grippy c-grippy--vertical-drag"
|
||||
></span>
|
||||
<object-label
|
||||
:domain-object="element"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<script>
|
||||
import ConditionalStylesView from '../../plugins/condition/components/inspector/ConditionalStylesView.vue';
|
||||
import Vue from 'vue';
|
||||
import { getStyleProp } from "../../plugins/condition/utils/styleUtils";
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
@@ -24,16 +25,30 @@ export default {
|
||||
this.openmct.selection.off('change', this.updateSelection);
|
||||
},
|
||||
methods: {
|
||||
getStyleProperties(item) {
|
||||
let styleProps = {};
|
||||
Object.keys(item).forEach((key) => {
|
||||
Object.assign(styleProps, getStyleProp(key, item[key]));
|
||||
});
|
||||
return styleProps;
|
||||
},
|
||||
updateSelection(selection) {
|
||||
if (selection.length > 0 && selection[0].length > 0) {
|
||||
let domainObject = selection[0][0].context.item;
|
||||
let layoutItem;
|
||||
let layoutItem = {};
|
||||
let styleProps = this.getStyleProperties({
|
||||
fill: 'inherit',
|
||||
stroke: 'inherit',
|
||||
color: 'inherit'
|
||||
});
|
||||
if (selection[0].length > 1) {
|
||||
//If there are more than 1 items in the selection[0] list, the first one could either be a sub domain object OR a layout drawing control.
|
||||
//The second item in the selection[0] list is the container object (usually a layout)
|
||||
domainObject = selection[0][0].context.item;
|
||||
if (!domainObject) {
|
||||
styleProps = {};
|
||||
layoutItem = selection[0][0].context.layoutItem;
|
||||
styleProps = this.getStyleProperties(layoutItem);
|
||||
domainObject = selection[0][1].context.item;
|
||||
}
|
||||
}
|
||||
@@ -49,14 +64,19 @@ export default {
|
||||
this.component = new Vue({
|
||||
provide: {
|
||||
openmct: this.openmct,
|
||||
domainObject: domainObject,
|
||||
layoutItem: layoutItem
|
||||
domainObject: domainObject
|
||||
},
|
||||
el: viewContainer,
|
||||
components: {
|
||||
ConditionalStylesView
|
||||
},
|
||||
template: '<conditional-styles-view></conditional-styles-view>'
|
||||
data() {
|
||||
return {
|
||||
layoutItem,
|
||||
styleProps
|
||||
}
|
||||
},
|
||||
template: '<conditional-styles-view :item-id="layoutItem.id" :initial-styles="styleProps"></conditional-styles-view>'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__grippy {
|
||||
.c-grippy {
|
||||
$d: 8px;
|
||||
@include grippy($c: $colorItemTreeVC, $dir: 'y');
|
||||
flex: 0 0 auto;
|
||||
margin-right: $interiorMarginSm;
|
||||
transform: translateY(-2px);
|
||||
|
||||
Reference in New Issue
Block a user