Compare commits
47 Commits
plots/cust
...
v1.2-RC6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d19975917 | ||
|
|
29e7942a4e | ||
|
|
4f853016d6 | ||
|
|
abbb31f384 | ||
|
|
ae8ed2d71f | ||
|
|
9ecb257e5d | ||
|
|
5e2d8106a5 | ||
|
|
32aa412d1e | ||
|
|
cb7f431fdf | ||
|
|
e667b22b3c | ||
|
|
7d51d9c1eb | ||
|
|
9124f4f566 | ||
|
|
d9baa94970 | ||
|
|
afeb89a51a | ||
|
|
07992f0b2a | ||
|
|
a5c4508578 | ||
|
|
a4fab3ce8a | ||
|
|
97d80f57cc | ||
|
|
41138a1731 | ||
|
|
a54a2f8f84 | ||
|
|
5bbe710552 | ||
|
|
f2d34d7c33 | ||
|
|
8fa1770885 | ||
|
|
7221dc1ac6 | ||
|
|
25bb9939d6 | ||
|
|
e7e12504f2 | ||
|
|
63bf856d89 | ||
|
|
e3dcd51f8d | ||
|
|
cb63f4eca1 | ||
|
|
3f60c3c0f1 | ||
|
|
16bb22e834 | ||
|
|
b1467548da | ||
|
|
baa7c0bc58 | ||
|
|
73b81e38e7 | ||
|
|
8b088b7a2c | ||
|
|
894da25461 | ||
|
|
87d63806b9 | ||
|
|
f0e7f8cfc0 | ||
|
|
db597e1e93 | ||
|
|
98db273f5d | ||
|
|
8a6f944655 | ||
|
|
bacad24811 | ||
|
|
8cc58946cf | ||
|
|
3338bc1000 | ||
|
|
80c20b3d05 | ||
|
|
0d9558b891 | ||
|
|
c29c3c386f |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -37,4 +37,7 @@ protractor/logs
|
||||
# npm-debug log
|
||||
npm-debug.log
|
||||
|
||||
# karma reports
|
||||
report.*.json
|
||||
|
||||
package-lock.json
|
||||
|
||||
@@ -113,7 +113,10 @@
|
||||
openmct.install(openmct.plugins.LADTable());
|
||||
openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay']));
|
||||
openmct.install(openmct.plugins.ObjectMigration());
|
||||
openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked']));
|
||||
openmct.install(openmct.plugins.ClearData(
|
||||
['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked'],
|
||||
{indicator: true}
|
||||
));
|
||||
openmct.start();
|
||||
</script>
|
||||
</html>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
/*global module,process*/
|
||||
|
||||
const devMode = process.env.NODE_ENV !== 'production';
|
||||
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless'];
|
||||
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'FirefoxHeadless'];
|
||||
const coverageEnabled = process.env.COVERAGE === 'true';
|
||||
const reporters = ['progress', 'html'];
|
||||
|
||||
@@ -95,6 +95,7 @@ module.exports = (config) => {
|
||||
stats: 'errors-only',
|
||||
logLevel: 'warn'
|
||||
},
|
||||
singleRun: true
|
||||
singleRun: true,
|
||||
browserNoActivityTimeout: 90000
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"jsdoc": "^3.3.2",
|
||||
"karma": "^2.0.3",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-firefox-launcher": "^1.3.0",
|
||||
"karma-cli": "^1.0.1",
|
||||
"karma-coverage": "^1.1.2",
|
||||
"karma-coverage-istanbul-reporter": "^2.1.1",
|
||||
@@ -59,7 +60,7 @@
|
||||
"moment-timezone": "0.5.28",
|
||||
"node-bourbon": "^4.2.3",
|
||||
"node-sass": "^4.9.2",
|
||||
"painterro": "^0.2.65",
|
||||
"painterro": "^1.0.35",
|
||||
"printj": "^1.2.1",
|
||||
"raw-loader": "^0.5.1",
|
||||
"request": "^2.69.0",
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
</mct-form>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<a class='c-button c-button--major'
|
||||
<button class='c-button c-button--major'
|
||||
ng-class="{ disabled: !createForm.$valid }"
|
||||
ng-click="ngModel.confirm()">
|
||||
OK
|
||||
</a>
|
||||
<a class='c-button '
|
||||
</button>
|
||||
<button class='c-button '
|
||||
ng-click="ngModel.cancel()">
|
||||
Cancel
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
</mct-include>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<a ng-repeat="option in ngModel.dialog.options"
|
||||
<button ng-repeat="option in ngModel.dialog.options"
|
||||
href=''
|
||||
class="s-button lg"
|
||||
title="{{option.description}}"
|
||||
ng-click="ngModel.confirm(option.key)"
|
||||
ng-class="{ major: $first, subtle: !$first }">
|
||||
{{option.name}}
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</mct-container>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<div class="c-overlay__outer">
|
||||
<button ng-click="ngModel.cancel()"
|
||||
ng-if="ngModel.cancel"
|
||||
class="c-click-icon c-overlay__close-button icon-x-in-circle"></button>
|
||||
class="c-click-icon c-overlay__close-button icon-x"></button>
|
||||
<div class="c-overlay__contents" ng-transclude></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -36,8 +36,6 @@ define(
|
||||
}
|
||||
|
||||
EditPersistableObjectsPolicy.prototype.allow = function (action, context) {
|
||||
var identifier;
|
||||
var provider;
|
||||
var domainObject = context.domainObject;
|
||||
var key = action.getMetadata().key;
|
||||
var category = (context || {}).category;
|
||||
@@ -46,9 +44,8 @@ define(
|
||||
// is also invoked during the create process which should be allowed,
|
||||
// because it may be saved elsewhere
|
||||
if ((key === 'edit' && category === 'view-control') || key === 'properties') {
|
||||
identifier = objectUtils.parseKeyString(domainObject.getId());
|
||||
provider = this.openmct.objects.getProvider(identifier);
|
||||
return provider.save !== undefined;
|
||||
let newStyleObject = objectUtils.toNewFormat(domainObject, domainObject.getId());
|
||||
return this.openmct.objects.isPersistable(newStyleObject);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -43,7 +43,7 @@ define(
|
||||
);
|
||||
|
||||
mockObjectAPI = jasmine.createSpyObj('objectAPI', [
|
||||
'getProvider'
|
||||
'isPersistable'
|
||||
]);
|
||||
|
||||
mockAPI = {
|
||||
@@ -69,34 +69,31 @@ define(
|
||||
});
|
||||
|
||||
it("Applies to edit action", function () {
|
||||
mockObjectAPI.getProvider.and.returnValue({});
|
||||
expect(mockObjectAPI.getProvider).not.toHaveBeenCalled();
|
||||
expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled();
|
||||
|
||||
policy.allow(mockEditAction, testContext);
|
||||
expect(mockObjectAPI.getProvider).toHaveBeenCalled();
|
||||
expect(mockObjectAPI.isPersistable).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Applies to properties action", function () {
|
||||
mockObjectAPI.getProvider.and.returnValue({});
|
||||
expect(mockObjectAPI.getProvider).not.toHaveBeenCalled();
|
||||
expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled();
|
||||
|
||||
policy.allow(mockPropertiesAction, testContext);
|
||||
expect(mockObjectAPI.getProvider).toHaveBeenCalled();
|
||||
expect(mockObjectAPI.isPersistable).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not apply to other actions", function () {
|
||||
mockObjectAPI.getProvider.and.returnValue({});
|
||||
expect(mockObjectAPI.getProvider).not.toHaveBeenCalled();
|
||||
expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled();
|
||||
|
||||
policy.allow(mockOtherAction, testContext);
|
||||
expect(mockObjectAPI.getProvider).not.toHaveBeenCalled();
|
||||
expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Tests object provider for editability", function () {
|
||||
mockObjectAPI.getProvider.and.returnValue({});
|
||||
mockObjectAPI.isPersistable.and.returnValue(false);
|
||||
expect(policy.allow(mockEditAction, testContext)).toBe(false);
|
||||
expect(mockObjectAPI.getProvider).toHaveBeenCalled();
|
||||
mockObjectAPI.getProvider.and.returnValue({save: function () {}});
|
||||
expect(mockObjectAPI.isPersistable).toHaveBeenCalled();
|
||||
mockObjectAPI.isPersistable.and.returnValue(true);
|
||||
expect(policy.allow(mockEditAction, testContext)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,7 +19,13 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="c-object-label">
|
||||
<div class="c-object-label__type-icon {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div>
|
||||
<div class="c-object-label"
|
||||
ng-class="{ 'is-missing': model.status === 'missing' }"
|
||||
>
|
||||
<div class="c-object-label__type-icon {{type.getCssClass()}}"
|
||||
ng-class="{ 'l-icon-link':location.isLink() }"
|
||||
>
|
||||
<span class="is-missing__indicator" title="This item is missing"></span>
|
||||
</div>
|
||||
<div class='c-object-label__name'>{{model.name}}</div>
|
||||
</div>
|
||||
|
||||
@@ -48,9 +48,8 @@ define(
|
||||
// prevents editing of objects that cannot be persisted, so we can assume that this
|
||||
// is a new object.
|
||||
if (!(parent.hasCapability('editor') && parent.getCapability('editor').isEditContextRoot())) {
|
||||
var identifier = objectUtils.parseKeyString(parent.getId());
|
||||
var provider = this.openmct.objects.getProvider(identifier);
|
||||
return provider.save !== undefined;
|
||||
let newStyleObject = objectUtils.toNewFormat(parent, parent.getId());
|
||||
return this.openmct.objects.isPersistable(newStyleObject);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ define(
|
||||
|
||||
beforeEach(function () {
|
||||
objectAPI = jasmine.createSpyObj('objectsAPI', [
|
||||
'getProvider'
|
||||
'isPersistable'
|
||||
]);
|
||||
|
||||
mockOpenMCT = {
|
||||
@@ -51,10 +51,6 @@ define(
|
||||
'isEditContextRoot'
|
||||
]);
|
||||
mockParent.getCapability.and.returnValue(mockEditorCapability);
|
||||
|
||||
objectAPI.getProvider.and.returnValue({
|
||||
save: function () {}
|
||||
});
|
||||
persistableCompositionPolicy = new PersistableCompositionPolicy(mockOpenMCT);
|
||||
});
|
||||
|
||||
@@ -65,19 +61,22 @@ define(
|
||||
|
||||
it("Does not allow composition for objects that are not persistable", function () {
|
||||
mockEditorCapability.isEditContextRoot.and.returnValue(false);
|
||||
objectAPI.isPersistable.and.returnValue(true);
|
||||
expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true);
|
||||
objectAPI.getProvider.and.returnValue({});
|
||||
objectAPI.isPersistable.and.returnValue(false);
|
||||
expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(false);
|
||||
});
|
||||
|
||||
it("Always allows composition of objects in edit mode to support object creation", function () {
|
||||
mockEditorCapability.isEditContextRoot.and.returnValue(true);
|
||||
objectAPI.isPersistable.and.returnValue(true);
|
||||
expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true);
|
||||
expect(objectAPI.getProvider).not.toHaveBeenCalled();
|
||||
expect(objectAPI.isPersistable).not.toHaveBeenCalled();
|
||||
|
||||
mockEditorCapability.isEditContextRoot.and.returnValue(false);
|
||||
objectAPI.isPersistable.and.returnValue(true);
|
||||
expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true);
|
||||
expect(objectAPI.getProvider).toHaveBeenCalled();
|
||||
expect(objectAPI.isPersistable).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -297,7 +297,8 @@ define([
|
||||
"persistenceService",
|
||||
"identifierService",
|
||||
"notificationService",
|
||||
"$q"
|
||||
"$q",
|
||||
"openmct"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
function () {
|
||||
define(["objectUtils"],
|
||||
function (objectUtils) {
|
||||
|
||||
/**
|
||||
* Defines the `persistence` capability, used to trigger the
|
||||
@@ -47,6 +47,7 @@ define(
|
||||
identifierService,
|
||||
notificationService,
|
||||
$q,
|
||||
openmct,
|
||||
domainObject
|
||||
) {
|
||||
// Cache modified timestamp
|
||||
@@ -58,6 +59,7 @@ define(
|
||||
this.persistenceService = persistenceService;
|
||||
this.notificationService = notificationService;
|
||||
this.$q = $q;
|
||||
this.openmct = openmct;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +68,7 @@ define(
|
||||
*/
|
||||
function rejectIfFalsey(value, $q) {
|
||||
if (!value) {
|
||||
return $q.reject("Error persisting object");
|
||||
return Promise.reject("Error persisting object");
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
@@ -98,7 +100,7 @@ define(
|
||||
dismissable: true
|
||||
});
|
||||
|
||||
return $q.reject(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,34 +112,16 @@ define(
|
||||
*/
|
||||
PersistenceCapability.prototype.persist = function () {
|
||||
var self = this,
|
||||
domainObject = this.domainObject,
|
||||
model = domainObject.getModel(),
|
||||
modified = model.modified,
|
||||
persisted = model.persisted,
|
||||
persistenceService = this.persistenceService,
|
||||
persistenceFn = persisted !== undefined ?
|
||||
this.persistenceService.updateObject :
|
||||
this.persistenceService.createObject;
|
||||
domainObject = this.domainObject;
|
||||
|
||||
if (persisted !== undefined && persisted === modified) {
|
||||
return this.$q.when(true);
|
||||
}
|
||||
|
||||
// Update persistence timestamp...
|
||||
domainObject.useCapability("mutation", function (m) {
|
||||
m.persisted = modified;
|
||||
}, modified);
|
||||
|
||||
// ...and persist
|
||||
return persistenceFn.apply(persistenceService, [
|
||||
this.getSpace(),
|
||||
this.getKey(),
|
||||
domainObject.getModel()
|
||||
]).then(function (result) {
|
||||
return rejectIfFalsey(result, self.$q);
|
||||
}).catch(function (error) {
|
||||
return notifyOnError(error, domainObject, self.notificationService, self.$q);
|
||||
});
|
||||
let newStyleObject = objectUtils.toNewFormat(domainObject.getModel(), domainObject.getId());
|
||||
return this.openmct.objects
|
||||
.save(newStyleObject)
|
||||
.then(function (result) {
|
||||
return rejectIfFalsey(result, self.$q);
|
||||
}).catch(function (error) {
|
||||
return notifyOnError(error, domainObject, self.notificationService, self.$q);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* PersistenceCapabilitySpec. Created by vwoeltje on 11/6/14.
|
||||
*/
|
||||
@@ -40,7 +39,8 @@ define(
|
||||
model,
|
||||
SPACE = "some space",
|
||||
persistence,
|
||||
happyPromise;
|
||||
mockOpenMCT,
|
||||
mockNewStyleDomainObject;
|
||||
|
||||
function asPromise(value, doCatch) {
|
||||
return (value || {}).then ? value : {
|
||||
@@ -56,7 +56,6 @@ define(
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
happyPromise = asPromise(true);
|
||||
model = { someKey: "some value", name: "domain object"};
|
||||
|
||||
mockPersistenceService = jasmine.createSpyObj(
|
||||
@@ -94,12 +93,23 @@ define(
|
||||
},
|
||||
useCapability: jasmine.createSpy()
|
||||
};
|
||||
|
||||
mockNewStyleDomainObject = Object.assign({}, model);
|
||||
mockNewStyleDomainObject.identifier = {
|
||||
namespace: "",
|
||||
key: id
|
||||
}
|
||||
|
||||
// Simulate mutation capability
|
||||
mockDomainObject.useCapability.and.callFake(function (capability, mutator) {
|
||||
if (capability === 'mutation') {
|
||||
model = mutator(model) || model;
|
||||
}
|
||||
});
|
||||
|
||||
mockOpenMCT = {};
|
||||
mockOpenMCT.objects = jasmine.createSpyObj('Object API', ['save']);
|
||||
|
||||
mockIdentifierService.parse.and.returnValue(mockIdentifier);
|
||||
mockIdentifier.getSpace.and.returnValue(SPACE);
|
||||
mockIdentifier.getKey.and.returnValue(key);
|
||||
@@ -110,51 +120,28 @@ define(
|
||||
mockIdentifierService,
|
||||
mockNofificationService,
|
||||
mockQ,
|
||||
mockOpenMCT,
|
||||
mockDomainObject
|
||||
);
|
||||
});
|
||||
|
||||
describe("successful persistence", function () {
|
||||
beforeEach(function () {
|
||||
mockPersistenceService.updateObject.and.returnValue(happyPromise);
|
||||
mockPersistenceService.createObject.and.returnValue(happyPromise);
|
||||
mockOpenMCT.objects.save.and.returnValue(Promise.resolve(true));
|
||||
});
|
||||
it("creates unpersisted objects with the persistence service", function () {
|
||||
// Verify precondition; no call made during constructor
|
||||
expect(mockPersistenceService.createObject).not.toHaveBeenCalled();
|
||||
expect(mockOpenMCT.objects.save).not.toHaveBeenCalled();
|
||||
|
||||
persistence.persist();
|
||||
|
||||
expect(mockPersistenceService.createObject).toHaveBeenCalledWith(
|
||||
SPACE,
|
||||
key,
|
||||
model
|
||||
);
|
||||
});
|
||||
|
||||
it("updates previously persisted objects with the persistence service", function () {
|
||||
// Verify precondition; no call made during constructor
|
||||
expect(mockPersistenceService.updateObject).not.toHaveBeenCalled();
|
||||
|
||||
model.persisted = 12321;
|
||||
persistence.persist();
|
||||
|
||||
expect(mockPersistenceService.updateObject).toHaveBeenCalledWith(
|
||||
SPACE,
|
||||
key,
|
||||
model
|
||||
);
|
||||
expect(mockOpenMCT.objects.save).toHaveBeenCalledWith(mockNewStyleDomainObject);
|
||||
});
|
||||
|
||||
it("reports which persistence space an object belongs to", function () {
|
||||
expect(persistence.getSpace()).toEqual(SPACE);
|
||||
});
|
||||
|
||||
it("updates persisted timestamp on persistence", function () {
|
||||
model.modified = 12321;
|
||||
persistence.persist();
|
||||
expect(model.persisted).toEqual(12321);
|
||||
});
|
||||
it("refreshes the domain object model from persistence", function () {
|
||||
var refreshModel = {someOtherKey: "some other value"};
|
||||
model.persisted = 1;
|
||||
@@ -165,30 +152,37 @@ define(
|
||||
|
||||
it("does not trigger error notification on successful" +
|
||||
" persistence", function () {
|
||||
persistence.persist();
|
||||
expect(mockQ.reject).not.toHaveBeenCalled();
|
||||
expect(mockNofificationService.error).not.toHaveBeenCalled();
|
||||
let rejected = false;
|
||||
return persistence.persist()
|
||||
.catch(() => rejected = true)
|
||||
.then(() => {
|
||||
expect(rejected).toBe(false);
|
||||
expect(mockNofificationService.error).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("unsuccessful persistence", function () {
|
||||
var sadPromise = {
|
||||
then: function (callback) {
|
||||
return asPromise(callback(0), true);
|
||||
}
|
||||
};
|
||||
beforeEach(function () {
|
||||
mockPersistenceService.createObject.and.returnValue(sadPromise);
|
||||
mockOpenMCT.objects.save.and.returnValue(Promise.resolve(false));
|
||||
});
|
||||
it("rejects on falsey persistence result", function () {
|
||||
persistence.persist();
|
||||
expect(mockQ.reject).toHaveBeenCalled();
|
||||
let rejected = false;
|
||||
return persistence.persist()
|
||||
.catch(() => rejected = true)
|
||||
.then(() => {
|
||||
expect(rejected).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("notifies user on persistence failure", function () {
|
||||
persistence.persist();
|
||||
expect(mockQ.reject).toHaveBeenCalled();
|
||||
expect(mockNofificationService.error).toHaveBeenCalled();
|
||||
let rejected = false;
|
||||
return persistence.persist()
|
||||
.catch(() => rejected = true)
|
||||
.then(() => {
|
||||
expect(rejected).toBe(true);
|
||||
expect(mockNofificationService.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="c-clock l-time-display" ng-controller="ClockController as clock">
|
||||
<div class="c-clock l-time-display u-style-receiver js-style-receiver" ng-controller="ClockController as clock">
|
||||
<div class="c-clock__timezone">
|
||||
{{clock.zone()}}
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="c-timer is-{{timer.timerState}}" ng-controller="TimerController as timer">
|
||||
<div class="c-timer u-style-receiver js-style-receiver is-{{timer.timerState}}" ng-controller="TimerController as timer">
|
||||
<div class="c-timer__controls">
|
||||
<button ng-click="timer.clickStopButton()"
|
||||
ng-hide="timer.timerState == 'stopped'"
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
type="text" tabindex="10000"
|
||||
ng-model="ngModel.input"
|
||||
ng-keyup="controller.search()"/>
|
||||
<a class="c-search__clear-input clear-icon icon-x-in-circle"
|
||||
<button class="c-search__clear-input clear-icon icon-x-in-circle"
|
||||
ng-class="{show: !(ngModel.input === '' || ngModel.input === undefined)}"
|
||||
ng-click="ngModel.input = ''; controller.search()"></a>
|
||||
ng-click="ngModel.input = ''; controller.search()"></button>
|
||||
<!-- To prevent double triggering of clicks on click away, render
|
||||
non-clickable version of the button when menu active-->
|
||||
<a ng-if="!toggle.isActive()" class="menu-icon context-available"
|
||||
@@ -45,16 +45,16 @@
|
||||
</mct-include>
|
||||
</div>
|
||||
|
||||
<a class="c-button c-search__btn-cancel"
|
||||
<button class="c-button c-search__btn-cancel"
|
||||
ng-show="!(ngModel.input === '' || ngModel.input === undefined)"
|
||||
ng-click="ngModel.input = ''; ngModel.checkAll = true; menuController.checkAll(); controller.search()">
|
||||
Cancel</a>
|
||||
Cancel</button>
|
||||
</div>
|
||||
|
||||
<div class="active-filter-display flex-elem holder"
|
||||
ng-class="{invisible: ngModel.filtersString === '' || ngModel.filtersString === undefined || !ngModel.search}">
|
||||
<a class="clear-filters icon-x-in-circle s-icon-button"
|
||||
ng-click="ngModel.checkAll = true; menuController.checkAll()"></a>Filtered by: {{ ngModel.filtersString }}
|
||||
<button class="clear-filters icon-x-in-circle s-icon-button"
|
||||
ng-click="ngModel.checkAll = true; menuController.checkAll()"></button>Filtered by: {{ ngModel.filtersString }}
|
||||
</div>
|
||||
|
||||
<div class="flex-elem holder results-msg" ng-model="ngModel" ng-show="!loading && ngModel.search">
|
||||
@@ -72,7 +72,7 @@
|
||||
ng-model="ngModel"
|
||||
class="l-flex-row flex-elem grows">
|
||||
</mct-representation>
|
||||
<a class="load-more-button s-button vsm" ng-if="controller.areMore()" ng-click="controller.loadMore()">More Results</a>
|
||||
<button class="load-more-button s-button vsm" ng-if="controller.areMore()" ng-click="controller.loadMore()">More Results</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -25,10 +25,11 @@ define([
|
||||
], function (
|
||||
utils
|
||||
) {
|
||||
function ObjectServiceProvider(eventEmitter, objectService, instantiate, topic) {
|
||||
function ObjectServiceProvider(eventEmitter, objectService, instantiate, topic, $injector) {
|
||||
this.eventEmitter = eventEmitter;
|
||||
this.objectService = objectService;
|
||||
this.instantiate = instantiate;
|
||||
this.$injector = $injector;
|
||||
|
||||
this.generalTopic = topic('mutation');
|
||||
this.bridgeEventBuses();
|
||||
@@ -68,16 +69,53 @@ define([
|
||||
removeGeneralTopicListener = this.generalTopic.listen(handleLegacyMutation);
|
||||
};
|
||||
|
||||
ObjectServiceProvider.prototype.save = function (object) {
|
||||
var key = object.key;
|
||||
ObjectServiceProvider.prototype.create = async function (object) {
|
||||
let model = utils.toOldFormat(object);
|
||||
|
||||
return object.getCapability('persistence')
|
||||
.persist()
|
||||
.then(function () {
|
||||
return utils.toNewFormat(object, key);
|
||||
});
|
||||
return this.getPersistenceService().createObject(
|
||||
this.getSpace(utils.makeKeyString(object.identifier)),
|
||||
object.identifier.key,
|
||||
model
|
||||
);
|
||||
}
|
||||
ObjectServiceProvider.prototype.update = async function (object) {
|
||||
let model = utils.toOldFormat(object);
|
||||
|
||||
return this.getPersistenceService().updateObject(
|
||||
this.getSpace(utils.makeKeyString(object.identifier)),
|
||||
object.identifier.key,
|
||||
model
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the space in which this domain object is persisted;
|
||||
* this is useful when, for example, decided which space a
|
||||
* newly-created domain object should be persisted to (by
|
||||
* default, this should be the space of its containing
|
||||
* object.)
|
||||
*
|
||||
* @returns {string} the name of the space which should
|
||||
* be used to persist this object
|
||||
*/
|
||||
ObjectServiceProvider.prototype.getSpace = function (keystring) {
|
||||
return this.getIdentifierService().parse(keystring).getSpace();
|
||||
};
|
||||
|
||||
ObjectServiceProvider.prototype.getIdentifierService = function () {
|
||||
if (this.identifierService === undefined) {
|
||||
this.identifierService = this.$injector.get('identifierService');
|
||||
}
|
||||
return this.identifierService;
|
||||
};
|
||||
|
||||
ObjectServiceProvider.prototype.getPersistenceService = function () {
|
||||
if (this.persistenceService === undefined) {
|
||||
this.persistenceService = this.$injector.get('persistenceService');
|
||||
}
|
||||
return this.persistenceService;
|
||||
}
|
||||
|
||||
ObjectServiceProvider.prototype.delete = function (object) {
|
||||
// TODO!
|
||||
};
|
||||
@@ -118,7 +156,8 @@ define([
|
||||
eventEmitter,
|
||||
objectService,
|
||||
instantiate,
|
||||
topic
|
||||
topic,
|
||||
openmct.$injector
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -101,14 +101,25 @@ define([
|
||||
*/
|
||||
|
||||
/**
|
||||
* Save this domain object in its current state.
|
||||
* Create the given domain object in the corresponding persistence store
|
||||
*
|
||||
* @method save
|
||||
* @method create
|
||||
* @memberof module:openmct.ObjectProvider#
|
||||
* @param {module:openmct.DomainObject} domainObject the domain object to
|
||||
* save
|
||||
* create
|
||||
* @returns {Promise} a promise which will resolve when the domain object
|
||||
* has been saved, or be rejected if it cannot be saved
|
||||
* has been created, or be rejected if it cannot be saved
|
||||
*/
|
||||
|
||||
/**
|
||||
* Update this domain object in its persistence store
|
||||
*
|
||||
* @method update
|
||||
* @memberof module:openmct.ObjectProvider#
|
||||
* @param {module:openmct.DomainObject} domainObject the domain object to
|
||||
* update
|
||||
* @returns {Promise} a promise which will resolve when the domain object
|
||||
* has been updated, or be rejected if it cannot be saved
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -161,8 +172,41 @@ define([
|
||||
throw new Error('Delete not implemented');
|
||||
};
|
||||
|
||||
ObjectAPI.prototype.save = function () {
|
||||
throw new Error('Save not implemented');
|
||||
ObjectAPI.prototype.isPersistable = function (domainObject) {
|
||||
let provider = this.getProvider(domainObject.identifier);
|
||||
return provider !== undefined &&
|
||||
provider.create !== undefined &&
|
||||
provider.update !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save this domain object in its current state. EXPERIMENTAL
|
||||
*
|
||||
* @private
|
||||
* @memberof module:openmct.ObjectAPI#
|
||||
* @param {module:openmct.DomainObject} domainObject the domain object to
|
||||
* save
|
||||
* @returns {Promise} a promise which will resolve when the domain object
|
||||
* has been saved, or be rejected if it cannot be saved
|
||||
*/
|
||||
ObjectAPI.prototype.save = function (domainObject) {
|
||||
let provider = this.getProvider(domainObject.identifier);
|
||||
let result;
|
||||
|
||||
if (!this.isPersistable(domainObject)) {
|
||||
result = Promise.reject('Object provider does not support saving');
|
||||
} else if (hasAlreadyBeenPersisted(domainObject)) {
|
||||
result = Promise.resolve(true);
|
||||
} else {
|
||||
if (domainObject.persisted === undefined) {
|
||||
this.mutate(domainObject, 'persisted', domainObject.modified);
|
||||
result = provider.create(domainObject);
|
||||
} else {
|
||||
this.mutate(domainObject, 'persisted', domainObject.modified);
|
||||
result = provider.update(domainObject);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -276,5 +320,9 @@ define([
|
||||
* @memberof module:openmct
|
||||
*/
|
||||
|
||||
function hasAlreadyBeenPersisted(domainObject) {
|
||||
return domainObject.persisted !== undefined &&
|
||||
domainObject.persisted === domainObject.modified;
|
||||
}
|
||||
return ObjectAPI;
|
||||
});
|
||||
|
||||
60
src/api/objects/ObjectAPISpec.js
Normal file
60
src/api/objects/ObjectAPISpec.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import ObjectAPI from './ObjectAPI.js';
|
||||
|
||||
describe("The Object API", () => {
|
||||
let objectAPI;
|
||||
let mockDomainObject;
|
||||
const TEST_NAMESPACE = "test-namespace";
|
||||
const FIFTEEN_MINUTES = 15 * 60 * 1000;
|
||||
|
||||
beforeEach(() => {
|
||||
objectAPI = new ObjectAPI();
|
||||
mockDomainObject = {
|
||||
identifier: {
|
||||
namespace: TEST_NAMESPACE,
|
||||
key: "test-key"
|
||||
},
|
||||
name: "test object",
|
||||
type: "test-type"
|
||||
};
|
||||
})
|
||||
describe("The save function", () => {
|
||||
it("Rejects if no provider available", () => {
|
||||
let rejected = false;
|
||||
return objectAPI.save(mockDomainObject)
|
||||
.catch(() => rejected = true)
|
||||
.then(() => expect(rejected).toBe(true));
|
||||
});
|
||||
describe("when a provider is available", () => {
|
||||
let mockProvider;
|
||||
beforeEach(() => {
|
||||
mockProvider = jasmine.createSpyObj("mock provider", [
|
||||
"create",
|
||||
"update"
|
||||
]);
|
||||
objectAPI.addProvider(TEST_NAMESPACE, mockProvider);
|
||||
})
|
||||
it("Calls 'create' on provider if object is new", () => {
|
||||
objectAPI.save(mockDomainObject);
|
||||
expect(mockProvider.create).toHaveBeenCalled();
|
||||
expect(mockProvider.update).not.toHaveBeenCalled();
|
||||
});
|
||||
it("Calls 'update' on provider if object is not new", () => {
|
||||
mockDomainObject.persisted = Date.now() - FIFTEEN_MINUTES;
|
||||
mockDomainObject.modified = Date.now();
|
||||
|
||||
objectAPI.save(mockDomainObject);
|
||||
expect(mockProvider.create).not.toHaveBeenCalled();
|
||||
expect(mockProvider.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Does not persist if the object is unchanged", () => {
|
||||
mockDomainObject.persisted =
|
||||
mockDomainObject.modified = Date.now();
|
||||
|
||||
objectAPI.save(mockDomainObject);
|
||||
expect(mockProvider.create).not.toHaveBeenCalled();
|
||||
expect(mockProvider.update).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="c-overlay__outer">
|
||||
<button
|
||||
v-if="dismissable"
|
||||
class="c-click-icon c-overlay__close-button icon-x-in-circle"
|
||||
class="c-click-icon c-overlay__close-button icon-x"
|
||||
@click="destroy"
|
||||
></button>
|
||||
<div
|
||||
|
||||
@@ -29,13 +29,12 @@
|
||||
}
|
||||
|
||||
&__close-button {
|
||||
$p: $interiorMargin;
|
||||
border-radius: 100% !important;
|
||||
$p: $interiorMargin + 2px;
|
||||
color: $overlayColorFg;
|
||||
display: inline-block;
|
||||
font-size: 1.25em;
|
||||
font-size: 1.5em;
|
||||
position: absolute;
|
||||
top: $p; right: $p;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
&__contents {
|
||||
@@ -43,7 +42,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&__top-bar {
|
||||
@@ -87,6 +86,10 @@
|
||||
.c-click-icon {
|
||||
filter: $overlayBrightnessAdjust;
|
||||
}
|
||||
|
||||
.c-object-label__name {
|
||||
filter: $objectLabelNameFilter;
|
||||
}
|
||||
}
|
||||
|
||||
body.desktop {
|
||||
@@ -100,7 +103,6 @@ body.desktop {
|
||||
}
|
||||
|
||||
// Overlay types, styling for desktop. Appended to .l-overlay-wrapper element.
|
||||
.l-overlay-large,
|
||||
.l-overlay-small,
|
||||
.l-overlay-fit {
|
||||
.c-overlay__outer {
|
||||
@@ -118,8 +120,28 @@ body.desktop {
|
||||
|
||||
.l-overlay-large {
|
||||
// Default
|
||||
.c-overlay__outer {
|
||||
@include overlaySizing($overlayOuterMarginLg);
|
||||
$pad: $interiorMarginLg;
|
||||
$tbPad: floor($pad * 0.8);
|
||||
$lrPad: $pad;
|
||||
.c-overlay {
|
||||
&__blocker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&__outer {
|
||||
@include overlaySizing($overlayOuterMarginFullscreen);
|
||||
padding: $tbPad $lrPad;
|
||||
}
|
||||
|
||||
&__close-button {
|
||||
//top: $interiorMargin;
|
||||
//right: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
.l-browse-bar {
|
||||
margin-right: 50px; // Don't cover close button
|
||||
margin-bottom: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,4 +161,4 @@ body.desktop {
|
||||
min-width: 20%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,8 +334,8 @@ define([
|
||||
});
|
||||
if (subscriber.callbacks.length === 0) {
|
||||
subscriber.unsubscribe();
|
||||
delete this.subscribeCache[keyString];
|
||||
}
|
||||
delete this.subscribeCache[keyString];
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
|
||||
@@ -156,6 +156,29 @@ define([
|
||||
expect(callbacktwo).not.toHaveBeenCalledWith('anotherValue');
|
||||
});
|
||||
|
||||
it('only deletes subscription cache when there are no more subscribers', function () {
|
||||
var unsubFunc = jasmine.createSpy('unsubscribe');
|
||||
telemetryProvider.subscribe.and.returnValue(unsubFunc);
|
||||
telemetryProvider.supportsSubscribe.and.returnValue(true);
|
||||
telemetryAPI.addProvider(telemetryProvider);
|
||||
|
||||
var callback = jasmine.createSpy('callback');
|
||||
var callbacktwo = jasmine.createSpy('callback two');
|
||||
var callbackThree = jasmine.createSpy('callback three');
|
||||
var unsubscribe = telemetryAPI.subscribe(domainObject, callback);
|
||||
var unsubscribeTwo = telemetryAPI.subscribe(domainObject, callbacktwo);
|
||||
|
||||
expect(telemetryProvider.subscribe.calls.count()).toBe(1);
|
||||
unsubscribe();
|
||||
var unsubscribeThree = telemetryAPI.subscribe(domainObject, callbackThree);
|
||||
// Regression test for where subscription cache was deleted on each unsubscribe, resulting in
|
||||
// superfluous additional subscriptions. If the subscription cache is being deleted on each unsubscribe,
|
||||
// then a subsequent subscribe will result in a new subscription at the provider.
|
||||
expect(telemetryProvider.subscribe.calls.count()).toBe(1);
|
||||
unsubscribeTwo();
|
||||
unsubscribeThree();
|
||||
});
|
||||
|
||||
it('does subscribe/unsubscribe', function () {
|
||||
var unsubFunc = jasmine.createSpy('unsubscribe');
|
||||
telemetryProvider.subscribe.and.returnValue(unsubFunc);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="c-lad-table-wrapper">
|
||||
<div class="c-lad-table-wrapper u-style-receiver js-style-receiver">
|
||||
<table class="c-table c-lad-table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -29,24 +29,28 @@ define([
|
||||
ClearDataAction,
|
||||
Vue
|
||||
) {
|
||||
return function plugin(appliesToObjects) {
|
||||
return function plugin(appliesToObjects, options = {indicator: true}) {
|
||||
let installIndicator = options.indicator;
|
||||
|
||||
appliesToObjects = appliesToObjects || [];
|
||||
|
||||
return function install(openmct) {
|
||||
let component = new Vue ({
|
||||
provide: {
|
||||
openmct
|
||||
},
|
||||
components: {
|
||||
GlobalClearIndicator: GlobaClearIndicator.default
|
||||
},
|
||||
template: '<GlobalClearIndicator></GlobalClearIndicator>'
|
||||
}),
|
||||
indicator = {
|
||||
element: component.$mount().$el
|
||||
};
|
||||
if (installIndicator) {
|
||||
let component = new Vue ({
|
||||
provide: {
|
||||
openmct
|
||||
},
|
||||
components: {
|
||||
GlobalClearIndicator: GlobaClearIndicator.default
|
||||
},
|
||||
template: '<GlobalClearIndicator></GlobalClearIndicator>'
|
||||
}),
|
||||
indicator = {
|
||||
element: component.$mount().$el
|
||||
};
|
||||
|
||||
openmct.indicators.add(indicator);
|
||||
openmct.indicators.add(indicator);
|
||||
}
|
||||
|
||||
openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
|
||||
};
|
||||
|
||||
@@ -46,6 +46,7 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
if (this.isEditing) {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
if (this.conditionSetIdentifier) {
|
||||
this.applySelectedConditionStyle();
|
||||
@@ -66,6 +67,7 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
subscribeToConditionSet() {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
this.openmct.objects.get(this.conditionSetIdentifier).then((conditionSetDomainObject) => {
|
||||
this.openmct.telemetry.request(conditionSetDomainObject)
|
||||
@@ -154,8 +156,8 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
this.applyStaticStyle();
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
delete this.stopProvidingTelemetry;
|
||||
this.conditionSetIdentifier = undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ export default {
|
||||
}
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
},
|
||||
initialize(conditionSetDomainObject) {
|
||||
@@ -210,6 +211,7 @@ export default {
|
||||
if (this.isEditing) {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
} else {
|
||||
this.subscribeToConditionSet();
|
||||
@@ -307,6 +309,7 @@ export default {
|
||||
this.persist(domainObjectStyles);
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
},
|
||||
updateDomainObjectItemStyles(newItems) {
|
||||
@@ -375,6 +378,7 @@ export default {
|
||||
subscribeToConditionSet() {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
if (this.conditionSetDomainObject) {
|
||||
this.openmct.telemetry.request(this.conditionSetDomainObject)
|
||||
|
||||
@@ -190,6 +190,7 @@ export default {
|
||||
if (this.isEditing) {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
} else {
|
||||
this.subscribeToConditionSet();
|
||||
@@ -325,6 +326,7 @@ export default {
|
||||
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
|
||||
if (this.unObserveObjects) {
|
||||
@@ -337,6 +339,7 @@ export default {
|
||||
subscribeToConditionSet() {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
if (this.conditionSetDomainObject) {
|
||||
this.openmct.telemetry.request(this.conditionSetDomainObject)
|
||||
@@ -494,6 +497,7 @@ export default {
|
||||
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
},
|
||||
removeConditionalStyles(domainObjectStyles, itemId) {
|
||||
|
||||
@@ -127,7 +127,7 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||
|
||||
if (validatedData) {
|
||||
if (this.isStalenessCheck()) {
|
||||
if (this.stalenessSubscription[validatedData.id]) {
|
||||
if (this.stalenessSubscription && this.stalenessSubscription[validatedData.id]) {
|
||||
this.stalenessSubscription[validatedData.id].update(validatedData);
|
||||
}
|
||||
this.telemetryDataCache[validatedData.id] = false;
|
||||
|
||||
@@ -142,12 +142,14 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
};
|
||||
}
|
||||
|
||||
let telemetryObject = this.telemetryObject;
|
||||
|
||||
return this.openmct.telemetry.request(
|
||||
this.telemetryObject,
|
||||
options
|
||||
).then(results => {
|
||||
const latestDatum = results.length ? results[results.length - 1] : {};
|
||||
const normalizedDatum = this.createNormalizedDatum(latestDatum, this.telemetryObject);
|
||||
const normalizedDatum = this.createNormalizedDatum(latestDatum, telemetryObject);
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
@@ -201,7 +203,7 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
let inputValue;
|
||||
if (metadataObject) {
|
||||
if(metadataObject.enumerations && input.length) {
|
||||
const enumeration = metadataObject.enumerations[input[0]];
|
||||
const enumeration = metadataObject.enumerations.find((item) => item.value.toString() === input[0].toString());
|
||||
if (enumeration !== undefined && enumeration.string) {
|
||||
inputValue = [enumeration.string];
|
||||
}
|
||||
|
||||
@@ -21,12 +21,14 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import TelemetryCriterion from "./TelemetryCriterion";
|
||||
import { getMockTelemetry } from "utils/testing";
|
||||
|
||||
let openmct = {},
|
||||
mockListener,
|
||||
testCriterionDefinition,
|
||||
testTelemetryObject,
|
||||
telemetryCriterion;
|
||||
telemetryCriterion,
|
||||
mockTelemetry = getMockTelemetry();
|
||||
|
||||
describe("The telemetry criterion", function () {
|
||||
|
||||
@@ -60,7 +62,7 @@ describe("The telemetry criterion", function () {
|
||||
};
|
||||
openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']);
|
||||
openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key);
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', "subscribe", "getMetadata", "getValueFormatter"]);
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', "subscribe", "getMetadata", "getValueFormatter", "request"]);
|
||||
openmct.telemetry.isTelemetryObject.and.returnValue(true);
|
||||
openmct.telemetry.subscribe.and.returnValue(function () {});
|
||||
openmct.telemetry.getValueFormatter.and.returnValue({
|
||||
@@ -109,4 +111,30 @@ describe("The telemetry criterion", function () {
|
||||
});
|
||||
expect(telemetryCriterion.result).toBeTrue();
|
||||
});
|
||||
|
||||
describe('the LAD request', () => {
|
||||
beforeEach(async () => {
|
||||
let telemetryRequestResolve;
|
||||
let telemetryRequestPromise = new Promise((resolve) => {
|
||||
telemetryRequestResolve = resolve;
|
||||
});
|
||||
openmct.telemetry.request.and.callFake(() => {
|
||||
setTimeout(() => {
|
||||
telemetryRequestResolve(mockTelemetry);
|
||||
}, 100);
|
||||
return telemetryRequestPromise;
|
||||
});
|
||||
});
|
||||
|
||||
it("returns results for slow LAD requests", async function () {
|
||||
const criteriaRequest = telemetryCriterion.requestLAD();
|
||||
telemetryCriterion.destroy();
|
||||
expect(telemetryCriterion.telemetryObject).toBeUndefined();
|
||||
setTimeout(() => {
|
||||
criteriaRequest.then((result) => {
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<template>
|
||||
<component :is="urlDefined ? 'a' : 'span'"
|
||||
class="c-condition-widget"
|
||||
class="c-condition-widget u-style-receiver js-style-receiver"
|
||||
:href="urlDefined ? internalDomainObject.url : null"
|
||||
>
|
||||
<div class="c-condition-widget__label">
|
||||
|
||||
@@ -124,7 +124,117 @@ define(['lodash'], function (_) {
|
||||
'telemetry.plot.overlay-multi': [
|
||||
VIEW_TYPES['telemetry.plot.stacked']
|
||||
]
|
||||
};
|
||||
},
|
||||
SMALL_FONT_SIZES = [
|
||||
{
|
||||
name: 'Default Size',
|
||||
value: 'default'
|
||||
},
|
||||
{
|
||||
name: '8px',
|
||||
value: '8'
|
||||
},
|
||||
{
|
||||
name: '9px',
|
||||
value: '9'
|
||||
},
|
||||
{
|
||||
name: '10px',
|
||||
value: '10'
|
||||
},
|
||||
{
|
||||
name: '11px',
|
||||
value: '11'
|
||||
},
|
||||
{
|
||||
name: '12px',
|
||||
value: '12'
|
||||
},
|
||||
{
|
||||
name: '13px',
|
||||
value: '13'
|
||||
},
|
||||
{
|
||||
name: '14px',
|
||||
value: '14'
|
||||
},
|
||||
{
|
||||
name: '16px',
|
||||
value: '16'
|
||||
},
|
||||
{
|
||||
name: '18px',
|
||||
value: '18'
|
||||
},
|
||||
{
|
||||
name: '20px',
|
||||
value: '20'
|
||||
},
|
||||
{
|
||||
name: '24px',
|
||||
value: '24'
|
||||
}
|
||||
],
|
||||
LARGE_FONT_SIZES = [
|
||||
{
|
||||
name: '28px',
|
||||
value: '28'
|
||||
},
|
||||
{
|
||||
name: '32px',
|
||||
value: '32'
|
||||
},
|
||||
{
|
||||
name: '36px',
|
||||
value: '36'
|
||||
},
|
||||
{
|
||||
name: '42px',
|
||||
value: '42'
|
||||
},
|
||||
{
|
||||
name: '48px',
|
||||
value: '48'
|
||||
},
|
||||
{
|
||||
name: '72px',
|
||||
value: '72'
|
||||
},
|
||||
{
|
||||
name: '96px',
|
||||
value: '96'
|
||||
},
|
||||
{
|
||||
name: '128px',
|
||||
value: '128'
|
||||
}
|
||||
],
|
||||
FONTS = [
|
||||
{
|
||||
name: 'Default',
|
||||
value: 'default'
|
||||
},
|
||||
{
|
||||
name: 'Bold',
|
||||
value: 'default-bold'
|
||||
},
|
||||
{
|
||||
name: 'Narrow',
|
||||
value: 'narrow'
|
||||
},
|
||||
{
|
||||
name: 'Narrow Bold',
|
||||
value: 'narrow-bold'
|
||||
},
|
||||
{
|
||||
name: 'Monospace',
|
||||
value: 'monospace'
|
||||
},
|
||||
{
|
||||
name: 'Monospace Bold',
|
||||
value: 'monospace-bold'
|
||||
}
|
||||
]
|
||||
|
||||
function getUserInput(form) {
|
||||
return openmct.$injector.get('dialogService').getUserInput(form, {});
|
||||
@@ -378,25 +488,136 @@ define(['lodash'], function (_) {
|
||||
}
|
||||
}
|
||||
|
||||
function getTextSizeMenu(selectedParent, selection) {
|
||||
const TEXT_SIZE = [8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96, 128];
|
||||
return {
|
||||
control: "select-menu",
|
||||
domainObject: selectedParent,
|
||||
applicableSelectedItems: selection.filter(selectionPath => {
|
||||
let type = selectionPath[0].context.layoutItem.type;
|
||||
return type === 'text-view' || type === 'telemetry-view';
|
||||
}),
|
||||
property: function (selectionPath) {
|
||||
return getPath(selectionPath) + ".size";
|
||||
},
|
||||
title: "Set text size",
|
||||
options: TEXT_SIZE.map(size => {
|
||||
return {
|
||||
value: size + "px"
|
||||
};
|
||||
})
|
||||
};
|
||||
function getAvailableFontSizeOptions(selection) {
|
||||
let sizeOptions = 'big';
|
||||
|
||||
selection.forEach(selectable => {
|
||||
if (selectable[0].context.item) {
|
||||
if (selectable[0].context.item.type.includes('plot') ||
|
||||
selectable[0].context.item.type.includes('table')) {
|
||||
sizeOptions = 'small';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (sizeOptions === 'small') {
|
||||
return SMALL_FONT_SIZES;
|
||||
} else {
|
||||
return SMALL_FONT_SIZES.concat(LARGE_FONT_SIZES);
|
||||
}
|
||||
}
|
||||
|
||||
function getFontSizeMenu(selectedParent, selection) {
|
||||
|
||||
if (selection.length === 1) {
|
||||
let primary = selection[0][0];
|
||||
let type = primary.context.layoutItem.type;
|
||||
|
||||
if (type === 'subobject-view') {
|
||||
let objectType = primary.context.item.type;
|
||||
|
||||
if (objectType === 'layout' ||
|
||||
objectType === 'flexible-layout' ||
|
||||
objectType === 'tabs') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
control: 'select-menu',
|
||||
domainObject: selectedParent,
|
||||
icon: "icon-font-size",
|
||||
applicableSelectedItems: selection,
|
||||
property: (selectionPath) => {
|
||||
return getPath(selectionPath) + '.fontSize';
|
||||
},
|
||||
title: "Set font size",
|
||||
options: getAvailableFontSizeOptions(selection)
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
control: 'select-menu',
|
||||
domainObject: selectedParent,
|
||||
icon: "icon-font-size",
|
||||
applicableSelectedItems: selection.filter(selectionPath => {
|
||||
let type = selectionPath[0].context.layoutItem.type;
|
||||
|
||||
if (type === 'line-view' || type === 'box-view') {
|
||||
return false;
|
||||
} else if (type === 'subobject-view') {
|
||||
let objectType = selectionPath[0].context.item.type;
|
||||
|
||||
if (objectType === 'layout' ||
|
||||
objectType === 'flexible-layout' ||
|
||||
objectType === 'tabs') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
property: (selectionPath) => {
|
||||
return getPath(selectionPath) + '.fontSize';
|
||||
},
|
||||
title: "Set font size",
|
||||
options: getAvailableFontSizeOptions(selection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getFontMenu(selectedParent, selection) {
|
||||
if (selection.length === 1) {
|
||||
let primary = selection[0][0];
|
||||
let type = primary.context.layoutItem.type;
|
||||
|
||||
if (type === 'subobject-view') {
|
||||
let objectType = primary.context.item.type;
|
||||
|
||||
if (objectType === 'layout' ||
|
||||
objectType === 'flexible-layout' ||
|
||||
objectType === 'tabs') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
control: 'select-menu',
|
||||
domainObject: selectedParent,
|
||||
icon: "icon-font",
|
||||
applicableSelectedItems: selection,
|
||||
property: (selectionPath) => {
|
||||
return getPath(selectionPath) + '.font';
|
||||
},
|
||||
title: "Set font style",
|
||||
options: FONTS
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
control: 'select-menu',
|
||||
domainObject: selectedParent,
|
||||
icon: "icon-font",
|
||||
applicableSelectedItems: selection.filter(selectionPath => {
|
||||
let type = selectionPath[0].context.layoutItem.type;
|
||||
|
||||
if (type === 'line-view' || type === 'box-view') {
|
||||
return false;
|
||||
} else if (type === 'subobject-view') {
|
||||
let objectType = selectionPath[0].context.item.type;
|
||||
|
||||
if (objectType === 'layout' ||
|
||||
objectType === 'flexible-layout' ||
|
||||
objectType === 'tabs') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
property: (selectionPath) => {
|
||||
return getPath(selectionPath) + '.font';
|
||||
},
|
||||
title: "Set font style",
|
||||
options: FONTS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTextButton(selectedParent, selection) {
|
||||
@@ -409,7 +630,7 @@ define(['lodash'], function (_) {
|
||||
property: function (selectionPath) {
|
||||
return getPath(selectionPath);
|
||||
},
|
||||
icon: "icon-font",
|
||||
icon: "icon-pencil",
|
||||
title: "Edit text properties",
|
||||
dialog: DIALOG_FORM.text
|
||||
};
|
||||
@@ -586,7 +807,8 @@ define(['lodash'], function (_) {
|
||||
'display-mode': [],
|
||||
'telemetry-value': [],
|
||||
'style': [],
|
||||
'text-style': [],
|
||||
'font-size': [],
|
||||
'font-family': [],
|
||||
'position': [],
|
||||
'duplicate': [],
|
||||
'remove': []
|
||||
@@ -622,6 +844,16 @@ define(['lodash'], function (_) {
|
||||
if (toolbar.viewSwitcher.length === 0) {
|
||||
toolbar.viewSwitcher = [getViewSwitcherMenu(selectedParent, selectionPath, selectedObjects)];
|
||||
}
|
||||
if (toolbar['font-size'].length === 0) {
|
||||
toolbar['font-size'] = [
|
||||
getFontSizeMenu(selectedParent, selectedObjects)
|
||||
];
|
||||
}
|
||||
if (toolbar['font-family'].length === 0) {
|
||||
toolbar['font-family'] = [
|
||||
getFontMenu(selectedParent, selectedObjects)
|
||||
];
|
||||
}
|
||||
} else if (layoutItem.type === 'telemetry-view') {
|
||||
if (toolbar['display-mode'].length === 0) {
|
||||
toolbar['display-mode'] = [getDisplayModeMenu(selectedParent, selectedObjects)];
|
||||
@@ -629,9 +861,14 @@ define(['lodash'], function (_) {
|
||||
if (toolbar['telemetry-value'].length === 0) {
|
||||
toolbar['telemetry-value'] = [getTelemetryValueMenu(selectionPath, selectedObjects)];
|
||||
}
|
||||
if (toolbar['text-style'].length === 0) {
|
||||
toolbar['text-style'] = [
|
||||
getTextSizeMenu(selectedParent, selectedObjects)
|
||||
if (toolbar['font-size'].length === 0) {
|
||||
toolbar['font-size'] = [
|
||||
getFontSizeMenu(selectedParent, selectedObjects)
|
||||
];
|
||||
}
|
||||
if (toolbar['font-family'].length === 0) {
|
||||
toolbar['font-family'] = [
|
||||
getFontMenu(selectedParent, selectedObjects)
|
||||
];
|
||||
}
|
||||
if (toolbar.position.length === 0) {
|
||||
@@ -650,9 +887,14 @@ define(['lodash'], function (_) {
|
||||
toolbar.viewSwitcher = [getViewSwitcherMenu(selectedParent, selectionPath, selectedObjects)];
|
||||
}
|
||||
} else if (layoutItem.type === 'text-view') {
|
||||
if (toolbar['text-style'].length === 0) {
|
||||
toolbar['text-style'] = [
|
||||
getTextSizeMenu(selectedParent, selectedObjects)
|
||||
if (toolbar['font-size'].length === 0) {
|
||||
toolbar['font-size'] = [
|
||||
getFontSizeMenu(selectedParent, selectedObjects)
|
||||
];
|
||||
}
|
||||
if (toolbar['font-family'].length === 0) {
|
||||
toolbar['font-family'] = [
|
||||
getFontMenu(selectedParent, selectedObjects)
|
||||
];
|
||||
}
|
||||
if (toolbar.position.length === 0) {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
@endMove="() => $emit('endMove')"
|
||||
>
|
||||
<div
|
||||
class="c-box-view"
|
||||
class="c-box-view u-style-receiver js-style-receiver"
|
||||
:class="[styleClass]"
|
||||
:style="style"
|
||||
></div>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="l-layout"
|
||||
class="l-layout u-style-receiver js-style-receiver"
|
||||
:class="{
|
||||
'is-multi-selected': selectedLayoutItems.length > 1,
|
||||
'allow-editing': isEditing
|
||||
@@ -587,7 +587,10 @@ export default {
|
||||
}
|
||||
},
|
||||
updateTelemetryFormat(item, format) {
|
||||
let index = this.layoutItems.findIndex(item);
|
||||
let index = this.layoutItems.findIndex((layoutItem) => {
|
||||
return layoutItem.id === item.id;
|
||||
});
|
||||
|
||||
item.format = format;
|
||||
this.mutate(`configuration.items[${index}]`, item);
|
||||
},
|
||||
@@ -609,6 +612,13 @@ export default {
|
||||
object.composition.push(...composition);
|
||||
}
|
||||
|
||||
if (object.modified || object.persisted) {
|
||||
object.modified = undefined;
|
||||
object.persisted = undefined;
|
||||
delete object.modified;
|
||||
delete object.persisted;
|
||||
}
|
||||
|
||||
object.name = objectName;
|
||||
object.identifier = identifier;
|
||||
object.location = parentKeyString;
|
||||
|
||||
@@ -81,6 +81,7 @@ export default {
|
||||
style() {
|
||||
let backgroundImage = 'url(' + this.item.url + ')';
|
||||
let border = '1px solid ' + this.item.stroke;
|
||||
|
||||
if (this.itemStyle) {
|
||||
if (this.itemStyle.imageUrl !== undefined) {
|
||||
backgroundImage = 'url(' + this.itemStyle.imageUrl + ')';
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
class="l-layout__frame c-frame"
|
||||
:class="{
|
||||
'no-frame': !item.hasFrame,
|
||||
'u-inspectable': inspectable
|
||||
'u-inspectable': inspectable,
|
||||
'is-in-small-container': size.width < 600 || size.height < 600
|
||||
}"
|
||||
:style="style"
|
||||
>
|
||||
<slot></slot>
|
||||
|
||||
<div
|
||||
class="c-frame-edit__move"
|
||||
class="c-frame__move-bar"
|
||||
@mousedown="isEditing ? startMove([1,1], [0,0], $event) : null"
|
||||
></div>
|
||||
</div>
|
||||
@@ -61,6 +61,13 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
size() {
|
||||
let {width, height} = this.item;
|
||||
return {
|
||||
width: (this.gridSize[0] * width),
|
||||
height: (this.gridSize[1] * height)
|
||||
};
|
||||
},
|
||||
style() {
|
||||
let {x, y, width, height} = this.item;
|
||||
return {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="l-layout__frame c-frame no-frame"
|
||||
class="l-layout__frame c-frame no-frame c-line-view"
|
||||
:class="[styleClass]"
|
||||
:style="style"
|
||||
>
|
||||
@@ -31,14 +31,20 @@
|
||||
height="100%"
|
||||
>
|
||||
<line
|
||||
class="c-line-view__hover-indicator"
|
||||
v-bind="linePosition"
|
||||
vector-effect="non-scaling-stroke"
|
||||
/>
|
||||
<line
|
||||
class="c-line-view__line"
|
||||
v-bind="linePosition"
|
||||
:stroke="stroke"
|
||||
stroke-width="2"
|
||||
vector-effect="non-scaling-stroke"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<div
|
||||
class="c-frame-edit__move"
|
||||
class="c-frame__move-bar"
|
||||
@mousedown="startDrag($event)"
|
||||
></div>
|
||||
<div
|
||||
@@ -49,7 +55,8 @@
|
||||
class="c-frame-edit__handle"
|
||||
:class="startHandleClass"
|
||||
@mousedown="startDrag($event, 'start')"
|
||||
></div>
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="c-frame-edit__handle"
|
||||
:class="endHandleClass"
|
||||
@@ -68,14 +75,18 @@ const START_HANDLE_QUADRANTS = {
|
||||
1: 'c-frame-edit__handle--sw',
|
||||
2: 'c-frame-edit__handle--se',
|
||||
3: 'c-frame-edit__handle--ne',
|
||||
4: 'c-frame-edit__handle--nw'
|
||||
4: 'c-frame-edit__handle--nw',
|
||||
5: 'c-frame-edit__handle--nw',
|
||||
6: 'c-frame-edit__handle--ne'
|
||||
};
|
||||
|
||||
const END_HANDLE_QUADRANTS = {
|
||||
1: 'c-frame-edit__handle--ne',
|
||||
2: 'c-frame-edit__handle--nw',
|
||||
3: 'c-frame-edit__handle--sw',
|
||||
4: 'c-frame-edit__handle--se'
|
||||
4: 'c-frame-edit__handle--se',
|
||||
5: 'c-frame-edit__handle--sw',
|
||||
6: 'c-frame-edit__handle--nw'
|
||||
};
|
||||
|
||||
export default {
|
||||
@@ -158,6 +169,12 @@ export default {
|
||||
},
|
||||
vectorQuadrant() {
|
||||
let {x, y, x2, y2} = this.position;
|
||||
if (x2 === x) {
|
||||
return 5; // Vertical line
|
||||
}
|
||||
if (y2 === y) {
|
||||
return 6; // Horizontal line
|
||||
}
|
||||
if (x2 > x) {
|
||||
if (y2 < y) {
|
||||
return 1;
|
||||
@@ -170,21 +187,27 @@ export default {
|
||||
return 3;
|
||||
},
|
||||
linePosition() {
|
||||
return this.vectorQuadrant % 2 !== 0
|
||||
// odd vectorQuadrant slopes up
|
||||
? {
|
||||
x1: '0%',
|
||||
y1: '100%',
|
||||
x2: '100%',
|
||||
y2: '0%'
|
||||
}
|
||||
// even vectorQuadrant slopes down
|
||||
: {
|
||||
x1: '0%',
|
||||
y1: '0%',
|
||||
x2: '100%',
|
||||
y2: '100%'
|
||||
};
|
||||
let pos = {};
|
||||
switch(this.vectorQuadrant) {
|
||||
case 1:
|
||||
case 3:
|
||||
// slopes up
|
||||
pos = {x1: '0%', y1: '100%', x2: '100%', y2: '0%'};
|
||||
break;
|
||||
case 5:
|
||||
// vertical
|
||||
pos = {x1: '0%', y1: '0%', x2: '0%', y2: '100%'};
|
||||
break;
|
||||
case 6:
|
||||
// horizontal
|
||||
pos = {x1: '0%', y1: '0%', x2: '100%', y2: '0%'};
|
||||
break;
|
||||
default:
|
||||
// slopes down
|
||||
pos = {x1: '0%', y1: '0%', x2: '100%', y2: '100%'};
|
||||
break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -209,8 +232,7 @@ export default {
|
||||
layoutItem: this.item,
|
||||
index: this.index
|
||||
};
|
||||
this.removeSelectable = this.openmct.selection.selectable(
|
||||
this.$el, this.context, this.initSelect);
|
||||
this.removeSelectable = this.openmct.selection.selectable(this.$el, this.context, this.initSelect);
|
||||
},
|
||||
destroyed() {
|
||||
if (this.removeSelectable) {
|
||||
@@ -224,12 +246,17 @@ export default {
|
||||
document.body.addEventListener('mousemove', this.continueDrag);
|
||||
document.body.addEventListener('mouseup', this.endDrag);
|
||||
this.startPosition = [event.pageX, event.pageY];
|
||||
this.dragPosition = {
|
||||
x: this.item.x,
|
||||
y: this.item.y,
|
||||
x2: this.item.x2,
|
||||
y2: this.item.y2
|
||||
};
|
||||
let {x, y, x2, y2} = this.item;
|
||||
this.dragPosition = {x, y, x2, y2};
|
||||
if (x === x2 || y === y2) {
|
||||
if (y > y2 || x < x2) {
|
||||
if (this.dragging === 'start') {
|
||||
this.dragging = 'end';
|
||||
} else if (this.dragging === 'end') {
|
||||
this.dragging = 'start';
|
||||
}
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
},
|
||||
continueDrag(event) {
|
||||
@@ -263,7 +290,7 @@ export default {
|
||||
},
|
||||
calculateDragPosition(pxDeltaX, pxDeltaY) {
|
||||
let gridDeltaX = Math.round(pxDeltaX / this.gridSize[0]);
|
||||
let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]?
|
||||
let gridDeltaY = Math.round(pxDeltaY / this.gridSize[1]);
|
||||
let {x, y, x2, y2} = this.item;
|
||||
let dragPosition = {x, y, x2, y2};
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
:object-path="currentObjectPath"
|
||||
:has-frame="item.hasFrame"
|
||||
:show-edit-view="false"
|
||||
:font-size="item.fontSize"
|
||||
:font="item.font"
|
||||
/>
|
||||
</layout-frame>
|
||||
</template>
|
||||
@@ -73,6 +75,8 @@ export default {
|
||||
y: position[1],
|
||||
identifier: domainObject.identifier,
|
||||
hasFrame: hasFrameByDefault(domainObject.type),
|
||||
fontSize: 'default',
|
||||
font: 'default',
|
||||
viewKey
|
||||
};
|
||||
},
|
||||
@@ -120,7 +124,6 @@ export default {
|
||||
if (!this.context) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.layoutItem = newItem;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -30,11 +30,19 @@
|
||||
>
|
||||
<div
|
||||
v-if="domainObject"
|
||||
class="c-telemetry-view"
|
||||
:class="styleClass"
|
||||
class="u-style-receiver c-telemetry-view"
|
||||
:class="{
|
||||
styleClass,
|
||||
'is-missing': domainObject.status === 'missing'
|
||||
}"
|
||||
:style="styleObject"
|
||||
:data-font-size="item.fontSize"
|
||||
:data-font="item.font"
|
||||
@contextmenu.prevent="showContextMenu"
|
||||
>
|
||||
<div class="is-missing__indicator"
|
||||
title="This item is missing"
|
||||
></div>
|
||||
<div
|
||||
v-if="showLabel"
|
||||
class="c-telemetry-view__label"
|
||||
@@ -83,7 +91,8 @@ export default {
|
||||
stroke: "",
|
||||
fill: "",
|
||||
color: "",
|
||||
size: "13px"
|
||||
fontSize: 'default',
|
||||
font: 'default'
|
||||
};
|
||||
},
|
||||
inject: ['openmct', 'objectPath'],
|
||||
@@ -130,10 +139,15 @@ export default {
|
||||
return displayMode === 'all' || displayMode === 'value';
|
||||
},
|
||||
styleObject() {
|
||||
return Object.assign({}, {
|
||||
fontSize: this.item.size
|
||||
}, this.itemStyle);
|
||||
let size;
|
||||
//for legacy size support
|
||||
if (!this.item.fontSize) {
|
||||
size = this.item.size
|
||||
}
|
||||
|
||||
return Object.assign({}, {
|
||||
size
|
||||
}, this.itemStyle);
|
||||
},
|
||||
fieldName() {
|
||||
return this.valueMetadata && this.valueMetadata.name;
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
@endMove="() => $emit('endMove')"
|
||||
>
|
||||
<div
|
||||
class="c-text-view"
|
||||
class="c-text-view u-style-receiver js-style-receiver"
|
||||
:data-font-size="item.fontSize"
|
||||
:data-font="item.font"
|
||||
:class="[styleClass]"
|
||||
:style="style"
|
||||
>
|
||||
@@ -47,13 +49,14 @@ export default {
|
||||
return {
|
||||
fill: '',
|
||||
stroke: '',
|
||||
size: '13px',
|
||||
color: '',
|
||||
x: 1,
|
||||
y: 1,
|
||||
width: 10,
|
||||
height: 5,
|
||||
text: element.text
|
||||
text: element.text,
|
||||
fontSize: 'default',
|
||||
font: 'default'
|
||||
};
|
||||
},
|
||||
inject: ['openmct'],
|
||||
@@ -84,8 +87,14 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
let size;
|
||||
//legacy size support
|
||||
if (!this.item.fontSize) {
|
||||
size = this.item.size;
|
||||
}
|
||||
|
||||
return Object.assign({
|
||||
fontSize: this.item.size
|
||||
size
|
||||
}, this.itemStyle);
|
||||
}
|
||||
},
|
||||
|
||||
60
src/plugins/displayLayout/components/box-and-line-views.scss
Normal file
60
src/plugins/displayLayout/components/box-and-line-views.scss
Normal file
@@ -0,0 +1,60 @@
|
||||
.c-box-view {
|
||||
border-width: $drawingObjBorderW !important;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
.c-frame & {
|
||||
@include abs();
|
||||
}
|
||||
}
|
||||
|
||||
.c-line-view {
|
||||
&.c-frame {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.c-frame-edit {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.c-handle-info {
|
||||
background: rgba(#999, 0.2);
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
top: 5px; left: 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
svg {
|
||||
// Prevent clipping when line is horizontal and vertical
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
// Must use !important to counteract setting in normalize.min.css
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&__line {
|
||||
stroke-linecap: round;
|
||||
stroke-width: $drawingObjBorderW;
|
||||
}
|
||||
|
||||
&__hover-indicator {
|
||||
display: none;
|
||||
opacity: 0.5;
|
||||
stroke: $editFrameColorHov;
|
||||
stroke-width: $drawingObjBorderW + 4;
|
||||
}
|
||||
|
||||
.is-editing & {
|
||||
// Needed to allow line to be moved
|
||||
$w: 4px;
|
||||
min-width: $w;
|
||||
min-height: $w;
|
||||
|
||||
&:hover {
|
||||
[class*='__hover-indicator'] {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
.c-box-view {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
.c-frame & {
|
||||
@include abs();
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,13 @@
|
||||
> *:first-child {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&.is-in-small-container {
|
||||
//background: rgba(blue, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.c-frame-edit__move {
|
||||
.c-frame__move-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -29,7 +33,7 @@
|
||||
border: $editFrameSelectedBorder;
|
||||
box-shadow: $editFrameSelectedShdw;
|
||||
|
||||
.c-frame-edit__move {
|
||||
.c-frame__move-bar {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
@@ -37,7 +41,7 @@
|
||||
|
||||
/******************* DEFAULT STYLES FOR -EDIT__MOVE */
|
||||
// All object types
|
||||
.c-frame-edit__move {
|
||||
.c-frame__move-bar {
|
||||
@include abs();
|
||||
display: block;
|
||||
}
|
||||
@@ -52,7 +56,7 @@
|
||||
transition-delay: $moveBarOutDelay;
|
||||
}
|
||||
|
||||
+ .c-frame-edit__move {
|
||||
+ .c-frame__move-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -61,14 +65,14 @@
|
||||
.l-layout {
|
||||
/******************* 0 - 1 ITEM SELECTED */
|
||||
&:not(.is-multi-selected) {
|
||||
> .l-layout__frame[s-selected] {
|
||||
> .l-layout__frame {
|
||||
> .c-so-view.has-complex-content {
|
||||
> .c-so-view__local-controls {
|
||||
transition: transform $transOutTime ease-in-out;
|
||||
transition-delay: $moveBarOutDelay;
|
||||
}
|
||||
|
||||
+ .c-frame-edit__move {
|
||||
+ .c-frame__move-bar {
|
||||
transition: $transOut;
|
||||
transition-delay: $moveBarOutDelay;
|
||||
@include userSelectNone();
|
||||
@@ -89,7 +93,7 @@
|
||||
$lrOffset: 25%;
|
||||
@include grippy($editFrameMovebarColorFg);
|
||||
content: '';
|
||||
display: block;
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: $tbOffset;
|
||||
right: $lrOffset;
|
||||
@@ -111,7 +115,7 @@
|
||||
transition-delay: 0s;
|
||||
}
|
||||
|
||||
+ .c-frame-edit__move {
|
||||
+ .c-frame__move-bar {
|
||||
transition: $transIn;
|
||||
transition-delay: 0s;
|
||||
height: $editFrameMovebarH;
|
||||
@@ -119,12 +123,19 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
> .l-layout__frame[s-selected] {
|
||||
> .c-so-view.has-complex-content {
|
||||
+ .c-frame__move-bar:before {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************* > 1 ITEMS SELECTED */
|
||||
&.is-multi-selected {
|
||||
.l-layout__frame[s-selected] {
|
||||
> .c-so-view.has-complex-content + .c-frame-edit__move {
|
||||
> .c-so-view.has-complex-content + .c-frame__move-bar {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,15 @@
|
||||
@include abs();
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
@include isMissing($absPos: true);
|
||||
|
||||
.is-missing__indicator {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&.is-missing {
|
||||
border: $borderMissing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
<template>
|
||||
<a
|
||||
class="l-grid-view__item c-grid-item"
|
||||
:class="{ 'is-alias': item.isAlias === true }"
|
||||
:class="{
|
||||
'is-alias': item.isAlias === true,
|
||||
'is-missing': item.model.status === 'missing',
|
||||
'c-grid-item--unknown': item.type.cssClass === undefined || item.type.cssClass.indexOf('unknown') !== -1
|
||||
}"
|
||||
:href="objectLink"
|
||||
>
|
||||
<div
|
||||
class="c-grid-item__type-icon"
|
||||
:class="(item.type.cssClass != undefined) ? 'bg-' + item.type.cssClass : 'bg-icon-object-unknown'"
|
||||
></div>
|
||||
>
|
||||
</div>
|
||||
<div class="c-grid-item__details">
|
||||
<!-- Name and metadata -->
|
||||
<div
|
||||
@@ -22,6 +27,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="c-grid-item__controls">
|
||||
<div class="is-missing__indicator"
|
||||
title="This item is missing"
|
||||
></div>
|
||||
<div
|
||||
class="icon-people"
|
||||
title="Shared"
|
||||
|
||||
@@ -7,13 +7,19 @@
|
||||
<td class="c-list-item__name">
|
||||
<a
|
||||
ref="objectLink"
|
||||
class="c-object-label"
|
||||
:class="{ 'is-missing': item.model.status === 'missing' }"
|
||||
:href="objectLink"
|
||||
>
|
||||
<div
|
||||
class="c-list-item__type-icon"
|
||||
class="c-object-label__type-icon c-list-item__type-icon"
|
||||
:class="item.type.cssClass"
|
||||
></div>
|
||||
<div class="c-list-item__name-value">{{ item.model.name }}</div>
|
||||
>
|
||||
<span class="is-missing__indicator"
|
||||
title="This item is missing"
|
||||
></span>
|
||||
</div>
|
||||
<div class="c-object-label__name c-list-item__name">{{ item.model.name }}</div>
|
||||
</a>
|
||||
</td>
|
||||
<td class="c-list-item__type">
|
||||
|
||||
@@ -38,7 +38,15 @@
|
||||
// Object is an alias to an original.
|
||||
[class*='__type-icon'] {
|
||||
@include isAlias();
|
||||
color: $colorIconAliasForKeyFilter;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-missing {
|
||||
@include isMissing();
|
||||
|
||||
[class*='__type-icon'],
|
||||
[class*='__details'] {
|
||||
opacity: $opacityMissing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,15 +93,14 @@
|
||||
body.desktop & {
|
||||
$transOutMs: 300ms;
|
||||
flex-flow: column nowrap;
|
||||
transition: background $transOutMs ease-in-out;
|
||||
transition: $transOutMs ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background: $colorItemBgHov;
|
||||
filter: $filterItemHoverFg;
|
||||
transition: $transIn;
|
||||
|
||||
.c-grid-item__type-icon {
|
||||
filter: $colorKeyFilterHov;
|
||||
transform: scale(1);
|
||||
transform: scale(1.1);
|
||||
transition: $transInBounce;
|
||||
}
|
||||
}
|
||||
@@ -103,7 +110,7 @@
|
||||
}
|
||||
|
||||
&__controls {
|
||||
align-items: start;
|
||||
align-items: baseline;
|
||||
flex: 0 0 auto;
|
||||
order: 1;
|
||||
.c-info-button,
|
||||
@@ -115,7 +122,6 @@
|
||||
font-size: floor($gridItemDesk / 3);
|
||||
margin: $interiorMargin 22.5% $interiorMargin * 3 22.5%;
|
||||
order: 2;
|
||||
transform: scale(0.9);
|
||||
transform-origin: center;
|
||||
transition: all $transOutMs ease-in-out;
|
||||
}
|
||||
|
||||
@@ -1,37 +1,17 @@
|
||||
/******************************* LIST ITEM */
|
||||
.c-list-item {
|
||||
&__name a {
|
||||
display: flex;
|
||||
|
||||
> * + * { margin-left: $interiorMarginSm; }
|
||||
}
|
||||
|
||||
&__type-icon {
|
||||
// Have to do it this way instead of using icon-* class, due to need to apply alias to the icon
|
||||
color: $colorKey;
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
margin-right:$interiorMarginSm;
|
||||
color: $colorItemTreeIcon;
|
||||
}
|
||||
|
||||
&__name-value {
|
||||
&__name {
|
||||
@include ellipsize();
|
||||
}
|
||||
|
||||
&.is-alias {
|
||||
// Object is an alias to an original.
|
||||
[class*='__type-icon'] {
|
||||
&:after {
|
||||
color: $colorIconAlias;
|
||||
content: $glyph-icon-link;
|
||||
font-family: symbolsfont;
|
||||
display: block;
|
||||
position: absolute;
|
||||
text-shadow: rgba(black, 0.5) 0 1px 2px;
|
||||
top: auto; left: -1px; bottom: 1px; right: auto;
|
||||
transform-origin: bottom left;
|
||||
transform: scale(0.65);
|
||||
}
|
||||
@include isAlias();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: $colorListItemBgHov;
|
||||
background: $colorItemTreeHoverBg;
|
||||
filter: $filterHov;
|
||||
transition: $transIn;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,13 +29,13 @@
|
||||
>
|
||||
</div>
|
||||
<div class="c-imagery__control-bar">
|
||||
<div class="c-imagery__timestamp">{{ getTime() }}</div>
|
||||
<div class="c-imagery__timestamp u-style-receiver js-style-receiver">{{ getTime() }}</div>
|
||||
<div class="h-local-controls flex-elem">
|
||||
<a
|
||||
<button
|
||||
class="c-button icon-pause pause-play"
|
||||
:class="{'is-paused': paused()}"
|
||||
@click="paused(!paused())"
|
||||
></a>
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -228,8 +228,8 @@ export default {
|
||||
subscribe() {
|
||||
this.unsubscribe = this.openmct.telemetry
|
||||
.subscribe(this.domainObject, (datum) => {
|
||||
let parsedTimestamp = this.timeFormat.parse(datum[this.timeKey]),
|
||||
bounds = this.openmct.time.bounds();
|
||||
let parsedTimestamp = this.timeFormat.parse(datum);
|
||||
let bounds = this.openmct.time.bounds();
|
||||
|
||||
if(parsedTimestamp >= bounds.start && parsedTimestamp <= bounds.end) {
|
||||
this.updateHistory(datum);
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
height: 135px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding-bottom: $interiorMarginSm;
|
||||
|
||||
&.is-paused {
|
||||
background: rgba($colorPausedBg, 0.4);
|
||||
@@ -99,7 +100,7 @@
|
||||
.c-imagery {
|
||||
.h-local-controls--overlay-content {
|
||||
position: absolute;
|
||||
right: $interiorMargin; top: $interiorMargin;
|
||||
left: $interiorMargin; top: $interiorMargin;
|
||||
z-index: 2;
|
||||
background: $colorLocalControlOvrBg;
|
||||
border-radius: $basicCr;
|
||||
|
||||
@@ -248,7 +248,8 @@ export default {
|
||||
previewEmbed() {
|
||||
const self = this;
|
||||
const previewAction = new PreviewAction(self.openmct);
|
||||
previewAction.invoke(JSON.parse(self.embed.objectPath));
|
||||
this.openmct.objects.get(self.embed.domainObject.identifier)
|
||||
.then(domainObject => previewAction.invoke([domainObject]));
|
||||
},
|
||||
removeEmbed(success) {
|
||||
if (!success) {
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
<div class="c-snapshots-h">
|
||||
<div class="l-browse-bar">
|
||||
<div class="l-browse-bar__start">
|
||||
<div class="l-browse-bar__object-name--w icon-notebook">
|
||||
<div class="l-browse-bar__object-name">
|
||||
Notebook Snapshots
|
||||
<span v-if="snapshots.length"
|
||||
class="l-browse-bar__object-details"
|
||||
> {{ snapshots.length }} of {{ getNotebookSnapshotMaxCount() }}
|
||||
</span>
|
||||
<div class="l-browse-bar__object-name--w">
|
||||
<div class="l-browse-bar__object-name c-object-label">
|
||||
<div class="c-object-label__type-icon icon-notebook"></div>
|
||||
<div class="c-object-label__name">
|
||||
Notebook Snapshots
|
||||
<span v-if="snapshots.length"
|
||||
class="l-browse-bar__object-details"
|
||||
> {{ snapshots.length }} of {{ getNotebookSnapshotMaxCount() }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<PopupMenu v-if="snapshots.length > 0"
|
||||
:popup-menu-items="popupMenuItems"
|
||||
|
||||
@@ -95,8 +95,7 @@ export const createNewEmbed = (snapshotMeta, snapshot = '') => {
|
||||
id: 'embed-' + date,
|
||||
name,
|
||||
snapshot,
|
||||
type,
|
||||
objectPath: JSON.stringify(objectPath)
|
||||
type
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="notifications.length > 0"
|
||||
v-show="notifications.length > 0"
|
||||
class="c-indicator c-indicator--clickable icon-bell"
|
||||
:class="[severityClass]"
|
||||
>
|
||||
|
||||
@@ -21,24 +21,34 @@
|
||||
-->
|
||||
<div class="gl-plot plot-legend-{{legend.get('position')}} {{legend.get('expanded')? 'plot-legend-expanded' : 'plot-legend-collapsed'}}">
|
||||
<div class="c-plot-legend gl-plot-legend"
|
||||
ng-class="{ 'hover-on-plot': !!highlights.length }"
|
||||
ng-show="legend.get('position') !== 'hidden'">
|
||||
ng-class="{
|
||||
'hover-on-plot': !!highlights.length,
|
||||
'is-legend-hidden': legend.get('hideLegendWhenSmall')
|
||||
}"
|
||||
>
|
||||
<div class="c-plot-legend__view-control gl-plot-legend__view-control c-disclosure-triangle is-enabled"
|
||||
ng-class="{ 'c-disclosure-triangle--expanded': legend.get('expanded') }"
|
||||
ng-click="legend.set('expanded', !legend.get('expanded'));">
|
||||
</div>
|
||||
|
||||
<div class="c-plot-legend__wrapper">
|
||||
<div class="c-plot-legend__wrapper"
|
||||
ng-class="{ 'is-cursor-locked': !!lockHighlightPoint }">
|
||||
|
||||
<!-- COLLAPSED PLOT LEGEND -->
|
||||
<div class="plot-wrapper-collapsed-legend"
|
||||
ng-class="{'icon-cursor-lock': !!lockHighlightPoint}">
|
||||
ng-class="{'is-cursor-locked': !!lockHighlightPoint }">
|
||||
<div class="c-state-indicator__alert-cursor-lock icon-cursor-lock" title="Cursor is point locked. Click anywhere in the plot to unlock."></div>
|
||||
<div class="plot-legend-item"
|
||||
ng-repeat="series in series track by $index">
|
||||
ng-class="{
|
||||
'is-missing': series.domainObject.status === 'missing'
|
||||
}"
|
||||
ng-repeat="series in series track by $index"
|
||||
>
|
||||
<div class="plot-series-swatch-and-name">
|
||||
<span class="plot-series-color-swatch"
|
||||
ng-style="{ 'background-color': series.get('color').asHexString() }">
|
||||
</span>
|
||||
<span class="is-missing__indicator" title="This item is missing"></span>
|
||||
<span class="plot-series-name">{{ series.get('name') }}</span>
|
||||
</div>
|
||||
<div class="plot-series-value hover-value-enabled value-to-display-{{ legend.get('valueToShowWhenCollapsed') }} {{ series.closest.mctLimitState.cssClass }}"
|
||||
@@ -55,7 +65,10 @@
|
||||
</div>
|
||||
|
||||
<!-- EXPANDED PLOT LEGEND -->
|
||||
<div class="plot-wrapper-expanded-legend">
|
||||
<div class="plot-wrapper-expanded-legend"
|
||||
ng-class="{'is-cursor-locked': !!lockHighlightPoint }"
|
||||
>
|
||||
<div class="c-state-indicator__alert-cursor-lock--verbose icon-cursor-lock" title="Click anywhere in the plot to unlock."> Cursor locked to point</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -76,12 +89,17 @@
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="series in series" class="plot-legend-item">
|
||||
<td class="plot-series-swatch-and-name"
|
||||
ng-class="{'icon-cursor-lock': !!lockHighlightPoint}">
|
||||
<tr ng-repeat="series in series"
|
||||
class="plot-legend-item"
|
||||
ng-class="{
|
||||
'is-missing': series.domainObject.status === 'missing'
|
||||
}"
|
||||
>
|
||||
<td class="plot-series-swatch-and-name">
|
||||
<span class="plot-series-color-swatch"
|
||||
ng-style="{ 'background-color': series.get('color').asHexString() }">
|
||||
</span>
|
||||
<span class="is-missing__indicator" title="This item is missing"></span>
|
||||
<span class="plot-series-name">{{ series.get('name') }}</span>
|
||||
</td>
|
||||
|
||||
@@ -117,7 +135,7 @@
|
||||
<div class="plot-wrapper-axis-and-display-area flex-elem grows">
|
||||
<div class="gl-plot-axis-area gl-plot-y has-local-controls"
|
||||
ng-style="{
|
||||
width: (tickWidth + 30) + 'px'
|
||||
width: (tickWidth + 20) + 'px'
|
||||
}">
|
||||
|
||||
<div class="gl-plot-label gl-plot-y-label"
|
||||
@@ -134,7 +152,6 @@
|
||||
{{option.name}}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
|
||||
<mct-ticks axis="yAxis">
|
||||
<div ng-repeat="tick in ticks track by tick.value"
|
||||
@@ -148,17 +165,15 @@
|
||||
</div>
|
||||
<div class="gl-plot-wrapper-display-area-and-x-axis"
|
||||
ng-style="{
|
||||
left: (tickWidth + 30) + 'px'
|
||||
}">
|
||||
<div class="l-state-indicators">
|
||||
<span class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle"
|
||||
title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data."></span>
|
||||
<span class="l-state-indicators__alert-cursor-lock icon-cursor-lock"
|
||||
title="Telemetry point selection is locked. Click anywhere in the plot to unlock."
|
||||
ng-if="lockHighlightPoint"></span>
|
||||
</div>
|
||||
left: (tickWidth + 20) + 'px'
|
||||
}">
|
||||
|
||||
<div class="gl-plot-display-area has-local-controls has-cursor-guides">
|
||||
<div class="l-state-indicators">
|
||||
<span class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle"
|
||||
title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data."></span>
|
||||
</div>
|
||||
|
||||
<mct-ticks axis="xAxis">
|
||||
<div class="gl-plot-hash hash-v"
|
||||
ng-repeat="tick in ticks track by tick.value"
|
||||
@@ -217,9 +232,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gl-plot-axis-area gl-plot-x">
|
||||
<div class="gl-plot-axis-area gl-plot-x has-local-controls">
|
||||
<mct-ticks axis="xAxis">
|
||||
<div ng-repeat="tick in ticks track by tick.value"
|
||||
<div ng-repeat="tick in ticks track by tick.text"
|
||||
class="gl-plot-tick gl-plot-x-tick-label"
|
||||
ng-style="{
|
||||
left: (100 * (tick.value - min) / interval) + '%'
|
||||
@@ -229,9 +244,21 @@
|
||||
</div>
|
||||
</mct-ticks>
|
||||
|
||||
<div class="gl-plot-label gl-plot-x-label">
|
||||
<div
|
||||
class="gl-plot-label gl-plot-x-label"
|
||||
ng-class="{'icon-gear': (xKeyOptions.length > 1 && series.length === 1)}"
|
||||
>
|
||||
{{ xAxis.get('label') }}
|
||||
</div>
|
||||
|
||||
<select
|
||||
ng-if="plot.isEnabledXKeyToggle()"
|
||||
ng-model="selectedXKeyOption.key"
|
||||
ng-change="plot.toggleXKeyOption()"
|
||||
class="gl-plot-x-label__select local-controls--hidden"
|
||||
ng-options="option.key as option.name for option in xKeyOptions"
|
||||
>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -44,9 +44,12 @@
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="The line style and rendering method to join lines for this series.">Line Method and Style</div>
|
||||
<div class="grid-cell value">
|
||||
{{ series.lineOptionsDisplayText() }}
|
||||
title="The rendering method to join lines for this series.">Line Method</div>
|
||||
<div class="grid-cell value">{{ {
|
||||
'none': 'None',
|
||||
'linear': 'Linear interpolation',
|
||||
'stepAfter': 'Step After'
|
||||
}[series.get('interpolate')] }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
@@ -111,6 +114,11 @@
|
||||
title="The position of the legend relative to the plot display area.">Position</div>
|
||||
<div class="grid-cell value capitalize">{{ config.legend.get('position') }}</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Hide the legend when the plot is small">Hide when plot small</div>
|
||||
<div class="grid-cell value">{{ config.legend.get('hideLegendWhenSmall') ? "Yes" : "No" }}</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Show the legend expanded by default">Expand by Default</div>
|
||||
|
||||
@@ -61,21 +61,6 @@
|
||||
</select>
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row" ng-show="form.interpolate !== 'none'">
|
||||
<div class="grid-cell label"
|
||||
title="The line style for this series.">Line Style</div>
|
||||
<div class="grid-cell value">
|
||||
<select ng-model="form.lineStyle">
|
||||
<option
|
||||
ng-repeat="option in lineStyleOptions"
|
||||
value="{{ option.value }}"
|
||||
ng-selected="option.value === form.lineStyle"
|
||||
>
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Whether markers are displayed.">Markers</div>
|
||||
@@ -189,7 +174,6 @@
|
||||
title="The position of the legend relative to the plot display area.">Position</div>
|
||||
<div class="grid-cell value">
|
||||
<select ng-model="form.position">
|
||||
<option value="hidden">Hidden</option>
|
||||
<option value="top">Top</option>
|
||||
<option value="right">Right</option>
|
||||
<option value="bottom">Bottom</option>
|
||||
@@ -197,6 +181,11 @@
|
||||
</select>
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Hide the legend when the plot is small">Hide when plot small</div>
|
||||
<div class="grid-cell value"><input type="checkbox" ng-model="form.hideLegendWhenSmall"/></div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Show the legend expanded by default">Expand by default</div>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="l-view-section">
|
||||
<div class="l-view-section u-style-receiver js-style-receiver">
|
||||
<div class="c-loading--overlay loading"
|
||||
ng-show="!!pending"></div>
|
||||
<mct-plot config="controller.config"
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
title="Toggle cursor guides">
|
||||
</button>
|
||||
</div>
|
||||
<div class="l-view-section">
|
||||
<div class="l-view-section u-style-receiver js-style-receiver">
|
||||
<div class="c-loading--overlay loading"
|
||||
ng-show="!!currentRequest.pending"></div>
|
||||
<div class="gl-plot child-frame u-inspectable"
|
||||
|
||||
@@ -68,7 +68,6 @@ function (
|
||||
this.listenTo(this.config.series, 'add', this.onSeriesAdd, this);
|
||||
this.listenTo(this.config.series, 'remove', this.onSeriesRemove, this);
|
||||
this.listenTo(this.config.yAxis, 'change:key', this.clearOffset, this);
|
||||
this.listenTo(this.config.xAxis, 'change:key', this.clearOffset, this);
|
||||
this.listenTo(this.config.yAxis, 'change', this.scheduleDraw);
|
||||
this.listenTo(this.config.xAxis, 'change', this.scheduleDraw);
|
||||
this.$scope.$watch('highlights', this.scheduleDraw);
|
||||
@@ -81,7 +80,14 @@ function (
|
||||
|
||||
MCTChartController.$inject = ['$scope'];
|
||||
|
||||
MCTChartController.prototype.reDraw = function (mode, o, series) {
|
||||
this.changeInterpolate(mode, o, series);
|
||||
this.changeMarkers(mode, o, series);
|
||||
this.changeAlarmMarkers(mode, o, series);
|
||||
};
|
||||
|
||||
MCTChartController.prototype.onSeriesAdd = function (series) {
|
||||
this.listenTo(series, 'change:xKey', this.reDraw, this);
|
||||
this.listenTo(series, 'change:interpolate', this.changeInterpolate, this);
|
||||
this.listenTo(series, 'change:markers', this.changeMarkers, this);
|
||||
this.listenTo(series, 'change:alarmMarkers', this.changeAlarmMarkers, this);
|
||||
@@ -380,8 +386,7 @@ function (
|
||||
this.drawAPI.drawLine(
|
||||
chartElement.getBuffer(),
|
||||
chartElement.color().asRGBAArray(),
|
||||
chartElement.count,
|
||||
chartElement.series.get('lineStyle')
|
||||
chartElement.count
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ define([
|
||||
return {
|
||||
position: 'top',
|
||||
expandByDefault: false,
|
||||
hideLegendWhenSmall: false,
|
||||
valueToShowWhenCollapsed: 'nearestValue',
|
||||
showTimestampWhenExpanded: true,
|
||||
showValueWhenExpanded: true,
|
||||
|
||||
@@ -26,14 +26,12 @@ define([
|
||||
'../configuration/Model',
|
||||
'../lib/extend',
|
||||
'EventEmitter',
|
||||
'../draw/LineStyles',
|
||||
'../draw/MarkerShapes'
|
||||
], function (
|
||||
_,
|
||||
Model,
|
||||
extend,
|
||||
EventEmitter,
|
||||
LINE_STYLES,
|
||||
MARKER_SHAPES
|
||||
) {
|
||||
|
||||
@@ -59,7 +57,6 @@ define([
|
||||
* `interpolate`: interpolate method, either `undefined` (no interpolation),
|
||||
* `linear` (points are connected via straight lines), or
|
||||
* `stepAfter` (points are connected by steps).
|
||||
* `lineStyle`: string, style of line.
|
||||
* `markers`: boolean, whether or not this series should render with markers.
|
||||
* `markerShape`: string, shape of markers.
|
||||
* `markerSize`: number, size in pixels of markers for this series.
|
||||
@@ -109,8 +106,7 @@ define([
|
||||
markers: true,
|
||||
markerShape: 'point',
|
||||
markerSize: 2.0,
|
||||
alarmMarkers: true,
|
||||
lineStyle: 'solid'
|
||||
alarmMarkers: true
|
||||
};
|
||||
},
|
||||
|
||||
@@ -419,23 +415,18 @@ define([
|
||||
this.filters = deepCopiedFilters;
|
||||
}
|
||||
},
|
||||
lineOptionsDisplayText: function () {
|
||||
const lineMethods = {
|
||||
'none': 'None',
|
||||
'linear': 'Linear interpolation',
|
||||
'stepAfter': 'Step After'
|
||||
}
|
||||
const lineMethodKey = this.get('interpolate');
|
||||
const lineMethod = lineMethods[lineMethodKey];
|
||||
getDisplayRange: function (xKey) {
|
||||
const unsortedData = this.data;
|
||||
this.data = [];
|
||||
unsortedData.forEach(point => this.add(point, false));
|
||||
|
||||
if (lineMethod === 'None') {
|
||||
return lineMethod;
|
||||
}
|
||||
const minValue = this.getXVal(this.data[0]);
|
||||
const maxValue = this.getXVal(this.data[this.data.length-1]);
|
||||
|
||||
const lineStyleKey = this.get('lineStyle');
|
||||
const lineStyle = LINE_STYLES[lineStyleKey].label;
|
||||
|
||||
return `${lineMethod}: ${lineStyle}`;
|
||||
return {
|
||||
min: minValue,
|
||||
max: maxValue
|
||||
};
|
||||
},
|
||||
markerOptionsDisplayText: function () {
|
||||
const showMarkers = this.get('markers');
|
||||
|
||||
@@ -48,6 +48,7 @@ define([
|
||||
this.set('range', this.get('range'));
|
||||
}
|
||||
this.listenTo(this, 'change:key', this.changeKey, this);
|
||||
this.listenTo(this, 'resetSeries', this.resetSeries, this);
|
||||
},
|
||||
changeKey: function (newKey) {
|
||||
var series = this.plot.series.first();
|
||||
@@ -62,8 +63,13 @@ define([
|
||||
});
|
||||
this.set('label', newKey);
|
||||
}
|
||||
|
||||
this.plot.series.forEach(function (plotSeries) {
|
||||
plotSeries.set('xKey', newKey);
|
||||
});
|
||||
},
|
||||
resetSeries: function () {
|
||||
this.plot.series.forEach(function (plotSeries) {
|
||||
plotSeries.reset();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -24,12 +24,10 @@
|
||||
define([
|
||||
'EventEmitter',
|
||||
'../lib/eventHelpers',
|
||||
'./LineStyles',
|
||||
'./MarkerShapes'
|
||||
], function (
|
||||
EventEmitter,
|
||||
eventHelpers,
|
||||
LINE_STYLES,
|
||||
MARKER_SHAPES
|
||||
) {
|
||||
|
||||
@@ -88,8 +86,9 @@ define([
|
||||
this.origin = newOrigin;
|
||||
};
|
||||
|
||||
Draw2D.prototype.drawLine = function (buf, color, points, style) {
|
||||
const pattern = LINE_STYLES[style].pattern;
|
||||
Draw2D.prototype.drawLine = function (buf, color, points) {
|
||||
var i;
|
||||
|
||||
this.setColor(color);
|
||||
|
||||
// Configure context to draw two-pixel-thick lines
|
||||
@@ -98,12 +97,11 @@ define([
|
||||
// Start a new path...
|
||||
if (buf.length > 1) {
|
||||
this.c2d.beginPath();
|
||||
this.c2d.setLineDash(pattern);
|
||||
this.c2d.moveTo(this.x(buf[0]), this.y(buf[1]));
|
||||
}
|
||||
|
||||
// ...and add points to it...
|
||||
for (let i = 2; i < points * 2; i = i + 2) {
|
||||
for (i = 2; i < points * 2; i = i + 2) {
|
||||
this.c2d.lineTo(this.x(buf[i]), this.y(buf[i + 1]));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,10 @@
|
||||
define([
|
||||
'EventEmitter',
|
||||
'../lib/eventHelpers',
|
||||
'./LineStyles',
|
||||
'./MarkerShapes'
|
||||
], function (
|
||||
EventEmitter,
|
||||
eventHelpers,
|
||||
LINE_STYLES,
|
||||
MARKER_SHAPES
|
||||
) {
|
||||
|
||||
@@ -37,42 +35,50 @@ define([
|
||||
const FRAGMENT_SHADER = `
|
||||
precision mediump float;
|
||||
uniform vec4 uColor;
|
||||
uniform int uLineStyle;
|
||||
uniform int uMarkerShape;
|
||||
uniform sampler2D uPattern;
|
||||
uniform float uPointCount;
|
||||
varying float vLengthSoFar;
|
||||
|
||||
void main(void) {
|
||||
if (uMarkerShape == 2) {
|
||||
float distance = length(2.0 * gl_PointCoord - 1.0);
|
||||
if (distance > 1.0) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
gl_FragColor = uColor;
|
||||
|
||||
if (uLineStyle == 2) {
|
||||
gl_FragColor = texture2D(
|
||||
uPattern,
|
||||
vec2(fract(vLengthSoFar * 10.0))
|
||||
);
|
||||
if (uMarkerShape > 1) {
|
||||
vec2 clipSpacePointCoord = 2.0 * gl_PointCoord - 1.0;
|
||||
|
||||
if (uMarkerShape == 2) { // circle
|
||||
float distance = length(clipSpacePointCoord);
|
||||
|
||||
if (distance > 1.0) {
|
||||
discard;
|
||||
}
|
||||
} else if (uMarkerShape == 3) { // diamond
|
||||
float distance = abs(clipSpacePointCoord.x) + abs(clipSpacePointCoord.y);
|
||||
|
||||
if (distance > 1.0) {
|
||||
discard;
|
||||
}
|
||||
} else if (uMarkerShape == 4) { // triangle
|
||||
float x = clipSpacePointCoord.x;
|
||||
float y = clipSpacePointCoord.y;
|
||||
float distance = 2.0 * x - 1.0;
|
||||
float distance2 = -2.0 * x - 1.0;
|
||||
|
||||
if (distance > y || distance2 > y) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const VERTEX_SHADER = `
|
||||
attribute vec2 aVertexPosition;
|
||||
attribute float aLengthSoFar;
|
||||
uniform vec2 uDimensions;
|
||||
uniform vec2 uOrigin;
|
||||
uniform float uPointSize;
|
||||
varying float vLengthSoFar;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1);
|
||||
gl_PointSize = uPointSize;
|
||||
vLengthSoFar = aLengthSoFar;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -133,17 +139,13 @@ define([
|
||||
// Get locations for attribs/uniforms from the
|
||||
// shader programs (to pass values into shaders at draw-time)
|
||||
this.aVertexPosition = this.gl.getAttribLocation(this.program, "aVertexPosition");
|
||||
this.aLengthSoFar = this.gl.getAttribLocation(this.program, "aLengthSoFar");
|
||||
this.uColor = this.gl.getUniformLocation(this.program, "uColor");
|
||||
this.uLineStyle = this.gl.getUniformLocation(this.program, "uLineStyle");
|
||||
this.uMarkerShape = this.gl.getUniformLocation(this.program, "uMarkerShape");
|
||||
this.uDimensions = this.gl.getUniformLocation(this.program, "uDimensions");
|
||||
this.uOrigin = this.gl.getUniformLocation(this.program, "uOrigin");
|
||||
this.uPointSize = this.gl.getUniformLocation(this.program, "uPointSize");
|
||||
this.uPointCount = this.gl.getUniformLocation(this.program, "uPointCount");
|
||||
|
||||
this.gl.enableVertexAttribArray(this.aVertexPosition);
|
||||
this.gl.enableVertexAttribArray(this.aLengthSoFar);
|
||||
|
||||
// Create a buffer to holds points which will be drawn
|
||||
this.buffer = this.gl.createBuffer();
|
||||
@@ -173,58 +175,14 @@ define([
|
||||
if (this.isContextLost) {
|
||||
return;
|
||||
}
|
||||
const lineStyle = LINE_STYLES[shape] ? LINE_STYLES[shape].drawWebGL : 0;
|
||||
|
||||
const shapeCode = MARKER_SHAPES[shape] ? MARKER_SHAPES[shape].drawWebGL : 0;
|
||||
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer);
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, buf, this.gl.DYNAMIC_DRAW);
|
||||
this.gl.vertexAttribPointer(this.aVertexPosition, 2, this.gl.FLOAT, false, 0, 0);
|
||||
this.gl.uniform4fv(this.uColor, color);
|
||||
this.gl.uniform1i(this.uLineStyle, lineStyle);
|
||||
this.gl.uniform1i(this.uMarkerShape, shapeCode);
|
||||
this.gl.uniform1f(this.uPointCount, points);
|
||||
|
||||
|
||||
const lengthSoFar = [0];
|
||||
for (let i = 1; i < points; i++) {
|
||||
const lastX = (i - 1) * 2;
|
||||
const currentX = i * 2;
|
||||
const xDelta = this.x(buf[lastX]) - this.x(buf[currentX]);
|
||||
const yDelta = this.y(buf[lastX + 1]) - this.y(buf[currentX + 1]);
|
||||
const distance = Math.sqrt(
|
||||
Math.pow(xDelta, 2)
|
||||
+ Math.pow(yDelta, 2)
|
||||
);
|
||||
|
||||
lengthSoFar.push(lengthSoFar[i - 1] + distance);
|
||||
}
|
||||
|
||||
let lineBuffer = this.gl.createBuffer();
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, lineBuffer);
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(lengthSoFar), this.gl.DYNAMIC_DRAW);
|
||||
this.gl.vertexAttribPointer(this.aLengthSoFar, 1, this.gl.FLOAT, false, 0, 0);
|
||||
|
||||
const mappedColor = color.map(function (c, i) {
|
||||
return Math.floor(c * 255);
|
||||
});
|
||||
|
||||
const dots = [
|
||||
...mappedColor,
|
||||
0,0,0,0,
|
||||
0,0,0,0,
|
||||
0,0,0,0,
|
||||
];
|
||||
|
||||
var texture = this.gl.createTexture();
|
||||
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
||||
this.gl.texImage2D(
|
||||
this.gl.TEXTURE_2D, 0, this.gl.RGBA, dots.length / 4, 1, 0,
|
||||
this.gl.RGBA, this.gl.UNSIGNED_BYTE, new Uint8Array(dots));
|
||||
this.gl.texParameteri(
|
||||
this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
|
||||
this.gl.texParameteri(
|
||||
this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
|
||||
|
||||
this.gl.uniform1i(this.uMarkerShape, shapeCode)
|
||||
this.gl.drawArrays(drawType, 0, points);
|
||||
};
|
||||
|
||||
@@ -277,14 +235,12 @@ define([
|
||||
* the line, as an RGBA color where each element
|
||||
* is in the range of 0.0-1.0
|
||||
* @param {number} points the number of points to draw
|
||||
* @param {string} style the line style
|
||||
*/
|
||||
DrawWebGL.prototype.drawLine = function (buf, color, points, style) {
|
||||
DrawWebGL.prototype.drawLine = function (buf, color, points) {
|
||||
if (this.isContextLost) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.doDraw(this.gl.LINE_STRIP, buf, color, points, style);
|
||||
this.doDraw(this.gl.LINE_STRIP, buf, color, points);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([], function () {
|
||||
/**
|
||||
* @label string (required) display name of shape
|
||||
* @drawWebGL integer (unique, required) index provided to WebGL Fragment Shader
|
||||
* @pattern array
|
||||
*/
|
||||
const LINE_STYLES = {
|
||||
solid: {
|
||||
label: 'Solid',
|
||||
drawWebGL: 1,
|
||||
drawC2D: []
|
||||
},
|
||||
dot: {
|
||||
label: 'Dot',
|
||||
drawWebGL: 2,
|
||||
drawC2D: [2, 2]
|
||||
}
|
||||
// dash: {
|
||||
// label: 'Dash',
|
||||
// drawWebGL: 3,
|
||||
// drawC2D: [5, 2]
|
||||
// }
|
||||
// dotDashDot: {
|
||||
// label: 'Dot Dash Dot',
|
||||
// drawWebGL: 4,
|
||||
// drawC2D: [5, 2, 2]
|
||||
// }
|
||||
};
|
||||
|
||||
return LINE_STYLES;
|
||||
});
|
||||
@@ -32,6 +32,7 @@ define([], function () {
|
||||
drawWebGL: 1,
|
||||
drawC2D: function (x, y, size) {
|
||||
const offset = size / 2;
|
||||
|
||||
this.c2d.fillRect(x - offset, y - offset, size, size);
|
||||
}
|
||||
},
|
||||
@@ -46,6 +47,42 @@ define([], function () {
|
||||
this.c2d.closePath();
|
||||
this.c2d.fill();
|
||||
}
|
||||
},
|
||||
diamond: {
|
||||
label: 'Diamond',
|
||||
drawWebGL: 3,
|
||||
drawC2D: function (x, y, size) {
|
||||
const offset = size / 2;
|
||||
const top = [x, y + offset];
|
||||
const right = [x + offset, y];
|
||||
const bottom = [x, y - offset];
|
||||
const left = [x - offset, y];
|
||||
|
||||
this.c2d.beginPath();
|
||||
this.c2d.moveTo(...top);
|
||||
this.c2d.lineTo(...right);
|
||||
this.c2d.lineTo(...bottom);
|
||||
this.c2d.lineTo(...left);
|
||||
this.c2d.closePath();
|
||||
this.c2d.fill();
|
||||
}
|
||||
},
|
||||
triangle: {
|
||||
label: 'Triangle',
|
||||
drawWebGL: 4,
|
||||
drawC2D: function (x, y, size) {
|
||||
const offset = size / 2;
|
||||
const v1 = [x, y - offset];
|
||||
const v2 = [x - offset, y + offset];
|
||||
const v3 = [x + offset, y + offset];
|
||||
|
||||
this.c2d.beginPath();
|
||||
this.c2d.moveTo(...v1);
|
||||
this.c2d.lineTo(...v2);
|
||||
this.c2d.lineTo(...v3);
|
||||
this.c2d.closePath();
|
||||
this.c2d.fill();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,11 @@ define([
|
||||
modelProp: 'position',
|
||||
objectPath: 'configuration.legend.position'
|
||||
},
|
||||
{
|
||||
modelProp: 'hideLegendWhenSmall',
|
||||
coerce: Boolean,
|
||||
objectPath: 'configuration.legend.hideLegendWhenSmall'
|
||||
},
|
||||
{
|
||||
modelProp: 'expandByDefault',
|
||||
coerce: Boolean,
|
||||
|
||||
@@ -22,12 +22,10 @@
|
||||
|
||||
define([
|
||||
'./PlotModelFormController',
|
||||
'../draw/LineStyles',
|
||||
'../draw/MarkerShapes',
|
||||
'lodash'
|
||||
], function (
|
||||
PlotModelFormController,
|
||||
LINE_STYLES,
|
||||
MARKER_SHAPES,
|
||||
_
|
||||
) {
|
||||
@@ -97,13 +95,6 @@ define([
|
||||
value: o.key
|
||||
};
|
||||
});
|
||||
this.$scope.lineStyleOptions = Object.entries(LINE_STYLES)
|
||||
.map(([key, obj]) => {
|
||||
return {
|
||||
name: obj.label,
|
||||
value: key
|
||||
};
|
||||
});
|
||||
this.$scope.markerShapeOptions = Object.entries(MARKER_SHAPES)
|
||||
.map(([key, obj]) => {
|
||||
return {
|
||||
@@ -122,10 +113,6 @@ define([
|
||||
modelProp: 'interpolate',
|
||||
objectPath: dynamicPathForKey('interpolate')
|
||||
},
|
||||
{
|
||||
modelProp: 'lineStyle',
|
||||
objectPath: dynamicPathForKey('lineStyle')
|
||||
},
|
||||
{
|
||||
modelProp: 'markers',
|
||||
objectPath: dynamicPathForKey('markers')
|
||||
|
||||
@@ -71,8 +71,6 @@ define([
|
||||
this.listenTo(this.$canvas, 'mouseleave', this.untrackMousePosition, this);
|
||||
this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this);
|
||||
this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this);
|
||||
|
||||
this.watchForMarquee();
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.initialize = function () {
|
||||
@@ -83,11 +81,6 @@ define([
|
||||
this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this);
|
||||
this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this);
|
||||
|
||||
this.watchForMarquee();
|
||||
|
||||
this.listenTo(this.$window, 'keydown', this.toggleInteractionMode, this);
|
||||
this.listenTo(this.$window, 'keyup', this.resetInteractionMode, this);
|
||||
|
||||
this.$scope.rectangles = [];
|
||||
this.$scope.tickWidth = 0;
|
||||
|
||||
@@ -108,12 +101,32 @@ define([
|
||||
this.listenTo(this.$scope, 'plot:tickWidth', this.onTickWidthChange, this);
|
||||
this.listenTo(this.$scope, 'plot:highlight:set', this.onPlotHighlightSet, this);
|
||||
this.listenTo(this.$scope, 'plot:reinitializeCanvas', this.initCanvas, this);
|
||||
this.listenTo(this.config.xAxis, 'resetSeries', this.setUpXAxisOptions, this);
|
||||
this.listenTo(this.config.xAxis, 'change:displayRange', this.onXAxisChange, this);
|
||||
this.listenTo(this.config.yAxis, 'change:displayRange', this.onYAxisChange, this);
|
||||
|
||||
this.setUpXAxisOptions();
|
||||
this.setUpYAxisOptions();
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.setUpXAxisOptions = function () {
|
||||
const xAxisKey = this.config.xAxis.get('key');
|
||||
|
||||
if (this.$scope.series.length === 1) {
|
||||
let metadata = this.$scope.series[0].metadata;
|
||||
|
||||
this.$scope.xKeyOptions = metadata
|
||||
.valuesForHints(['domain'])
|
||||
.map(function (o) {
|
||||
return {
|
||||
name: o.name,
|
||||
key: o.key
|
||||
};
|
||||
});
|
||||
this.$scope.selectedXKeyOption = this.getXKeyOption(xAxisKey);
|
||||
}
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.setUpYAxisOptions = function () {
|
||||
if (this.$scope.series.length === 1) {
|
||||
let metadata = this.$scope.series[0].metadata;
|
||||
@@ -243,12 +256,16 @@ define([
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.onMouseDown = function ($event) {
|
||||
// do not monitor drag events on browser context click
|
||||
if (event.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.listenTo(this.$window, 'mouseup', this.onMouseUp, this);
|
||||
this.listenTo(this.$window, 'mousemove', this.trackMousePosition, this);
|
||||
if (this.allowPan) {
|
||||
if (event.altKey) {
|
||||
return this.startPan($event);
|
||||
}
|
||||
if (this.allowMarquee) {
|
||||
} else {
|
||||
return this.startMarquee($event);
|
||||
}
|
||||
};
|
||||
@@ -261,11 +278,11 @@ define([
|
||||
this.$scope.lockHighlightPoint = !this.$scope.lockHighlightPoint;
|
||||
}
|
||||
|
||||
if (this.allowPan) {
|
||||
if (this.pan) {
|
||||
return this.endPan($event);
|
||||
}
|
||||
|
||||
if (this.allowMarquee) {
|
||||
if (this.marquee) {
|
||||
return this.endMarquee($event);
|
||||
}
|
||||
};
|
||||
@@ -289,6 +306,9 @@ define([
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.startMarquee = function ($event) {
|
||||
this.$canvas.removeClass('plot-drag');
|
||||
this.$canvas.addClass('plot-marquee');
|
||||
|
||||
this.trackMousePosition($event);
|
||||
if (this.positionOverPlot) {
|
||||
this.freeze();
|
||||
@@ -444,6 +464,9 @@ define([
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.startPan = function ($event) {
|
||||
this.$canvas.addClass('plot-drag');
|
||||
this.$canvas.removeClass('plot-marquee');
|
||||
|
||||
this.trackMousePosition($event);
|
||||
this.freeze();
|
||||
this.pan = {
|
||||
@@ -486,32 +509,6 @@ define([
|
||||
this.$scope.$emit('user:viewport:change:end');
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.watchForMarquee = function () {
|
||||
this.$canvas.removeClass('plot-drag');
|
||||
this.$canvas.addClass('plot-marquee');
|
||||
this.allowPan = false;
|
||||
this.allowMarquee = true;
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.watchForPan = function () {
|
||||
this.$canvas.addClass('plot-drag');
|
||||
this.$canvas.removeClass('plot-marquee');
|
||||
this.allowPan = true;
|
||||
this.allowMarquee = false;
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.toggleInteractionMode = function (event) {
|
||||
if (event.keyCode === 18) { // control key.
|
||||
this.watchForPan();
|
||||
}
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.resetInteractionMode = function (event) {
|
||||
if (event.keyCode === 18) {
|
||||
this.watchForMarquee();
|
||||
}
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.freeze = function () {
|
||||
this.config.yAxis.set('frozen', true);
|
||||
this.config.xAxis.set('frozen', true);
|
||||
@@ -543,6 +540,22 @@ define([
|
||||
this.cursorGuide = !this.cursorGuide;
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.getXKeyOption = function (key) {
|
||||
return this.$scope.xKeyOptions.find(option => option.key === key);
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.isEnabledXKeyToggle = function () {
|
||||
const isSinglePlot = this.$scope.xKeyOptions.length > 1 && this.$scope.series.length === 1;
|
||||
const isFrozen = this.config.xAxis.get('frozen');
|
||||
const inRealTimeMode = this.config.openmct.time.clock();
|
||||
|
||||
return isSinglePlot && !isFrozen && !inRealTimeMode;
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.toggleXKeyOption = function () {
|
||||
this.config.xAxis.set('key', this.$scope.selectedXKeyOption.key);
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.toggleYAxisLabel = function (label, options, series) {
|
||||
let yAxisObject = options.filter(o => o.name === label)[0];
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@ define([
|
||||
this.tickUpdate = false;
|
||||
this.listenTo(this.axis, 'change:displayRange', this.updateTicks, this);
|
||||
this.listenTo(this.axis, 'change:format', this.updateTicks, this);
|
||||
this.listenTo(this.axis, 'change:key', this.updateTicksForceRegeneration, this);
|
||||
this.listenTo(this.$scope, '$destroy', this.stopListening, this);
|
||||
this.updateTicks();
|
||||
}
|
||||
@@ -133,12 +134,18 @@ define([
|
||||
|
||||
/**
|
||||
* Determine whether ticks should be regenerated for a given range.
|
||||
* Ticks are updated a) if they don't exist, b) if the existing ticks are
|
||||
* outside of given range, or c) if the range exceeds the size of the tick
|
||||
* range by more than one tick step.
|
||||
* Ticks are updated
|
||||
* a) if they don't exist,
|
||||
* b) if existing ticks are outside of given range,
|
||||
* c) if range exceeds size of tick range by more than one tick step,
|
||||
* d) if forced to regenerate (ex. changing x-axis metadata).
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
MCTTicksController.prototype.shouldRegenerateTicks = function (range) {
|
||||
MCTTicksController.prototype.shouldRegenerateTicks = function (range, forceRegeneration) {
|
||||
if (forceRegeneration) {
|
||||
return true;
|
||||
}
|
||||
if (!this.tickRange || !this.$scope.ticks || !this.$scope.ticks.length) {
|
||||
return true;
|
||||
}
|
||||
@@ -166,7 +173,11 @@ define([
|
||||
return ticks(range.min, range.max, number);
|
||||
};
|
||||
|
||||
MCTTicksController.prototype.updateTicks = function () {
|
||||
MCTTicksController.prototype.updateTicksForceRegeneration = function () {
|
||||
this.updateTicks(true);
|
||||
}
|
||||
|
||||
MCTTicksController.prototype.updateTicks = function (forceRegeneration = false) {
|
||||
var range = this.axis.get('displayRange');
|
||||
if (!range) {
|
||||
delete this.$scope.min;
|
||||
@@ -184,7 +195,7 @@ define([
|
||||
this.$scope.min = range.min;
|
||||
this.$scope.max = range.max;
|
||||
this.$scope.interval = Math.abs(range.min - range.max);
|
||||
if (this.shouldRegenerateTicks(range)) {
|
||||
if (this.shouldRegenerateTicks(range, forceRegeneration)) {
|
||||
var newTicks = this.getTicks();
|
||||
this.tickRange = {
|
||||
min: Math.min.apply(Math, newTicks),
|
||||
@@ -242,6 +253,7 @@ define([
|
||||
this.$scope.$emit('plot:tickWidth', tickWidth);
|
||||
this.shouldCheckWidth = false;
|
||||
}
|
||||
|
||||
this.$scope.$digest();
|
||||
this.tickUpdate = false;
|
||||
};
|
||||
|
||||
@@ -130,6 +130,9 @@ define([
|
||||
};
|
||||
|
||||
PlotController.prototype.addSeries = function (series) {
|
||||
this.listenTo(series, 'change:xKey', function (xKey) {
|
||||
this.setDisplayRange(series, xKey);
|
||||
}, this);
|
||||
this.listenTo(series, 'change:yKey', function () {
|
||||
this.loadSeriesData(series);
|
||||
}, this);
|
||||
@@ -141,6 +144,16 @@ define([
|
||||
this.loadSeriesData(series);
|
||||
};
|
||||
|
||||
|
||||
PlotController.prototype.setDisplayRange = function (series, xKey) {
|
||||
if (this.config.series.models.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const displayRange = series.getDisplayRange(xKey);
|
||||
this.config.xAxis.set('range', displayRange);
|
||||
};
|
||||
|
||||
PlotController.prototype.removeSeries = function (plotSeries) {
|
||||
this.stopListening(plotSeries);
|
||||
};
|
||||
@@ -162,6 +175,7 @@ define([
|
||||
|
||||
PlotController.prototype.onTimeSystemChange = function (timeSystem) {
|
||||
this.config.xAxis.set('key', timeSystem.key);
|
||||
this.config.xAxis.emit('resetSeries');
|
||||
};
|
||||
|
||||
PlotController.prototype.destroy = function () {
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Espresso Theme
|
||||
A light colored theme for the Open MCT user interface.
|
||||
|
||||
## Installation
|
||||
```js
|
||||
openmct.install(openmct.plugins.Snow());
|
||||
```
|
||||
@@ -17,6 +17,19 @@
|
||||
margin-right: $interiorMarginSm;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&__label {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&__close-btn {
|
||||
flex: 0 0 auto;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
&__object-holder {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div
|
||||
class="c-tabs-view__tabs-holder c-tabs"
|
||||
:class="{
|
||||
'is-dragging': isDragging,
|
||||
'is-dragging': isDragging && allowEditing,
|
||||
'is-mouse-over': allowDrop
|
||||
}"
|
||||
>
|
||||
@@ -19,18 +19,21 @@
|
||||
>
|
||||
Drag objects here to add them to this view.
|
||||
</div>
|
||||
<button
|
||||
<div
|
||||
v-for="(tab,index) in tabsList"
|
||||
:key="index"
|
||||
class="c-tabs-view__tab c-tab"
|
||||
:class="[
|
||||
{'is-current': isCurrent(tab)},
|
||||
tab.type.definition.cssClass
|
||||
]"
|
||||
class="c-tab c-tabs-view__tab"
|
||||
:class="{
|
||||
'is-current': isCurrent(tab)
|
||||
}"
|
||||
@click="showTab(tab, index)"
|
||||
>
|
||||
<span class="c-button__label">{{ tab.domainObject.name }}</span>
|
||||
</button>
|
||||
<span class="c-button__label c-tabs-view__tab__label">{{ tab.domainObject.name }}</span>
|
||||
<button v-if="isEditing"
|
||||
class="icon-x c-click-icon c-tabs-view__tab__close-btn"
|
||||
@click="showRemoveDialog(index)"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="(tab, index) in tabsList"
|
||||
@@ -38,15 +41,6 @@
|
||||
class="c-tabs-view__object-holder"
|
||||
:class="{'c-tabs-view__object-holder--hidden': !isCurrent(tab)}"
|
||||
>
|
||||
<div
|
||||
v-if="currentTab"
|
||||
class="c-tabs-view__object-name c-object-label l-browse-bar__object-name--w"
|
||||
:class="currentTab.type.definition.cssClass"
|
||||
>
|
||||
<div class="l-browse-bar__object-name c-object-label__name">
|
||||
{{ currentTab.domainObject.name }}
|
||||
</div>
|
||||
</div>
|
||||
<object-view
|
||||
v-if="internalDomainObject.keep_alive ? currentTab : isCurrent(tab)"
|
||||
class="c-tabs-view__object"
|
||||
@@ -58,6 +52,13 @@
|
||||
|
||||
<script>
|
||||
import ObjectView from '../../../ui/components/ObjectView.vue';
|
||||
import RemoveAction from '../../remove/RemoveAction.js';
|
||||
import {
|
||||
getSearchParam,
|
||||
setSearchParam,
|
||||
deleteSearchParam
|
||||
} from 'utils/openmctLocation';
|
||||
|
||||
|
||||
var unknownObjectType = {
|
||||
definition: {
|
||||
@@ -71,53 +72,114 @@ export default {
|
||||
components: {
|
||||
ObjectView
|
||||
},
|
||||
props: {
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
|
||||
return {
|
||||
internalDomainObject: this.domainObject,
|
||||
currentTab: {},
|
||||
currentTabIndex: undefined,
|
||||
tabsList: [],
|
||||
setCurrentTab: true,
|
||||
isDragging: false,
|
||||
allowDrop: false
|
||||
allowDrop: false,
|
||||
searchTabKey: `tabs.pos.${keyString}`
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
allowEditing() {
|
||||
return !this.internalDomainObject.locked && this.isEditing;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.composition) {
|
||||
this.composition.on('add', this.addItem);
|
||||
this.composition.on('remove', this.removeItem);
|
||||
this.composition.on('reorder', this.onReorder);
|
||||
this.composition.load().then(() => {
|
||||
let currentTabIndex = this.domainObject.currentTabIndex;
|
||||
let currentTabIndexFromURL = getSearchParam(this.searchTabKey);
|
||||
let currentTabIndexFromDomainObject = this.internalDomainObject.currentTabIndex;
|
||||
|
||||
if (currentTabIndex !== undefined && this.tabsList.length > currentTabIndex) {
|
||||
this.currentTab = this.tabsList[currentTabIndex];
|
||||
if (currentTabIndexFromURL !== null) {
|
||||
this.setCurrentTabByIndex(currentTabIndexFromURL);
|
||||
} else if (currentTabIndexFromDomainObject !== undefined) {
|
||||
this.setCurrentTabByIndex(currentTabIndexFromDomainObject);
|
||||
this.storeCurrentTabIndexInURL(currentTabIndexFromDomainObject);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.unsubscribe = this.openmct.objects.observe(this.internalDomainObject, '*', this.updateInternalDomainObject);
|
||||
|
||||
this.RemoveAction = new RemoveAction(this.openmct);
|
||||
document.addEventListener('dragstart', this.dragstart);
|
||||
document.addEventListener('dragend', this.dragend);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.persistCurrentTabIndex(this.currentTabIndex);
|
||||
},
|
||||
destroyed() {
|
||||
this.composition.off('add', this.addItem);
|
||||
this.composition.off('remove', this.removeItem);
|
||||
this.composition.off('reorder', this.onReorder);
|
||||
|
||||
this.unsubscribe();
|
||||
this.clearCurrentTabIndexFromURL();
|
||||
|
||||
document.removeEventListener('dragstart', this.dragstart);
|
||||
document.removeEventListener('dragend', this.dragend);
|
||||
},
|
||||
methods:{
|
||||
setCurrentTabByIndex(index) {
|
||||
if (this.tabsList[index]) {
|
||||
this.currentTab = this.tabsList[index];
|
||||
}
|
||||
},
|
||||
showTab(tab, index) {
|
||||
if (index !== undefined) {
|
||||
this.storeCurrentTabIndex(index);
|
||||
this.storeCurrentTabIndexInURL(index);
|
||||
}
|
||||
|
||||
this.currentTab = tab;
|
||||
},
|
||||
showRemoveDialog(index) {
|
||||
if(!this.tabsList[index]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let activeTab = this.tabsList[index];
|
||||
let childDomainObject = activeTab.domainObject
|
||||
|
||||
let prompt = this.openmct.overlays.dialog({
|
||||
iconClass: 'alert',
|
||||
message: `This action will remove this tab from the Tabs Layout. Do you want to continue?`,
|
||||
buttons: [
|
||||
{
|
||||
label: 'Ok',
|
||||
emphasis: 'true',
|
||||
callback: () => {
|
||||
this.removeFromComposition(childDomainObject);
|
||||
prompt.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Cancel',
|
||||
callback: () => {
|
||||
prompt.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
removeFromComposition(childDomainObject) {
|
||||
this.composition.remove(childDomainObject);
|
||||
},
|
||||
addItem(domainObject) {
|
||||
let type = this.openmct.types.get(domainObject.type) || unknownObjectType,
|
||||
tabItem = {
|
||||
@@ -133,6 +195,10 @@ export default {
|
||||
this.setCurrentTab = false;
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
this.currentTab = {};
|
||||
this.setCurrentTab = true;
|
||||
},
|
||||
removeItem(identifier) {
|
||||
let pos = this.tabsList.findIndex(tab =>
|
||||
tab.domainObject.identifier.namespace === identifier.namespace && tab.domainObject.identifier.key === identifier.key
|
||||
@@ -144,6 +210,10 @@ export default {
|
||||
if (this.isCurrent(tabToBeRemoved)) {
|
||||
this.showTab(this.tabsList[this.tabsList.length - 1], this.tabsList.length - 1);
|
||||
}
|
||||
|
||||
if (!this.tabsList.length) {
|
||||
this.reset();
|
||||
}
|
||||
},
|
||||
onReorder(reorderPlan) {
|
||||
let oldTabs = this.tabsList.slice();
|
||||
@@ -154,7 +224,7 @@ export default {
|
||||
},
|
||||
onDrop(e) {
|
||||
this.setCurrentTab = true;
|
||||
this.storeCurrentTabIndex(this.tabsList.length);
|
||||
this.storeCurrentTabIndexInURL(this.tabsList.length);
|
||||
},
|
||||
dragstart(e) {
|
||||
if (e.dataTransfer.types.includes('openmct/domain-object-path')) {
|
||||
@@ -177,8 +247,19 @@ export default {
|
||||
updateInternalDomainObject(domainObject) {
|
||||
this.internalDomainObject = domainObject;
|
||||
},
|
||||
storeCurrentTabIndex(index) {
|
||||
persistCurrentTabIndex(index) {
|
||||
this.openmct.objects.mutate(this.internalDomainObject, 'currentTabIndex', index);
|
||||
},
|
||||
storeCurrentTabIndexInURL(index) {
|
||||
let currentTabIndexInURL = getSearchParam(this.searchTabKey);
|
||||
|
||||
if (index !== currentTabIndexInURL) {
|
||||
setSearchParam(this.searchTabKey, index);
|
||||
this.currentTabIndex = index;
|
||||
}
|
||||
},
|
||||
clearCurrentTabIndexFromURL() {
|
||||
deleteSearchParam(this.searchTabKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,20 +42,28 @@ define([
|
||||
let component;
|
||||
|
||||
return {
|
||||
show: function (element) {
|
||||
show: function (element, editMode) {
|
||||
component = new Vue({
|
||||
el: element,
|
||||
components: {
|
||||
TabsComponent: TabsComponent.default
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isEditing: editMode
|
||||
};
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject,
|
||||
composition: openmct.composition.get(domainObject)
|
||||
},
|
||||
template: '<tabs-component></tabs-component>'
|
||||
template: '<tabs-component :isEditing="isEditing"></tabs-component>'
|
||||
});
|
||||
},
|
||||
onEditModeChange(editMode) {
|
||||
component.isEditing = editMode;
|
||||
},
|
||||
destroy: function (element) {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
|
||||
@@ -74,6 +74,10 @@ define([], function () {
|
||||
return this.cellLimitClasses;
|
||||
}
|
||||
|
||||
getContextualDomainObject(openmct, objectKeyString) {
|
||||
return openmct.objects.get(objectKeyString);
|
||||
}
|
||||
|
||||
getContextMenuActions() {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -46,11 +46,23 @@ define(
|
||||
filter = filter.trim().toLowerCase();
|
||||
|
||||
let rowsToFilter = this.getRowsToFilter(columnKey, filter);
|
||||
|
||||
if (filter.length === 0) {
|
||||
delete this.columnFilters[columnKey];
|
||||
} else {
|
||||
this.columnFilters[columnKey] = filter;
|
||||
}
|
||||
|
||||
this.rows = rowsToFilter.filter(this.matchesFilters, this);
|
||||
this.emit('filter');
|
||||
}
|
||||
|
||||
setColumnRegexFilter(columnKey, filter) {
|
||||
filter = filter.trim();
|
||||
|
||||
let rowsToFilter = this.masterCollection.getRows();
|
||||
|
||||
this.columnFilters[columnKey] = new RegExp(filter);
|
||||
this.rows = rowsToFilter.filter(this.matchesFilters, this);
|
||||
this.emit('filter');
|
||||
}
|
||||
@@ -70,6 +82,10 @@ define(
|
||||
* @private
|
||||
*/
|
||||
isSubsetOfCurrentFilter(columnKey, filter) {
|
||||
if (this.columnFilters[columnKey] instanceof RegExp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.columnFilters[columnKey] &&
|
||||
filter.startsWith(this.columnFilters[columnKey]) &&
|
||||
// startsWith check will otherwise fail when filter cleared
|
||||
@@ -96,7 +112,11 @@ define(
|
||||
return false;
|
||||
}
|
||||
|
||||
doesMatchFilters = formattedValue.toLowerCase().indexOf(this.columnFilters[key]) !== -1;
|
||||
if (this.columnFilters[key] instanceof RegExp) {
|
||||
doesMatchFilters = this.columnFilters[key].test(formattedValue);
|
||||
} else {
|
||||
doesMatchFilters = formattedValue.toLowerCase().indexOf(this.columnFilters[key]) !== -1;
|
||||
}
|
||||
});
|
||||
return doesMatchFilters;
|
||||
}
|
||||
|
||||
56
src/plugins/telemetryTable/components/sizing-row.vue
Normal file
56
src/plugins/telemetryTable/components/sizing-row.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<tr class="c-telemetry-table__sizing-tr"><td>SIZING ROW</td></tr>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isEditing: function (isEditing) {
|
||||
if (isEditing) {
|
||||
this.pollForRowHeight();
|
||||
} else {
|
||||
this.clearPoll();
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick().then(() => {
|
||||
this.height = this.$el.offsetHeight;
|
||||
this.$emit('change-height', this.height);
|
||||
});
|
||||
|
||||
if (this.isEditing) {
|
||||
this.pollForRowHeight();
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
this.clearPoll();
|
||||
},
|
||||
methods: {
|
||||
pollForRowHeight() {
|
||||
this.clearPoll();
|
||||
this.pollID = window.setInterval(this.heightPoll, 300);
|
||||
},
|
||||
clearPoll() {
|
||||
if (this.pollID) {
|
||||
window.clearInterval(this.pollID);
|
||||
this.pollID = undefined;
|
||||
}
|
||||
},
|
||||
heightPoll() {
|
||||
let height = this.$el.offsetHeight;
|
||||
|
||||
if (height !== this.height) {
|
||||
this.$emit('change-height', height);
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -171,7 +171,7 @@ export default {
|
||||
showContextMenu: function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.openmct.objects.get(this.row.objectKeyString).then((domainObject) => {
|
||||
this.row.getContextualDomainObject(this.openmct, this.row.objectKeyString).then(domainObject => {
|
||||
let contextualObjectPath = this.objectPath.slice();
|
||||
contextualObjectPath.unshift(domainObject);
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
.c-telemetry-table {
|
||||
// Table that displays telemetry in a scrolling body area
|
||||
|
||||
@include fontAndSize();
|
||||
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
@@ -54,6 +57,16 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__filter {
|
||||
.c-table__search {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.is-in-small-container & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__headers__label {
|
||||
@@ -86,6 +99,10 @@
|
||||
height: 0; // Fixes Chrome 73 overflow bug
|
||||
overflow-x: auto;
|
||||
overflow-y: scroll;
|
||||
|
||||
.is-editing & {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* TABLES */
|
||||
@@ -98,7 +115,7 @@
|
||||
display: flex; // flex-flow defaults to row nowrap (which is what we want) so no need to define
|
||||
align-items: stretch;
|
||||
position: absolute;
|
||||
height: 18px; // Needed when a row has empty values in its cells
|
||||
min-height: 18px; // Needed when a row has empty values in its cells
|
||||
|
||||
&.is-selected {
|
||||
background-color: $colorSelectedBg !important;
|
||||
@@ -136,9 +153,15 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
&__sizing-tr {
|
||||
// A row element used to determine sizing of rows based on font size
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* EDITING */
|
||||
/******************************* SPECIFIC CASE WRAPPERS */
|
||||
.is-editing {
|
||||
.c-telemetry-table__headers__labels {
|
||||
th[draggable],
|
||||
@@ -158,8 +181,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.paused {
|
||||
border: 1px solid #ff9900;
|
||||
.is-paused {
|
||||
.c-table__body-w {
|
||||
border: 1px solid rgba($colorPausedBg, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* LEGACY */
|
||||
|
||||
@@ -20,13 +20,16 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
<template>
|
||||
<div class="c-table-wrapper">
|
||||
<div class="c-table-wrapper"
|
||||
:class="{ 'is-paused': paused }"
|
||||
>
|
||||
<!-- main contolbar start-->
|
||||
<div v-if="!marking.useAlternateControlBar"
|
||||
class="c-table-control-bar c-control-bar"
|
||||
>
|
||||
<button
|
||||
v-if="allowExport"
|
||||
v-show="!markedRows.length"
|
||||
class="c-button icon-download labeled"
|
||||
title="Export this view's data"
|
||||
@click="exportAllDataAsCSV()"
|
||||
@@ -122,10 +125,10 @@
|
||||
<!-- alternate controlbar end -->
|
||||
|
||||
<div
|
||||
class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar"
|
||||
class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar u-style-receiver js-style-receiver"
|
||||
:class="{
|
||||
'loading': loading,
|
||||
'paused' : paused
|
||||
'is-paused' : paused
|
||||
}"
|
||||
>
|
||||
<div :style="{ 'max-width': widthWithScroll, 'min-width': '150px'}">
|
||||
@@ -187,7 +190,17 @@
|
||||
class="c-table__search"
|
||||
@input="filterChanged(key)"
|
||||
@clear="clearFilter(key)"
|
||||
/>
|
||||
>
|
||||
|
||||
<button
|
||||
class="c-search__use-regex"
|
||||
:class="{ 'is-active': enableRegexSearch[key] }"
|
||||
title="Click to enable regex: enter a string with slashes, like this: /regex_exp/"
|
||||
@click="toggleRegex(key)"
|
||||
>
|
||||
/R/
|
||||
</button>
|
||||
</search>
|
||||
</table-column-header>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -231,6 +244,10 @@
|
||||
class="c-telemetry-table__sizing js-telemetry-table__sizing"
|
||||
:style="sizingTableWidth"
|
||||
>
|
||||
<sizing-row
|
||||
:is-editing="isEditing"
|
||||
@change-height="setRowHeight"
|
||||
/>
|
||||
<tr>
|
||||
<template v-for="(title, key) in headers">
|
||||
<th
|
||||
@@ -263,6 +280,7 @@ import TelemetryFilterIndicator from './TelemetryFilterIndicator.vue';
|
||||
import CSVExporter from '../../../exporters/CSVExporter.js';
|
||||
import _ from 'lodash';
|
||||
import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue';
|
||||
import SizingRow from './sizing-row.vue';
|
||||
|
||||
const VISIBLE_ROW_COUNT = 100;
|
||||
const ROW_HEIGHT = 17;
|
||||
@@ -275,7 +293,8 @@ export default {
|
||||
TableColumnHeader,
|
||||
search,
|
||||
TelemetryFilterIndicator,
|
||||
ToggleSwitch
|
||||
ToggleSwitch,
|
||||
SizingRow
|
||||
},
|
||||
inject: ['table', 'openmct', 'objectPath'],
|
||||
props: {
|
||||
@@ -338,7 +357,8 @@ export default {
|
||||
paused: false,
|
||||
markedRows: [],
|
||||
isShowingMarkedRowsOnly: false,
|
||||
hideHeaders: configuration.hideHeaders
|
||||
hideHeaders: configuration.hideHeaders,
|
||||
enableRegexSearch: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -490,7 +510,7 @@ export default {
|
||||
let columnWidths = {},
|
||||
totalWidth = 0,
|
||||
headerKeys = Object.keys(this.headers),
|
||||
sizingTableRow = this.sizingTable.children[0],
|
||||
sizingTableRow = this.sizingTable.children[1],
|
||||
sizingCells = sizingTableRow.children;
|
||||
|
||||
headerKeys.forEach((headerKey, headerIndex, array)=>{
|
||||
@@ -547,6 +567,17 @@ export default {
|
||||
},
|
||||
filterChanged(columnKey) {
|
||||
this.table.filteredRows.setColumnFilter(columnKey, this.filters[columnKey]);
|
||||
|
||||
if (this.enableRegexSearch[columnKey]) {
|
||||
if (this.isCompleteRegex(this.filters[columnKey])) {
|
||||
this.table.filteredRows.setColumnRegexFilter(columnKey, this.filters[columnKey].slice(1,-1));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.table.filteredRows.setColumnFilter(columnKey, this.filters[columnKey]);
|
||||
}
|
||||
|
||||
this.setHeight();
|
||||
},
|
||||
clearFilter(columnKey) {
|
||||
@@ -873,6 +904,23 @@ export default {
|
||||
this.isAutosizeEnabled = true;
|
||||
|
||||
this.$nextTick().then(this.calculateColumnWidths);
|
||||
},
|
||||
setRowHeight(height) {
|
||||
this.rowHeight = height;
|
||||
this.setHeight();
|
||||
this.calculateTableSize();
|
||||
this.clearRowsAndRerender();
|
||||
},
|
||||
toggleRegex(key) {
|
||||
this.$set(this.filters, key, '');
|
||||
if (this.enableRegexSearch[key] === undefined) {
|
||||
this.$set(this.enableRegexSearch, key, true)
|
||||
} else {
|
||||
this.$set(this.enableRegexSearch, key, !this.enableRegexSearch[key]);
|
||||
}
|
||||
},
|
||||
isCompleteRegex(string) {
|
||||
return (string.length > 2 && string[0] === '/' && string[string.length - 1] === '/')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
<ConductorHistory
|
||||
v-if="isFixed"
|
||||
class="c-conductor__history-select"
|
||||
:bounds="openmct.time.bounds()"
|
||||
:bounds="bounds"
|
||||
:time-system="timeSystem"
|
||||
/>
|
||||
</div>
|
||||
@@ -190,6 +190,10 @@ export default {
|
||||
start: offsets && durationFormatter.format(Math.abs(offsets.start)),
|
||||
end: offsets && durationFormatter.format(Math.abs(offsets.end))
|
||||
},
|
||||
bounds: {
|
||||
start: bounds.start,
|
||||
end: bounds.end
|
||||
},
|
||||
formattedBounds: {
|
||||
start: timeFormatter.format(bounds.start),
|
||||
end: timeFormatter.format(bounds.end)
|
||||
@@ -210,7 +214,7 @@ export default {
|
||||
document.addEventListener('keydown', this.handleKeyDown);
|
||||
document.addEventListener('keyup', this.handleKeyUp);
|
||||
this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem())));
|
||||
this.openmct.time.on('bounds', this.setViewFromBounds);
|
||||
this.openmct.time.on('bounds', this.handleNewBounds);
|
||||
this.openmct.time.on('timeSystem', this.setTimeSystem);
|
||||
this.openmct.time.on('clock', this.setViewFromClock);
|
||||
this.openmct.time.on('clockOffsets', this.setViewFromOffsets)
|
||||
@@ -220,6 +224,13 @@ export default {
|
||||
document.removeEventListener('keyup', this.handleKeyUp);
|
||||
},
|
||||
methods: {
|
||||
handleNewBounds(bounds) {
|
||||
this.setBounds(bounds);
|
||||
this.setViewFromBounds(bounds);
|
||||
},
|
||||
setBounds(bounds) {
|
||||
this.bounds = bounds;
|
||||
},
|
||||
handleKeyDown(event) {
|
||||
if (event.key === 'Alt') {
|
||||
this.altPressed = true;
|
||||
@@ -246,10 +257,13 @@ export default {
|
||||
this.formattedBounds.end = this.timeFormatter.format(bounds.end);
|
||||
},
|
||||
endZoom(bounds) {
|
||||
const _bounds = bounds ? bounds : this.openmct.time.bounds();
|
||||
this.isZooming = false;
|
||||
|
||||
this.openmct.time.bounds(_bounds);
|
||||
if (bounds) {
|
||||
this.handleNewBounds(bounds);
|
||||
} else {
|
||||
this.setViewFromBounds(this.bounds);
|
||||
}
|
||||
},
|
||||
setTimeSystem(timeSystem) {
|
||||
this.timeSystem = timeSystem
|
||||
|
||||
@@ -207,7 +207,7 @@ export default {
|
||||
this.$emit('panAxis', panBounds);
|
||||
},
|
||||
endPan() {
|
||||
const panBounds = this.dragStartX && this.dragX && this.dragStartX !== this.dragX
|
||||
const panBounds = this.isChangingViewBounds()
|
||||
? this.getPanBounds()
|
||||
: undefined;
|
||||
this.$emit('endPan', panBounds);
|
||||
@@ -251,16 +251,14 @@ export default {
|
||||
});
|
||||
},
|
||||
endZoom() {
|
||||
const zoomRange = this.dragStartX && this.dragX && this.dragStartX !== this.dragX
|
||||
? this.getZoomRange()
|
||||
: undefined;
|
||||
|
||||
const zoomBounds = zoomRange
|
||||
? {
|
||||
let zoomBounds;
|
||||
if (this.isChangingViewBounds()) {
|
||||
const zoomRange = this.getZoomRange();
|
||||
zoomBounds = {
|
||||
start: this.scaleToBounds(zoomRange.start),
|
||||
end: this.scaleToBounds(zoomRange.end)
|
||||
}
|
||||
: this.openmct.time.bounds();
|
||||
};
|
||||
}
|
||||
|
||||
this.zoomStyle = {};
|
||||
this.$emit('endZoom', zoomBounds);
|
||||
@@ -289,6 +287,9 @@ export default {
|
||||
const offset = valueDelta / this.width * timeDelta;
|
||||
return bounds.start + offset;
|
||||
},
|
||||
isChangingViewBounds() {
|
||||
return this.dragStartX && this.dragX && this.dragStartX !== this.dragX;
|
||||
},
|
||||
resize() {
|
||||
if (this.$refs.axisHolder.clientWidth !== this.width) {
|
||||
this.setAxisDimensions();
|
||||
|
||||
@@ -84,7 +84,12 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
history: {}, // contains arrays of timespans {start, end}, array key is time system key
|
||||
/**
|
||||
* previous bounds entries available for easy re-use
|
||||
* @history array of timespans
|
||||
* @timespans {start, end} number representing timestamp
|
||||
*/
|
||||
history: this.getHistoryFromLocalStorage(),
|
||||
presets: []
|
||||
}
|
||||
},
|
||||
@@ -111,22 +116,20 @@ export default {
|
||||
this.addTimespan();
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
history: {
|
||||
handler() {
|
||||
this.persistHistoryToLocalStorage();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getHistoryFromLocalStorage();
|
||||
this.initializeHistoryIfNoHistory();
|
||||
},
|
||||
methods: {
|
||||
getHistoryFromLocalStorage() {
|
||||
if (localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY)) {
|
||||
this.history = JSON.parse(localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY))
|
||||
} else {
|
||||
const localStorageHistory = localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY);
|
||||
const history = localStorageHistory ? JSON.parse(localStorageHistory) : undefined;
|
||||
|
||||
return history;
|
||||
},
|
||||
initializeHistoryIfNoHistory() {
|
||||
if (!this.history) {
|
||||
this.history = {};
|
||||
this.persistHistoryToLocalStorage();
|
||||
}
|
||||
@@ -156,6 +159,8 @@ export default {
|
||||
|
||||
currentHistory.unshift(timespan);
|
||||
this.history[key] = currentHistory;
|
||||
|
||||
this.persistHistoryToLocalStorage();
|
||||
},
|
||||
selectTimespan(timespan) {
|
||||
this.openmct.time.bounds(timespan);
|
||||
|
||||
@@ -84,6 +84,10 @@ $filterHov: brightness(1.3); // Tree, location items
|
||||
$colorSelectedBg: pushBack($colorKey, 10%);
|
||||
$colorSelectedFg: pullForward($colorBodyFg, 20%);
|
||||
|
||||
// Object labels
|
||||
$objectLabelTypeIconOpacity: 0.7;
|
||||
$objectLabelNameFilter: brightness(1.3);
|
||||
|
||||
// Layout
|
||||
$shellMainPad: 4px 0;
|
||||
$shellPanePad: $interiorMargin, 7px;
|
||||
@@ -94,7 +98,7 @@ $sideBarHeaderBg: rgba($colorBodyFg, 0.2);
|
||||
$sideBarHeaderFg: rgba($colorBodyFg, 0.7);
|
||||
|
||||
// Status colors, mainly used for messaging and item ancillary symbols
|
||||
$colorStatusFg: #999;
|
||||
$colorStatusFg: #888;
|
||||
$colorStatusDefault: #ccc;
|
||||
$colorStatusInfo: #60ba7b;
|
||||
$colorStatusInfoFilter: invert(58%) sepia(44%) saturate(405%) hue-rotate(85deg) brightness(102%) contrast(92%);
|
||||
@@ -151,6 +155,10 @@ $browseFrameColor: pullForward($colorBodyBg, 10%);
|
||||
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
|
||||
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
|
||||
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
|
||||
$filterItemHoverFg: brightness(1.2) contrast(1.1);
|
||||
$filterItemMissing: brightness(0.6) grayscale(1);
|
||||
$opacityMissing: 0.5;
|
||||
$borderMissing: 1px dashed $colorAlert !important;
|
||||
|
||||
/************************************************** EDITING */
|
||||
$editUIColor: $uiColor; // Base color
|
||||
@@ -201,9 +209,9 @@ $colorBtnMajorBg: $colorKey;
|
||||
$colorBtnMajorBgHov: $colorKeyHov;
|
||||
$colorBtnMajorFg: $colorKeyFg;
|
||||
$colorBtnMajorFgHov: pushBack($colorBtnMajorFg, 10%);
|
||||
$colorBtnCautionBg: #f16f6f;
|
||||
$colorBtnCautionBg: $colorStatusAlert;
|
||||
$colorBtnCautionBgHov: #f1504e;
|
||||
$colorBtnCautionFg: $colorBtnFg;
|
||||
$colorBtnCautionFg: $colorBtnBg;
|
||||
$colorBtnActiveBg: $colorOk;
|
||||
$colorBtnActiveFg: $colorOkFg;
|
||||
$colorBtnSelectedBg: $colorSelectedBg;
|
||||
@@ -331,7 +339,7 @@ $shdwItemText: none;
|
||||
$colorTabBorder: pullForward($colorBodyBg, 10%);
|
||||
$colorTabBodyBg: $colorBodyBg;
|
||||
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
|
||||
$colorTabHeaderBg: rgba($colorBodyFg, 0.2);
|
||||
$colorTabHeaderBg: rgba($colorBodyFg, 0.15);
|
||||
$colorTabHeaderFg: $colorBodyFg;
|
||||
$colorTabHeaderBorder: $colorBodyBg;
|
||||
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);
|
||||
@@ -349,7 +357,7 @@ $stylePlotHash: dashed;
|
||||
$colorPlotAreaBorder: $colorInteriorBorder;
|
||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
|
||||
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
|
||||
$legendTableHeadBg: rgba($colorBodyFg, 0.15);
|
||||
$legendTableHeadBg: $colorTabHeaderBg;
|
||||
|
||||
// Tree
|
||||
$colorTreeBg: transparent;
|
||||
|
||||
@@ -88,6 +88,10 @@ $filterHov: brightness(1.3); // Tree, location items
|
||||
$colorSelectedBg: pushBack($colorKey, 10%);
|
||||
$colorSelectedFg: pullForward($colorBodyFg, 20%);
|
||||
|
||||
// Object labels
|
||||
$objectLabelTypeIconOpacity: 0.7;
|
||||
$objectLabelNameFilter: brightness(1.3);
|
||||
|
||||
// Layout
|
||||
$shellMainPad: 4px 0;
|
||||
$shellPanePad: $interiorMargin, 7px;
|
||||
@@ -155,6 +159,10 @@ $browseFrameColor: pullForward($colorBodyBg, 10%);
|
||||
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
|
||||
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
|
||||
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
|
||||
$filterItemHoverFg: brightness(1.2) contrast(1.1);
|
||||
$filterItemMissing: contrast(0.2);
|
||||
$opacityMissing: 0.5;
|
||||
$borderMissing: 1px dashed $colorAlert !important;
|
||||
|
||||
/************************************************** EDITING */
|
||||
$editUIColor: $uiColor; // Base color
|
||||
@@ -205,9 +213,9 @@ $colorBtnMajorBg: $colorKey;
|
||||
$colorBtnMajorBgHov: $colorKeyHov;
|
||||
$colorBtnMajorFg: $colorKeyFg;
|
||||
$colorBtnMajorFgHov: pushBack($colorBtnMajorFg, 10%);
|
||||
$colorBtnCautionBg: #f16f6f;
|
||||
$colorBtnCautionBg: $colorStatusAlert;
|
||||
$colorBtnCautionBgHov: #f1504e;
|
||||
$colorBtnCautionFg: $colorBtnFg;
|
||||
$colorBtnCautionFg: $colorBtnBg;
|
||||
$colorBtnActiveBg: $colorOk;
|
||||
$colorBtnActiveFg: $colorOkFg;
|
||||
$colorBtnSelectedBg: $colorSelectedBg;
|
||||
@@ -335,7 +343,7 @@ $shdwItemText: none;
|
||||
$colorTabBorder: pullForward($colorBodyBg, 10%);
|
||||
$colorTabBodyBg: $colorBodyBg;
|
||||
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
|
||||
$colorTabHeaderBg: rgba($colorBodyFg, 0.2);
|
||||
$colorTabHeaderBg: rgba($colorBodyFg, 0.15);
|
||||
$colorTabHeaderFg: $colorBodyFg;
|
||||
$colorTabHeaderBorder: $colorBodyBg;
|
||||
$colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%);
|
||||
|
||||
@@ -80,10 +80,14 @@ $uiColor: #289fec; // Resize bars, splitter bars, etc.
|
||||
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
|
||||
$colorA: #999;
|
||||
$colorAHov: $colorKey;
|
||||
$filterHov: brightness(1.3); // Tree, location items
|
||||
$filterHov: brightness(0.8) contrast(2); // Tree, location items
|
||||
$colorSelectedBg: pushBack($colorKey, 40%);
|
||||
$colorSelectedFg: pullForward($colorBodyFg, 10%);
|
||||
|
||||
// Object labels
|
||||
$objectLabelTypeIconOpacity: 0.5;
|
||||
$objectLabelNameFilter: brightness(0.5);
|
||||
|
||||
// Layout
|
||||
$shellMainPad: 4px 0;
|
||||
$shellPanePad: $interiorMargin, 7px;
|
||||
@@ -151,6 +155,10 @@ $browseFrameColor: pullForward($colorBodyBg, 10%);
|
||||
$browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing
|
||||
$browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px;
|
||||
$browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4);
|
||||
$filterItemHoverFg: brightness(0.9);
|
||||
$filterItemMissing: contrast(0.2);
|
||||
$opacityMissing: 0.4;
|
||||
$borderMissing: 1px dashed $colorAlert !important;
|
||||
|
||||
/************************************************** EDITING */
|
||||
$editUIColor: $uiColor; // Base color
|
||||
@@ -220,7 +228,7 @@ $colorDisclosureCtrlHov: rgba($colorBodyFg, 0.7);
|
||||
$btnStdH: 24px;
|
||||
$colorCursorGuide: rgba(black, 0.6);
|
||||
$shdwCursorGuide: rgba(white, 0.4) 0 0 2px;
|
||||
$colorLocalControlOvrBg: rgba($colorBodyFg, 0.8);
|
||||
$colorLocalControlOvrBg: rgba($colorBodyBg, 0.8);
|
||||
$colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due to usage of SVG bg in selects
|
||||
$colorSelectFg: $colorBtnFg;
|
||||
$colorSelectArw: lighten($colorBtnBg, 20%);
|
||||
|
||||
@@ -40,11 +40,10 @@ $inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
|
||||
$menuLineH: 1.5rem;
|
||||
$treeItemIndent: 16px;
|
||||
$treeTypeIconW: 18px;
|
||||
$overlayOuterMarginLg: 5%;
|
||||
$overlayOuterMarginFullscreen: 0%;
|
||||
$overlayOuterMarginDialog: 20%;
|
||||
$overlayInnerMargin: 25px;
|
||||
$mainViewPad: 2px;
|
||||
$mainViewPad: 0px;
|
||||
/*************** Items */
|
||||
$itemPadLR: 5px;
|
||||
$gridItemDesk: 175px;
|
||||
@@ -57,11 +56,11 @@ $tabularTdPadTB: 2px;
|
||||
$plotYBarW: 60px;
|
||||
$plotYLabelMinH: 20px;
|
||||
$plotYLabelW: 10px;
|
||||
$plotXBarH: 35px;
|
||||
$plotXBarH: 32px;
|
||||
$plotLegendH: 20px;
|
||||
$plotLegendWidthCollapsed: 20%;
|
||||
$plotLegendWidthExpanded: 50%;
|
||||
$plotSwatchD: 10px;
|
||||
$plotSwatchD: 12px;
|
||||
$plotDisplayArea: (0, 0, $plotXBarH, $plotYBarW); // 1: Top, 2: right, 3: bottom, 4: left
|
||||
$plotMinH: 95px;
|
||||
$controlBarH: 25px;
|
||||
@@ -90,6 +89,8 @@ $messageIconD: 80px;
|
||||
$messageListIconD: 32px;
|
||||
/*************** Tables */
|
||||
$tableResizeColHitareaD: 6px;
|
||||
/*************** Misc */
|
||||
$drawingObjBorderW: 3px;
|
||||
|
||||
/************************** MOBILE */
|
||||
$mobileMenuIconD: 24px; // Used
|
||||
@@ -101,6 +102,8 @@ $colorProgressBarHolder: rgba(black, 0.1);
|
||||
$colorProgressBar: #0085ad;
|
||||
$progressAnimW: 500px;
|
||||
$progressBarMinH: 6px;
|
||||
/************************** FONT STYLING */
|
||||
$listFontSizes: 8,9,10,11,12,13,14,16,18,20,24,28,32,36,42,48,72,96,128;
|
||||
|
||||
/************************** GLYPH CHAR UNICODES */
|
||||
$glyph-icon-alert-rect: '\e900';
|
||||
|
||||
@@ -57,11 +57,6 @@ button {
|
||||
line-height: 90%;
|
||||
padding: 3px 10px;
|
||||
|
||||
@include hover() {
|
||||
background: $colorBtnBgHov;
|
||||
color: $colorBtnFgHov;
|
||||
}
|
||||
|
||||
@include desktop() {
|
||||
font-size: 6px;
|
||||
}
|
||||
@@ -411,7 +406,17 @@ select {
|
||||
|
||||
.c-tab {
|
||||
// Used in Tab View, generic tabs
|
||||
background: $colorBtnBg;
|
||||
$notchSize: 7px;
|
||||
$clipPath:
|
||||
polygon(
|
||||
0% 0%,
|
||||
calc(100% - #{$notchSize}) 0%,
|
||||
100% #{$notchSize},
|
||||
100% calc(100% - #{$notchSize}),
|
||||
100% 100%,
|
||||
0% 100%
|
||||
);
|
||||
background: rgba($colorBtnBg, 0.7);
|
||||
color: $colorBtnFg;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
@@ -420,21 +425,15 @@ select {
|
||||
margin: 1px 1px 0 0;
|
||||
padding: $interiorMargin $interiorMarginLg;
|
||||
white-space: nowrap;
|
||||
clip-path: $clipPath;
|
||||
-webkit-clip-path: $clipPath; // Safari
|
||||
|
||||
--notchSize: 7px;
|
||||
|
||||
clip-path:
|
||||
polygon(
|
||||
0% 0%,
|
||||
calc(100% - var(--notchSize)) 0%,
|
||||
100% var(--notchSize),
|
||||
100% calc(100% - var(--notchSize)),
|
||||
100% 100%,
|
||||
0% 100%
|
||||
);
|
||||
> * + * {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
|
||||
@include hover() {
|
||||
background: $colorBtnBgHov;
|
||||
filter: $filterHov;
|
||||
}
|
||||
|
||||
&.is-current {
|
||||
|
||||
@@ -96,6 +96,37 @@ body.desktop {
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** FONTS */
|
||||
@mixin fontAndSize() {
|
||||
@each $size in $listFontSizes {
|
||||
&[data-font-size="#{$size}"] {
|
||||
font-size: #{$size}px;
|
||||
|
||||
// Set row heights in telemetry tables
|
||||
tr {
|
||||
min-height: #{$size + ($tabularTdPadTB * 2)};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
&[data-font*="bold"] {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&[data-font*="narrow"] {
|
||||
font-family: 'Arial Narrow', sans-serif;
|
||||
}
|
||||
|
||||
&[data-font*="monospace"] {
|
||||
font-family: 'Andale Mono', sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
.u-style-receiver {
|
||||
@include fontAndSize();
|
||||
}
|
||||
|
||||
/******************************************************** HTML ENTITIES */
|
||||
a {
|
||||
color: $colorA;
|
||||
@@ -206,10 +237,6 @@ body.desktop .has-local-controls {
|
||||
&:hover {
|
||||
box-shadow: $browseSelectableShdwHov;
|
||||
}
|
||||
|
||||
&[s-selected] {
|
||||
border: $browseSelectedBorder;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************** EDITING */
|
||||
@@ -230,7 +257,7 @@ body.desktop .has-local-controls {
|
||||
}
|
||||
|
||||
/******************************************************** STATES */
|
||||
@mixin spinner($b: 5px, $c: $colorKey) {
|
||||
@mixin spinner($b: 5, $c: $colorKey) {
|
||||
animation-name: rotation-centered;
|
||||
animation-duration: 0.5s;
|
||||
animation-iteration-count: infinite;
|
||||
@@ -280,13 +307,13 @@ body.desktop .has-local-controls {
|
||||
}
|
||||
&.c-tree__item {
|
||||
$d: $waitSpinnerTreeD;
|
||||
$spinnerL: 19px + $d/2;
|
||||
$spinnerL: 19 + $d/2;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: $spinnerL + $d/2 + $interiorMargin;
|
||||
background: $colorLoadingBg;
|
||||
min-height: 5px + $d;
|
||||
min-height: 5 + $d;
|
||||
|
||||
.c-tree__item__label {
|
||||
font-style: italic;
|
||||
@@ -295,7 +322,7 @@ body.desktop .has-local-controls {
|
||||
&:before {
|
||||
height: $d;
|
||||
width: $d;
|
||||
border-width: 4px;
|
||||
border-width: 4;
|
||||
left: $spinnerL;
|
||||
}
|
||||
&:after {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
@@ -27,53 +27,65 @@ mct-plot {
|
||||
/*********************** STACKED PLOT LAYOUT */
|
||||
.is-editing {
|
||||
.gl-plot.child-frame {
|
||||
&:hover {
|
||||
@include hover {
|
||||
background: rgba($editUIColorBg, 0.1);
|
||||
box-shadow: inset rgba($editUIColorBg, 0.8) 0 0 0 1px;
|
||||
box-shadow: inset rgba($editUIColorBg, 0.3) 0 0 0 1px;
|
||||
}
|
||||
|
||||
&[s-selected] {
|
||||
border: 1px solid $editUIColorFg !important;
|
||||
color: $editUIColorFg !important;
|
||||
box-shadow: $editFrameSelectedShdw;
|
||||
background: rgba($editUIColorBg, 0.2);
|
||||
box-shadow: inset rgba($editUIColorBg, 0.8) 0 0 0 1px;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.plot-wrapper-axis-and-display-area {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.c-plot,
|
||||
.gl-plot {
|
||||
.s-status-taking-snapshot & {
|
||||
overflow: hidden;
|
||||
|
||||
.s-status-taking-snapshot & {
|
||||
.c-control-bar {
|
||||
display: none;
|
||||
}
|
||||
.gl-plot-x-label__select,
|
||||
.gl-plot-y-label__select {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************** MISSING ITEM INDICATORS */
|
||||
.is-missing__indicator {
|
||||
display: none;
|
||||
}
|
||||
.is-missing {
|
||||
@include isMissing();
|
||||
.is-missing__indicator {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-plot {
|
||||
//$p: $mainViewPad;
|
||||
@include abs($mainViewPad);
|
||||
//position: absolute;
|
||||
//top: $p; right: $p; bottom: $p; left: $p;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
|
||||
.l-control-bar {
|
||||
.c-control-bar {
|
||||
flex: 0 0 auto;
|
||||
margin-bottom: $interiorMargin;
|
||||
}
|
||||
|
||||
.l-view-section {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&--stacked {
|
||||
@@ -100,20 +112,23 @@ mct-plot {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.is-in-small-container & {
|
||||
.c-control-bar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gl-plot {
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: $plotMinH;
|
||||
flex: 1 1 auto;
|
||||
|
||||
/*********************** AXIS AND DISPLAY AREA */
|
||||
.plot-wrapper-axis-and-display-area {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
min-height: $plotMinH;
|
||||
}
|
||||
|
||||
.gl-plot-wrapper-display-area-and-x-axis {
|
||||
@@ -158,6 +173,14 @@ mct-plot {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.gl-plot-x {
|
||||
@include hover {
|
||||
.gl-plot-x-label__select {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gl-plot-coords {
|
||||
@@ -194,9 +217,7 @@ mct-plot {
|
||||
&.gl-plot-y-label {
|
||||
display: block;
|
||||
left: 0; top: 0; right: auto; bottom: 0;
|
||||
padding-left: 5px;
|
||||
text-orientation: mixed;
|
||||
//overflow: hidden;
|
||||
writing-mode: vertical-lr;
|
||||
&:before {
|
||||
// Icon denoting configurability
|
||||
@@ -205,11 +226,19 @@ mct-plot {
|
||||
}
|
||||
}
|
||||
|
||||
.gl-plot-x-label__select {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
transform: translateX(-50%);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.gl-plot-y-label__select {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 20px;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
@@ -261,7 +290,7 @@ mct-plot {
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: $m;
|
||||
right: $m;
|
||||
left: $m;
|
||||
z-index: 9;
|
||||
|
||||
&__reset {
|
||||
@@ -274,15 +303,18 @@ mct-plot {
|
||||
top: $m;
|
||||
right: $m;
|
||||
}
|
||||
|
||||
.c-button {
|
||||
box-shadow: $colorLocalControlOvrBg 0 0 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.l-state-indicators {
|
||||
color: $colorPausedBg;
|
||||
position: absolute;
|
||||
display: block;
|
||||
font-size: 1.5em;
|
||||
pointer-events: none;
|
||||
top: $interiorMarginSm;
|
||||
cursor: help;
|
||||
font-size: 1.2em;
|
||||
bottom: $interiorMarginSm;
|
||||
left: $interiorMarginSm;
|
||||
z-index: 2;
|
||||
|
||||
@@ -341,11 +373,11 @@ mct-plot {
|
||||
|
||||
.gl-plot-tick {
|
||||
&.gl-plot-x-tick-label {
|
||||
top: $interiorMargin;
|
||||
top: $interiorMarginSm;
|
||||
}
|
||||
&.gl-plot-y-tick-label {
|
||||
right: $interiorMargin;
|
||||
left: $interiorMargin;
|
||||
right: $interiorMarginSm;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,12 +400,6 @@ mct-plot {
|
||||
z-index: -10;
|
||||
|
||||
.l-view-section {
|
||||
//$m: $interiorMargin;
|
||||
//top: $m !important;
|
||||
//right: $m;
|
||||
//bottom: $m;
|
||||
//left: $m;
|
||||
|
||||
.s-status-timeconductor-unsynced .holder-plot {
|
||||
.t-object-alert.t-alert-unsynced {
|
||||
display: none;
|
||||
@@ -429,14 +455,18 @@ mct-plot {
|
||||
/****************** _LEGEND.SCSS */
|
||||
.gl-plot-legend,
|
||||
.c-plot-legend {
|
||||
overflow: hidden;
|
||||
|
||||
&__wrapper {
|
||||
// Holds view-control and both collapsed and expanded legends
|
||||
flex: 1 1 auto;
|
||||
overflow: auto; // Prevents collapsed legend from forcing scrollbars on higher parent containers
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
&__view-control {
|
||||
padding-top: 2px;
|
||||
padding-top: 4px;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
@@ -444,8 +474,22 @@ mct-plot {
|
||||
@include propertiesHeader();
|
||||
margin-bottom: $interiorMarginSm;
|
||||
}
|
||||
|
||||
.is-in-small-container & {
|
||||
&.is-legend-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-plot--stacked {
|
||||
.is-legend-hidden {
|
||||
// Always show the legend in a stacked plot
|
||||
display: flex !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.gl-plot-legend {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@@ -481,15 +525,21 @@ mct-plot {
|
||||
/***************** GENERAL STYLES, ALL STATES */
|
||||
.plot-legend-item {
|
||||
// General styles for legend items, both expanded and collapsed legend states
|
||||
> * + * {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
|
||||
.plot-series-color-swatch {
|
||||
border-radius: $smallCr;
|
||||
border-radius: 30%; //$smallCr;
|
||||
border: 1px solid $colorBodyBg;
|
||||
display: inline-block;
|
||||
flex: 0 0 auto;
|
||||
height: $plotSwatchD;
|
||||
width: $plotSwatchD;
|
||||
}
|
||||
.plot-series-name {
|
||||
display: inline;
|
||||
@include ellipsize();
|
||||
}
|
||||
|
||||
.plot-series-value {
|
||||
@@ -497,11 +547,27 @@ mct-plot {
|
||||
}
|
||||
}
|
||||
|
||||
.plot-series-swatch-and-name {
|
||||
display: flex;
|
||||
flex: 0 1 auto;
|
||||
align-items: center;
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.plot-wrapper-expanded-legend {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.gl-plot {
|
||||
.plot-legend-top .gl-plot-legend { margin-bottom: $interiorMargin; }
|
||||
.plot-legend-bottom .gl-plot-legend { margin-top: $interiorMargin; }
|
||||
.plot-legend-left .gl-plot-legend { margin-right: $interiorMargin; }
|
||||
.plot-legend-right .gl-plot-legend { margin-left: $interiorMargin; }
|
||||
|
||||
.gl-plot,
|
||||
.c-plot {
|
||||
&.plot-legend-collapsed .plot-wrapper-expanded-legend { display: none; }
|
||||
&.plot-legend-expanded .plot-wrapper-collapsed-legend { display: none; }
|
||||
|
||||
@@ -519,21 +585,14 @@ mct-plot {
|
||||
|
||||
.plot-legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: stretch;
|
||||
&:not(:first-child) {
|
||||
margin-left: $interiorMarginLg;
|
||||
}
|
||||
|
||||
.plot-series-swatch-and-name,
|
||||
.plot-series-value {
|
||||
@include ellipsize();
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.plot-series-swatch-and-name {
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
|
||||
.plot-series-value {
|
||||
text-align: left;
|
||||
}
|
||||
@@ -543,7 +602,7 @@ mct-plot {
|
||||
/***************** GENERAL STYLES, EXPANDED */
|
||||
&.plot-legend-expanded {
|
||||
.gl-plot-legend {
|
||||
// max-height: 70%;
|
||||
max-height: 70%;
|
||||
}
|
||||
|
||||
.plot-wrapper-expanded-legend {
|
||||
@@ -554,8 +613,10 @@ mct-plot {
|
||||
|
||||
/***************** TOP OR BOTTOM */
|
||||
&.plot-legend-top,
|
||||
&.plot-legend-bottom {
|
||||
&.plot-legend-bottom,
|
||||
&.plot-legend-hidden {
|
||||
// General styles when legend is on the top or bottom
|
||||
// -hidden included for legacy plots
|
||||
flex-direction: column;
|
||||
|
||||
&.plot-legend-collapsed {
|
||||
@@ -564,6 +625,11 @@ mct-plot {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
|
||||
> .plot-legend-item + .plot-legend-item {
|
||||
// Space between plot items
|
||||
margin-left: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -572,6 +638,7 @@ mct-plot {
|
||||
&.plot-legend-left,
|
||||
&.plot-legend-right {
|
||||
// General styles when legend is on left or right
|
||||
|
||||
.gl-plot-legend {
|
||||
max-height: inherit;
|
||||
}
|
||||
@@ -595,12 +662,18 @@ mct-plot {
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
|
||||
> * + * {
|
||||
// Space between plot items
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
.plot-legend-item {
|
||||
margin-bottom: 1px;
|
||||
margin-bottom: $interiorMarginSm;
|
||||
margin-left: 0;
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: nowrap;
|
||||
.plot-series-swatch-and-name {
|
||||
@include ellipsize();
|
||||
flex: 0 1 auto;
|
||||
min-width: 20%;
|
||||
}
|
||||
@@ -624,6 +697,31 @@ mct-plot {
|
||||
}
|
||||
}
|
||||
|
||||
/***************** STACKED PLOT LEGEND OVERRIDES */
|
||||
.c-plot--stacked {
|
||||
// Always show the legend on top, ignore any position setting
|
||||
.c-plot,
|
||||
.gl-plot {
|
||||
flex-direction: column !important;
|
||||
|
||||
.c-plot-legend,
|
||||
.gl-plot-legend {
|
||||
margin: 0;
|
||||
margin-bottom: $interiorMargin;
|
||||
order: 1 !important;
|
||||
width: 100% !important;
|
||||
|
||||
.plot-wrapper-collapsed-legend {
|
||||
flex-direction: row !important;
|
||||
}
|
||||
}
|
||||
.plot-wrapper-axis-and-display-area {
|
||||
order: 2 !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***************** CURSOR GUIDES */
|
||||
[class*='c-cursor-guide'] {
|
||||
box-shadow: $shdwCursorGuide;
|
||||
@@ -654,3 +752,24 @@ mct-plot {
|
||||
display: inline-block !important;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************** CURSOR LOCK INDICATOR */
|
||||
[class*='c-state-indicator__alert-cursor-lock'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[class*='is-cursor-locked'] {
|
||||
background: rgba($colorInfo, 0.1);
|
||||
|
||||
[class*='c-state-indicator__alert-cursor-lock'] {
|
||||
@include userSelectNone();
|
||||
color: $colorInfo;
|
||||
display: block;
|
||||
margin-right: $interiorMarginSm;
|
||||
|
||||
&[class*='--verbose'] {
|
||||
padding: $interiorMarginSm;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
$ctrlW: 22px;
|
||||
|
||||
&__controls {
|
||||
font-size: 1rem !important;
|
||||
margin-right: 0;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
@@ -62,7 +63,7 @@
|
||||
}
|
||||
|
||||
&__direction {
|
||||
font-size: 0.9em;
|
||||
font-size: 0.9rem !important;
|
||||
margin-right: $interiorMargin;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
@mixin isMissing($absPos: false) {
|
||||
// Common styles to be applied to tree items, object labels, grid and list item views
|
||||
//opacity: 0.7;
|
||||
//pointer-events: none; // Don't think we can do this, as disables title hover on icon element
|
||||
|
||||
.is-missing__indicator {
|
||||
display: none ;
|
||||
text-shadow: $colorBodyBg 0 0 2px;
|
||||
color: $colorAlert;
|
||||
font-family: symbolsfont;
|
||||
|
||||
&:before {
|
||||
content: $glyph-icon-alert-triangle;
|
||||
}
|
||||
}
|
||||
|
||||
@if $absPos {
|
||||
.is-missing__indicator {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-missing .is-missing__indicator,
|
||||
.is-missing .is-missing__indicator { display: block !important; }
|
||||
}
|
||||
|
||||
@mixin bgDiagonalStripes($c: yellow, $a: 0.1, $d: 40px) {
|
||||
background-image: linear-gradient(-45deg,
|
||||
rgba($c, $a) 25%, transparent 25%,
|
||||
@@ -416,28 +443,18 @@
|
||||
}
|
||||
|
||||
@include hover() {
|
||||
background: $colorBtnBgHov;
|
||||
color: $colorBtnFgHov;
|
||||
filter: $filterHov;
|
||||
}
|
||||
|
||||
&[class*="--major"],
|
||||
&[class*='is-active']{
|
||||
background: $colorBtnMajorBg;
|
||||
color: $colorBtnMajorFg;
|
||||
|
||||
@include hover() {
|
||||
background: $colorBtnMajorBgHov;
|
||||
color: $colorBtnMajorFgHov;
|
||||
}
|
||||
}
|
||||
|
||||
&[class*='--caution'] {
|
||||
background: $colorBtnCautionBg;
|
||||
color: $colorBtnCautionFg;
|
||||
|
||||
&:hover {
|
||||
background: $colorBtnCautionBgHov;
|
||||
}
|
||||
background: $colorBtnCautionBg !important;
|
||||
color: $colorBtnCautionFg !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,6 @@ table {
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
a { color: $colorBtnMajorBg; }
|
||||
}
|
||||
|
||||
.is-editing {
|
||||
@@ -92,14 +90,28 @@ div.c-table {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
.is-in-small-container & {
|
||||
&:not(.is-paused) {
|
||||
.c-table-control-bar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.c-table-control-bar {
|
||||
.c-click-icon,
|
||||
.c-button {
|
||||
&__label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-table-control-bar {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
//margin-bottom: $interiorMarginSm; // This approach to allow margin to go away when control bar is hidden
|
||||
padding: $interiorMarginSm 0;
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMarginSm;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"metadata": {
|
||||
"name": "Open MCT Symbols 16px",
|
||||
"lastOpened": 0,
|
||||
"created": 1593102875898
|
||||
"created": 1596146160781
|
||||
},
|
||||
"iconSets": [
|
||||
{
|
||||
@@ -752,7 +752,7 @@
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 114,
|
||||
"order": 189,
|
||||
"id": 4,
|
||||
"name": "icon-font-size",
|
||||
"prevSize": 24,
|
||||
@@ -2686,17 +2686,26 @@
|
||||
{
|
||||
"id": 4,
|
||||
"paths": [
|
||||
"M842.841 380.048h-120.956l-52.382 139.676 52.918 141.12 59.942-159.84 62.361 166.314h-119.884l34.019 90.717h119.884l39.695 105.836h105.836l-181.434-483.823z",
|
||||
"M263.903 160.129l-263.903 703.742h153.944l57.729-153.944h280.397l57.729 153.944h153.944l-263.903-703.742zM261.154 577.976l90.717-241.911 90.717 241.911z"
|
||||
"M1148 416h-152l-65.82 175.54 66.5 177.32 75.32-200.86 78.38 209h-150.66l42.76 114h150.64l49.88 133h133l-228-608z",
|
||||
"M384 0l-384 1024h224l84-224h408l84 224h224l-384-1024zM380 608l132-352 132 352z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"attrs": [],
|
||||
"grid": 16,
|
||||
"tags": [
|
||||
"icon-font-size-alt1"
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"colorPermutations": {
|
||||
"12552552551": []
|
||||
}
|
||||
"12552552551": [
|
||||
{},
|
||||
{}
|
||||
]
|
||||
},
|
||||
"width": 1376
|
||||
},
|
||||
{
|
||||
"id": 141,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user