mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 18:50:11 +00:00
Compare commits
2 Commits
couchdb-pe
...
angular-up
Author | SHA1 | Date | |
---|---|---|---|
5f0096ba16 | |||
b4e6893627 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -37,7 +37,4 @@ protractor/logs
|
||||
# npm-debug log
|
||||
npm-debug.log
|
||||
|
||||
# karma reports
|
||||
report.*.json
|
||||
|
||||
package-lock.json
|
||||
|
@ -226,9 +226,9 @@ typically from the author of the change and its reviewer.
|
||||
Automated testing shall occur whenever changes are merged into the main
|
||||
development branch and must be confirmed alongside any pull request.
|
||||
|
||||
Automated tests are tests which exercise plugins, API, and utility classes.
|
||||
Tests are subject to code review along with the actual implementation, to
|
||||
ensure that tests are applicable and useful.
|
||||
Automated tests are typically unit tests which exercise individual software
|
||||
components. Tests are subject to code review along with the actual
|
||||
implementation, to ensure that tests are applicable and useful.
|
||||
|
||||
Examples of useful tests:
|
||||
* Tests which replicate bugs (or their root causes) to verify their
|
||||
@ -238,26 +238,8 @@ Examples of useful tests:
|
||||
* Tests which verify expected interactions with other components in the
|
||||
system.
|
||||
|
||||
#### Guidelines
|
||||
* 100% statement coverage is achievable and desirable.
|
||||
* Do blackbox testing. Test external behaviors, not internal details. Write tests that describe what your plugin is supposed to do. How it does this doesn't matter, so don't test it.
|
||||
* Unit test specs for plugins should be defined at the plugin level. Start with one test spec per plugin named pluginSpec.js, and as this test spec grows too big, break it up into multiple test specs that logically group related tests.
|
||||
* Unit tests for API or for utility functions and classes may be defined at a per-source file level.
|
||||
* Wherever possible only use and mock public API, builtin functions, and UI in your test specs. Do not directly invoke any private functions. ie. only call or mock functions and objects exposed by openmct.* (eg. openmct.telemetry, openmct.objectView, etc.), and builtin browser functions (fetch, requestAnimationFrame, setTimeout, etc.).
|
||||
* Where builtin functions have been mocked, be sure to clear them between tests.
|
||||
* Test at an appropriate level of isolation. Eg.
|
||||
* If you’re testing a view, you do not need to test the whole application UI, you can just fetch the view provider using the public API and render the view into an element that you have created.
|
||||
* You do not need to test that the view switcher works, there should be separate tests for that.
|
||||
* You do not need to test that telemetry providers work, you can mock openmct.telemetry.request() to feed test data to the view.
|
||||
* Use your best judgement when deciding on appropriate scope.
|
||||
* Automated tests for plugins should start by actually installing the plugin being tested, and then test that installing the plugin adds the desired features and behavior to Open MCT, observing the above rules.
|
||||
* All variables used in a test spec, including any instances of the Open MCT API should be declared inside of an appropriate block scope (not at the root level of the source file), and should be initialized in the relevant beforeEach block. `beforeEach` is preferable to `beforeAll` to avoid leaking of state between tests.
|
||||
* A `afterEach` or `afterAll` should be used to do any clean up necessary to prevent leakage of state between test specs. This can happen when functions on `window` are wrapped, or when the URL is changed. [A convenience function](https://github.com/nasa/openmct/blob/master/src/utils/testing.js#L59) is provided for resetting the URL and clearing builtin spies between tests.
|
||||
* If writing unit tests for legacy Angular code be sure to follow [best practices in order to avoid memory leaks](https://www.thecodecampus.de/blog/avoid-memory-leaks-angularjs-unit-tests/).
|
||||
|
||||
#### Examples
|
||||
* [Example of an automated test spec for an object view plugin](https://github.com/nasa/openmct/blob/master/src/plugins/telemetryTable/pluginSpec.js)
|
||||
* [Example of an automated test spec for API](https://github.com/nasa/openmct/blob/master/src/api/time/TimeAPISpec.js)
|
||||
During automated testing, code coverage metrics will be reported. Line
|
||||
coverage must remain at or above 80%.
|
||||
|
||||
### Commit Message Standards
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Open MCT License
|
||||
|
||||
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, Copyright (c) 2014-2019, 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.
|
||||
|
||||
|
@ -28,16 +28,6 @@ define([
|
||||
domain: 2
|
||||
}
|
||||
},
|
||||
// Need to enable "LocalTimeSystem" plugin to make use of this
|
||||
// {
|
||||
// key: "local",
|
||||
// name: "Time",
|
||||
// format: "local-format",
|
||||
// source: "utc",
|
||||
// hints: {
|
||||
// domain: 3
|
||||
// }
|
||||
// },
|
||||
{
|
||||
key: "sin",
|
||||
name: "Sine",
|
||||
@ -71,15 +61,6 @@ define([
|
||||
domain: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "local",
|
||||
name: "Time",
|
||||
format: "utc",
|
||||
source: "utc",
|
||||
hints: {
|
||||
domain: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "state",
|
||||
source: "value",
|
||||
|
47
index.html
47
index.html
@ -34,8 +34,8 @@
|
||||
<body>
|
||||
</body>
|
||||
<script>
|
||||
const THIRTY_SECONDS = 30 * 1000;
|
||||
const THIRTY_MINUTES = THIRTY_SECONDS * 60;
|
||||
const FIVE_MINUTES = 5 * 60 * 1000;
|
||||
const THIRTY_MINUTES = 30 * 60 * 1000;
|
||||
|
||||
[
|
||||
'example/eventGenerator'
|
||||
@ -43,9 +43,7 @@
|
||||
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
|
||||
);
|
||||
|
||||
//openmct.install(openmct.plugins.LocalStorage());
|
||||
//Change 'vipersim' to whatever your local db is named
|
||||
openmct.install(openmct.plugins.CouchDB('http://localhost:5984/vipersim'));
|
||||
openmct.install(openmct.plugins.LocalStorage());
|
||||
openmct.install(openmct.plugins.Espresso());
|
||||
openmct.install(openmct.plugins.MyItems());
|
||||
openmct.install(openmct.plugins.Generator());
|
||||
@ -65,47 +63,15 @@
|
||||
bounds: {
|
||||
start: Date.now() - THIRTY_MINUTES,
|
||||
end: Date.now()
|
||||
},
|
||||
// commonly used bounds can be stored in history
|
||||
// bounds (start and end) can accept either a milliseconds number
|
||||
// or a callback function returning a milliseconds number
|
||||
// a function is useful for invoking Date.now() at exact moment of preset selection
|
||||
presets: [
|
||||
{
|
||||
label: 'Last Day',
|
||||
bounds: {
|
||||
start: () => Date.now() - 1000 * 60 * 60 * 24,
|
||||
end: () => Date.now()
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Last 2 hours',
|
||||
bounds: {
|
||||
start: () => Date.now() - 1000 * 60 * 60 * 2,
|
||||
end: () => Date.now()
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Last hour',
|
||||
bounds: {
|
||||
start: () => Date.now() - 1000 * 60 * 60,
|
||||
end: () => Date.now()
|
||||
}
|
||||
}
|
||||
],
|
||||
// maximum recent bounds to retain in conductor history
|
||||
records: 10,
|
||||
// maximum duration between start and end bounds
|
||||
// for utc-based time systems this is in milliseconds
|
||||
limit: 1000 * 60 * 60 * 24
|
||||
},
|
||||
{
|
||||
name: "Realtime",
|
||||
timeSystem: 'utc',
|
||||
clock: 'local',
|
||||
clockOffsets: {
|
||||
start: - THIRTY_MINUTES,
|
||||
end: THIRTY_SECONDS
|
||||
end: FIVE_MINUTES
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -115,10 +81,7 @@
|
||||
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'],
|
||||
{indicator: true}
|
||||
));
|
||||
openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked']));
|
||||
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' : 'FirefoxHeadless'];
|
||||
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless'];
|
||||
const coverageEnabled = process.env.COVERAGE === 'true';
|
||||
const reporters = ['progress', 'html'];
|
||||
|
||||
@ -95,7 +95,6 @@ module.exports = (config) => {
|
||||
stats: 'errors-only',
|
||||
logLevel: 'warn'
|
||||
},
|
||||
singleRun: true,
|
||||
browserNoActivityTimeout: 90000
|
||||
singleRun: true
|
||||
});
|
||||
}
|
||||
|
@ -41,7 +41,6 @@
|
||||
"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",
|
||||
@ -60,7 +59,7 @@
|
||||
"moment-timezone": "0.5.28",
|
||||
"node-bourbon": "^4.2.3",
|
||||
"node-sass": "^4.9.2",
|
||||
"painterro": "^1.0.35",
|
||||
"painterro": "^0.2.65",
|
||||
"printj": "^1.2.1",
|
||||
"raw-loader": "^0.5.1",
|
||||
"request": "^2.69.0",
|
||||
|
@ -81,15 +81,10 @@ define(
|
||||
* context.
|
||||
*/
|
||||
PropertiesAction.appliesTo = function (context) {
|
||||
|
||||
var domainObject = (context || {}).domainObject,
|
||||
type = domainObject && domainObject.getCapability('type'),
|
||||
creatable = type && type.hasFeature('creation');
|
||||
|
||||
if (domainObject && domainObject.model && domainObject.model.locked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow creatable types to be edited
|
||||
return domainObject && creatable;
|
||||
};
|
||||
|
@ -36,6 +36,8 @@ define(
|
||||
}
|
||||
|
||||
EditPersistableObjectsPolicy.prototype.allow = function (action, context) {
|
||||
var identifier;
|
||||
var provider;
|
||||
var domainObject = context.domainObject;
|
||||
var key = action.getMetadata().key;
|
||||
var category = (context || {}).category;
|
||||
@ -44,8 +46,9 @@ 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') {
|
||||
let newStyleObject = objectUtils.toNewFormat(domainObject, domainObject.getId());
|
||||
return this.openmct.objects.isPersistable(newStyleObject);
|
||||
identifier = objectUtils.parseKeyString(domainObject.getId());
|
||||
provider = this.openmct.objects.getProvider(identifier);
|
||||
return provider.save !== undefined;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -43,7 +43,7 @@ define(
|
||||
);
|
||||
|
||||
mockObjectAPI = jasmine.createSpyObj('objectAPI', [
|
||||
'isPersistable'
|
||||
'getProvider'
|
||||
]);
|
||||
|
||||
mockAPI = {
|
||||
@ -69,31 +69,34 @@ define(
|
||||
});
|
||||
|
||||
it("Applies to edit action", function () {
|
||||
expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled();
|
||||
mockObjectAPI.getProvider.and.returnValue({});
|
||||
expect(mockObjectAPI.getProvider).not.toHaveBeenCalled();
|
||||
|
||||
policy.allow(mockEditAction, testContext);
|
||||
expect(mockObjectAPI.isPersistable).toHaveBeenCalled();
|
||||
expect(mockObjectAPI.getProvider).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Applies to properties action", function () {
|
||||
expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled();
|
||||
mockObjectAPI.getProvider.and.returnValue({});
|
||||
expect(mockObjectAPI.getProvider).not.toHaveBeenCalled();
|
||||
|
||||
policy.allow(mockPropertiesAction, testContext);
|
||||
expect(mockObjectAPI.isPersistable).toHaveBeenCalled();
|
||||
expect(mockObjectAPI.getProvider).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not apply to other actions", function () {
|
||||
expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled();
|
||||
mockObjectAPI.getProvider.and.returnValue({});
|
||||
expect(mockObjectAPI.getProvider).not.toHaveBeenCalled();
|
||||
|
||||
policy.allow(mockOtherAction, testContext);
|
||||
expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled();
|
||||
expect(mockObjectAPI.getProvider).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("Tests object provider for editability", function () {
|
||||
mockObjectAPI.isPersistable.and.returnValue(false);
|
||||
mockObjectAPI.getProvider.and.returnValue({});
|
||||
expect(policy.allow(mockEditAction, testContext)).toBe(false);
|
||||
expect(mockObjectAPI.isPersistable).toHaveBeenCalled();
|
||||
mockObjectAPI.isPersistable.and.returnValue(true);
|
||||
expect(mockObjectAPI.getProvider).toHaveBeenCalled();
|
||||
mockObjectAPI.getProvider.and.returnValue({save: function () {}});
|
||||
expect(policy.allow(mockEditAction, testContext)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
@ -19,13 +19,7 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<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">
|
||||
<div class="c-object-label__type-icon {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div>
|
||||
<div class='c-object-label__name'>{{model.name}}</div>
|
||||
</div>
|
||||
|
@ -48,8 +48,9 @@ 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())) {
|
||||
let newStyleObject = objectUtils.toNewFormat(parent, parent.getId());
|
||||
return this.openmct.objects.isPersistable(newStyleObject);
|
||||
var identifier = objectUtils.parseKeyString(parent.getId());
|
||||
var provider = this.openmct.objects.getProvider(identifier);
|
||||
return provider.save !== undefined;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ define(
|
||||
|
||||
beforeEach(function () {
|
||||
objectAPI = jasmine.createSpyObj('objectsAPI', [
|
||||
'isPersistable'
|
||||
'getProvider'
|
||||
]);
|
||||
|
||||
mockOpenMCT = {
|
||||
@ -51,6 +51,10 @@ define(
|
||||
'isEditContextRoot'
|
||||
]);
|
||||
mockParent.getCapability.and.returnValue(mockEditorCapability);
|
||||
|
||||
objectAPI.getProvider.and.returnValue({
|
||||
save: function () {}
|
||||
});
|
||||
persistableCompositionPolicy = new PersistableCompositionPolicy(mockOpenMCT);
|
||||
});
|
||||
|
||||
@ -61,22 +65,19 @@ 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.isPersistable.and.returnValue(false);
|
||||
objectAPI.getProvider.and.returnValue({});
|
||||
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.isPersistable).not.toHaveBeenCalled();
|
||||
expect(objectAPI.getProvider).not.toHaveBeenCalled();
|
||||
|
||||
mockEditorCapability.isEditContextRoot.and.returnValue(false);
|
||||
objectAPI.isPersistable.and.returnValue(true);
|
||||
expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true);
|
||||
expect(objectAPI.isPersistable).toHaveBeenCalled();
|
||||
expect(objectAPI.getProvider).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -297,8 +297,7 @@ define([
|
||||
"persistenceService",
|
||||
"identifierService",
|
||||
"notificationService",
|
||||
"$q",
|
||||
"openmct"
|
||||
"$q"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -20,8 +20,8 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(["objectUtils"],
|
||||
function (objectUtils) {
|
||||
define(
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Defines the `persistence` capability, used to trigger the
|
||||
@ -47,7 +47,6 @@ define(["objectUtils"],
|
||||
identifierService,
|
||||
notificationService,
|
||||
$q,
|
||||
openmct,
|
||||
domainObject
|
||||
) {
|
||||
// Cache modified timestamp
|
||||
@ -59,7 +58,6 @@ define(["objectUtils"],
|
||||
this.persistenceService = persistenceService;
|
||||
this.notificationService = notificationService;
|
||||
this.$q = $q;
|
||||
this.openmct = openmct;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,7 +66,7 @@ define(["objectUtils"],
|
||||
*/
|
||||
function rejectIfFalsey(value, $q) {
|
||||
if (!value) {
|
||||
return Promise.reject("Error persisting object");
|
||||
return $q.reject("Error persisting object");
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
@ -100,7 +98,7 @@ define(["objectUtils"],
|
||||
dismissable: true
|
||||
});
|
||||
|
||||
return Promise.reject(error);
|
||||
return $q.reject(error);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,12 +110,30 @@ define(["objectUtils"],
|
||||
*/
|
||||
PersistenceCapability.prototype.persist = function () {
|
||||
var self = this,
|
||||
domainObject = this.domainObject;
|
||||
domainObject = this.domainObject,
|
||||
model = domainObject.getModel(),
|
||||
modified = model.modified,
|
||||
persisted = model.persisted,
|
||||
persistenceService = this.persistenceService,
|
||||
persistenceFn = persisted !== undefined ?
|
||||
this.persistenceService.updateObject :
|
||||
this.persistenceService.createObject;
|
||||
|
||||
let newStyleObject = objectUtils.toNewFormat(domainObject.getModel(), domainObject.getId());
|
||||
return this.openmct.objects
|
||||
.save(newStyleObject)
|
||||
.then(function (result) {
|
||||
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);
|
||||
|
@ -19,6 +19,7 @@
|
||||
* 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.
|
||||
*/
|
||||
@ -39,8 +40,7 @@ define(
|
||||
model,
|
||||
SPACE = "some space",
|
||||
persistence,
|
||||
mockOpenMCT,
|
||||
mockNewStyleDomainObject;
|
||||
happyPromise;
|
||||
|
||||
function asPromise(value, doCatch) {
|
||||
return (value || {}).then ? value : {
|
||||
@ -56,6 +56,7 @@ define(
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
happyPromise = asPromise(true);
|
||||
model = { someKey: "some value", name: "domain object"};
|
||||
|
||||
mockPersistenceService = jasmine.createSpyObj(
|
||||
@ -93,23 +94,12 @@ 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);
|
||||
@ -120,28 +110,51 @@ define(
|
||||
mockIdentifierService,
|
||||
mockNofificationService,
|
||||
mockQ,
|
||||
mockOpenMCT,
|
||||
mockDomainObject
|
||||
);
|
||||
});
|
||||
|
||||
describe("successful persistence", function () {
|
||||
beforeEach(function () {
|
||||
mockOpenMCT.objects.save.and.returnValue(Promise.resolve(true));
|
||||
mockPersistenceService.updateObject.and.returnValue(happyPromise);
|
||||
mockPersistenceService.createObject.and.returnValue(happyPromise);
|
||||
});
|
||||
it("creates unpersisted objects with the persistence service", function () {
|
||||
// Verify precondition; no call made during constructor
|
||||
expect(mockOpenMCT.objects.save).not.toHaveBeenCalled();
|
||||
expect(mockPersistenceService.createObject).not.toHaveBeenCalled();
|
||||
|
||||
persistence.persist();
|
||||
|
||||
expect(mockOpenMCT.objects.save).toHaveBeenCalledWith(mockNewStyleDomainObject);
|
||||
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
|
||||
);
|
||||
});
|
||||
|
||||
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;
|
||||
@ -152,39 +165,32 @@ define(
|
||||
|
||||
it("does not trigger error notification on successful" +
|
||||
" persistence", function () {
|
||||
let rejected = false;
|
||||
return persistence.persist()
|
||||
.catch(() => rejected = true)
|
||||
.then(() => {
|
||||
expect(rejected).toBe(false);
|
||||
persistence.persist();
|
||||
expect(mockQ.reject).not.toHaveBeenCalled();
|
||||
expect(mockNofificationService.error).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("unsuccessful persistence", function () {
|
||||
var sadPromise = {
|
||||
then: function (callback) {
|
||||
return asPromise(callback(0), true);
|
||||
}
|
||||
};
|
||||
beforeEach(function () {
|
||||
mockOpenMCT.objects.save.and.returnValue(Promise.resolve(false));
|
||||
mockPersistenceService.createObject.and.returnValue(sadPromise);
|
||||
});
|
||||
it("rejects on falsey persistence result", function () {
|
||||
let rejected = false;
|
||||
return persistence.persist()
|
||||
.catch(() => rejected = true)
|
||||
.then(() => {
|
||||
expect(rejected).toBe(true);
|
||||
});
|
||||
persistence.persist();
|
||||
expect(mockQ.reject).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("notifies user on persistence failure", function () {
|
||||
let rejected = false;
|
||||
return persistence.persist()
|
||||
.catch(() => rejected = true)
|
||||
.then(() => {
|
||||
expect(rejected).toBe(true);
|
||||
persistence.persist();
|
||||
expect(mockQ.reject).toHaveBeenCalled();
|
||||
expect(mockNofificationService.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -40,18 +40,7 @@ define(
|
||||
}
|
||||
|
||||
MoveAction.prototype = Object.create(AbstractComposeAction.prototype);
|
||||
|
||||
MoveAction.appliesTo = function (context) {
|
||||
var applicableObject =
|
||||
context.selectedObject || context.domainObject;
|
||||
|
||||
if (applicableObject && applicableObject.model.locked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Boolean(applicableObject &&
|
||||
applicableObject.hasCapability('context'));
|
||||
};
|
||||
MoveAction.appliesTo = AbstractComposeAction.appliesTo;
|
||||
|
||||
return MoveAction;
|
||||
}
|
||||
|
@ -216,14 +216,8 @@ define(['zepto', 'objectUtils'], function ($, objectUtils) {
|
||||
};
|
||||
|
||||
ImportAsJSONAction.appliesTo = function (context) {
|
||||
let domainObject = context.domainObject;
|
||||
|
||||
if (domainObject && domainObject.model.locked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return domainObject !== undefined &&
|
||||
domainObject.hasCapability("composition");
|
||||
return context.domainObject !== undefined &&
|
||||
context.domainObject.hasCapability("composition");
|
||||
};
|
||||
|
||||
return ImportAsJSONAction;
|
||||
|
621
report.20200527.134750.93992.001.json
Normal file
621
report.20200527.134750.93992.001.json
Normal file
@ -0,0 +1,621 @@
|
||||
|
||||
{
|
||||
"header": {
|
||||
"event": "Allocation failed - JavaScript heap out of memory",
|
||||
"location": "OnFatalError",
|
||||
"filename": "report.20200527.134750.93992.001.json",
|
||||
"dumpEventTime": "2020-05-27T13:47:50Z",
|
||||
"dumpEventTimeStamp": "1590612470877",
|
||||
"processId": 93992,
|
||||
"commandLine": [
|
||||
"node",
|
||||
"/Users/dtailor/Desktop/openmct/node_modules/.bin/karma",
|
||||
"start",
|
||||
"--single-run"
|
||||
],
|
||||
"nodejsVersion": "v11.9.0",
|
||||
"wordSize": 64,
|
||||
"componentVersions": {
|
||||
"node": "11.9.0",
|
||||
"v8": "7.0.276.38-node.16",
|
||||
"uv": "1.25.0",
|
||||
"zlib": "1.2.11",
|
||||
"brotli": "1.0.7",
|
||||
"ares": "1.15.0",
|
||||
"modules": "67",
|
||||
"nghttp2": "1.34.0",
|
||||
"napi": "4",
|
||||
"llhttp": "1.0.1",
|
||||
"http_parser": "2.8.0",
|
||||
"openssl": "1.1.1a",
|
||||
"cldr": "34.0",
|
||||
"icu": "63.1",
|
||||
"tz": "2018e",
|
||||
"unicode": "11.0",
|
||||
"arch": "x64",
|
||||
"platform": "darwin",
|
||||
"release": "node"
|
||||
},
|
||||
"osVersion": "Darwin 18.7.0 Darwin Kernel Version 18.7.0: Thu Jan 23 06:52:12 PST 2020; root:xnu-4903.278.25~1/RELEASE_X86_64",
|
||||
"machine": "Darwin 18.7.0 Darwin Kernel Version 18.7.0: Thu Jan 23 06:52:12 PST 2020; root:xnu-4903.278.25~1/RELEASE_X86_64tailor x86_64"
|
||||
},
|
||||
"javascriptStack": {
|
||||
"message": "No stack.",
|
||||
"stack": [
|
||||
"Unavailable."
|
||||
]
|
||||
},
|
||||
"nativeStack": [
|
||||
" [pc=0x10013090e] report::TriggerNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, v8::Local<v8::String>) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x100063744] node::OnFatalError(char const*, char const*) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x1001a8c47] v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x1001a8be4] v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x1005add42] v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x1005b0273] v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x1005ac7a8] v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x1005aa965] v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x1005b720c] v8::internal::Heap::AllocateRawWithLightRetry(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x1005b728f] v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x100586484] v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x1008389a4] v8::internal::Runtime_AllocateInNewSpace(int, v8::internal::Object**, v8::internal::Isolate*) [/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node]",
|
||||
" [pc=0x14acfddcfc7d] "
|
||||
],
|
||||
"javascriptHeap": {
|
||||
"totalMemory": 1479229440,
|
||||
"totalCommittedMemory": 1477309024,
|
||||
"usedMemory": 1445511032,
|
||||
"availableMemory": 50296592,
|
||||
"memoryLimit": 1526909922,
|
||||
"heapSpaces": {
|
||||
"read_only_space": {
|
||||
"memorySize": 524288,
|
||||
"committedMemory": 42224,
|
||||
"capacity": 515584,
|
||||
"used": 33520,
|
||||
"available": 482064
|
||||
},
|
||||
"new_space": {
|
||||
"memorySize": 4194304,
|
||||
"committedMemory": 4194288,
|
||||
"capacity": 2062336,
|
||||
"used": 59016,
|
||||
"available": 2003320
|
||||
},
|
||||
"old_space": {
|
||||
"memorySize": 305860608,
|
||||
"committedMemory": 305138544,
|
||||
"capacity": 283264904,
|
||||
"used": 282942208,
|
||||
"available": 322696
|
||||
},
|
||||
"code_space": {
|
||||
"memorySize": 6291456,
|
||||
"committedMemory": 5687328,
|
||||
"capacity": 5237152,
|
||||
"used": 5237152,
|
||||
"available": 0
|
||||
},
|
||||
"map_space": {
|
||||
"memorySize": 5255168,
|
||||
"committedMemory": 5143024,
|
||||
"capacity": 2523280,
|
||||
"used": 2523280,
|
||||
"available": 0
|
||||
},
|
||||
"large_object_space": {
|
||||
"memorySize": 1157103616,
|
||||
"committedMemory": 1157103616,
|
||||
"capacity": 1202204368,
|
||||
"used": 1154715856,
|
||||
"available": 47488512
|
||||
},
|
||||
"new_large_object_space": {
|
||||
"memorySize": 0,
|
||||
"committedMemory": 0,
|
||||
"capacity": 0,
|
||||
"used": 0,
|
||||
"available": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"resourceUsage": {
|
||||
"userCpuSeconds": 43.1616,
|
||||
"kernelCpuSeconds": 43.1616,
|
||||
"cpuConsumptionPercent": 5.42705e-06,
|
||||
"maxRss": 1966080000000,
|
||||
"pageFaults": {
|
||||
"IORequired": 245,
|
||||
"IONotRequired": 832598
|
||||
},
|
||||
"fsActivity": {
|
||||
"reads": 0,
|
||||
"writes": 0
|
||||
}
|
||||
},
|
||||
"libuv": [
|
||||
],
|
||||
"environmentVariables": {
|
||||
"npm_config_save_dev": "",
|
||||
"npm_config_legacy_bundling": "",
|
||||
"npm_config_dry_run": "",
|
||||
"npm_package_devDependencies_markdown_toc": "^0.11.7",
|
||||
"npm_config_only": "",
|
||||
"npm_config_browser": "",
|
||||
"npm_config_viewer": "man",
|
||||
"npm_config_commit_hooks": "true",
|
||||
"npm_package_gitHead": "7126abe7ec1d66d3252f3598fbd6bd27217018bc",
|
||||
"npm_config_also": "",
|
||||
"npm_package_scripts_otherdoc": "node docs/gendocs.js --in docs/src --out dist/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
|
||||
"npm_package_devDependencies_minimist": "^1.1.1",
|
||||
"npm_config_sign_git_commit": "",
|
||||
"npm_config_rollback": "true",
|
||||
"npm_package_devDependencies_fast_sass_loader": "1.4.6",
|
||||
"TERM_PROGRAM": "Apple_Terminal",
|
||||
"npm_config_usage": "",
|
||||
"npm_config_audit": "true",
|
||||
"npm_package_devDependencies_git_rev_sync": "^1.4.0",
|
||||
"npm_package_devDependencies_file_loader": "^1.1.11",
|
||||
"npm_package_devDependencies_d3_selection": "1.3.x",
|
||||
"NODE": "/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node",
|
||||
"npm_package_homepage": "https://github.com/nasa/openmct#readme",
|
||||
"INIT_CWD": "/Users/dtailor/Desktop/openmct",
|
||||
"NVM_CD_FLAGS": "",
|
||||
"npm_config_globalignorefile": "/Users/dtailor/.nvm/versions/node/v11.9.0/etc/npmignore",
|
||||
"npm_package_devDependencies_comma_separated_values": "^3.6.4",
|
||||
"SHELL": "/bin/bash",
|
||||
"TERM": "xterm-256color",
|
||||
"npm_config_init_author_url": "",
|
||||
"npm_config_shell": "/bin/bash",
|
||||
"npm_config_maxsockets": "50",
|
||||
"npm_package_devDependencies_vue_template_compiler": "2.5.6",
|
||||
"npm_package_devDependencies_style_loader": "^1.0.1",
|
||||
"npm_package_devDependencies_moment_duration_format": "^2.2.2",
|
||||
"npm_config_parseable": "",
|
||||
"npm_config_shrinkwrap": "true",
|
||||
"npm_config_metrics_registry": "https://registry.npmjs.org/",
|
||||
"TMPDIR": "/var/folders/ks/ytghmh9x4lj3cchr5km5lhkcb7v9y2/T/",
|
||||
"npm_config_timing": "",
|
||||
"npm_config_init_license": "ISC",
|
||||
"npm_package_scripts_lint": "eslint platform example src --ext .js,.vue openmct.js",
|
||||
"npm_package_devDependencies_d3_array": "1.2.x",
|
||||
"Apple_PubSub_Socket_Render": "/private/tmp/com.apple.launchd.PsV6Dfq4Tm/Render",
|
||||
"npm_config_if_present": "",
|
||||
"npm_package_devDependencies_concurrently": "^3.6.1",
|
||||
"TERM_PROGRAM_VERSION": "421.2",
|
||||
"npm_package_scripts_jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
|
||||
"npm_config_sign_git_tag": "",
|
||||
"npm_config_init_author_email": "",
|
||||
"npm_config_cache_max": "Infinity",
|
||||
"npm_config_preid": "",
|
||||
"npm_config_long": "",
|
||||
"npm_config_local_address": "",
|
||||
"npm_config_cert": "",
|
||||
"npm_config_git_tag_version": "true",
|
||||
"npm_package_devDependencies_exports_loader": "^0.7.0",
|
||||
"TERM_SESSION_ID": "0630D2FA-BAC2-48D3-A21D-9AB58A79FB14",
|
||||
"npm_config_noproxy": "",
|
||||
"npm_config_registry": "https://registry.npmjs.org/",
|
||||
"npm_config_fetch_retries": "2",
|
||||
"npm_package_private": "true",
|
||||
"npm_package_devDependencies_karma_jasmine": "^1.1.2",
|
||||
"npm_package_repository_url": "git+https://github.com/nasa/openmct.git",
|
||||
"npm_config_versions": "",
|
||||
"npm_config_key": "",
|
||||
"npm_config_message": "%s",
|
||||
"npm_package_readmeFilename": "README.md",
|
||||
"npm_package_devDependencies_painterro": "^0.2.65",
|
||||
"npm_package_scripts_verify": "concurrently 'npm:test' 'npm:lint'",
|
||||
"npm_package_devDependencies_webpack": "^4.16.2",
|
||||
"npm_package_devDependencies_eventemitter3": "^1.2.0",
|
||||
"npm_package_description": "The Open MCT core platform",
|
||||
"USER": "dtailor",
|
||||
"NVM_DIR": "/Users/dtailor/.nvm",
|
||||
"npm_package_license": "Apache-2.0",
|
||||
"npm_package_scripts_build_dev": "webpack",
|
||||
"npm_package_devDependencies_webpack_cli": "^3.1.0",
|
||||
"npm_package_devDependencies_location_bar": "^3.0.1",
|
||||
"npm_package_devDependencies_jasmine_core": "^3.1.0",
|
||||
"npm_config_globalconfig": "/Users/dtailor/.nvm/versions/node/v11.9.0/etc/npmrc",
|
||||
"npm_package_devDependencies_karma": "^2.0.3",
|
||||
"npm_config_prefer_online": "",
|
||||
"npm_config_always_auth": "",
|
||||
"npm_config_logs_max": "10",
|
||||
"npm_package_devDependencies_angular": "1.7.9",
|
||||
"SSH_AUTH_SOCK": "/private/tmp/com.apple.launchd.JH8E4KgH06/Listeners",
|
||||
"npm_package_devDependencies_request": "^2.69.0",
|
||||
"npm_package_devDependencies_eslint": "5.2.0",
|
||||
"__CF_USER_TEXT_ENCODING": "0x167DA7C2:0x0:0x0",
|
||||
"npm_execpath": "/Users/dtailor/.nvm/versions/node/v11.9.0/lib/node_modules/npm/bin/npm-cli.js",
|
||||
"npm_config_global_style": "",
|
||||
"npm_config_cache_lock_retries": "10",
|
||||
"npm_config_cafile": "",
|
||||
"npm_config_update_notifier": "true",
|
||||
"npm_package_scripts_test_debug": "cross-env NODE_ENV=debug karma start --no-single-run",
|
||||
"npm_package_devDependencies_glob": ">= 3.0.0",
|
||||
"npm_config_heading": "npm",
|
||||
"npm_config_audit_level": "low",
|
||||
"npm_package_devDependencies_mini_css_extract_plugin": "^0.4.1",
|
||||
"npm_package_devDependencies_copy_webpack_plugin": "^4.5.2",
|
||||
"npm_config_read_only": "",
|
||||
"npm_config_offline": "",
|
||||
"npm_config_searchlimit": "20",
|
||||
"npm_config_fetch_retry_mintimeout": "10000",
|
||||
"npm_package_devDependencies_webpack_dev_middleware": "^3.1.3",
|
||||
"npm_config_json": "",
|
||||
"npm_config_access": "",
|
||||
"npm_config_argv": "{\"remain\":[],\"cooked\":[\"run\",\"test\"],\"original\":[\"run\",\"test\"]}",
|
||||
"npm_package_scripts_lint_fix": "eslint platform example src --ext .js,.vue openmct.js --fix",
|
||||
"npm_package_devDependencies_uuid": "^3.3.3",
|
||||
"npm_package_devDependencies_karma_coverage": "^1.1.2",
|
||||
"PATH": "/Users/dtailor/.nvm/versions/node/v11.9.0/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/dtailor/Desktop/openmct/node_modules/.bin:/Users/dtailor/.nvm/versions/node/v11.9.0/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/dtailor/Desktop/openmct/node_modules/.bin:/Users/dtailor/.nvm/versions/node/v11.9.0/bin:/Users/dtailor/.homebrew/bin:/Users/dtailor/local/bin:/Users/dtailor/.homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Users/dtailor/Applications/Visual Studio Code.app/Contents/Resources/app/bin:/opt/local/bin:/Users/dtailor/.homebrew/bin:/Users/dtailor/.homebrew/bin:/Users/dtailor/.homebrew/bin:/Users/dtailor/local/bin:/Users/dtailor/.homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin",
|
||||
"npm_config_allow_same_version": "",
|
||||
"npm_config_https_proxy": "",
|
||||
"npm_config_engine_strict": "",
|
||||
"npm_config_description": "true",
|
||||
"npm_package_devDependencies_html2canvas": "^1.0.0-alpha.12",
|
||||
"_": "/Users/dtailor/Desktop/openmct/node_modules/.bin/karma",
|
||||
"npm_config_userconfig": "/Users/dtailor/.npmrc",
|
||||
"npm_config_init_module": "/Users/dtailor/.npm-init.js",
|
||||
"npm_package_author": "",
|
||||
"npm_package_devDependencies_karma_chrome_launcher": "^2.2.0",
|
||||
"npm_package_devDependencies_d3_scale": "1.0.x",
|
||||
"npm_config_cidr": "",
|
||||
"npm_package_devDependencies_printj": "^1.2.1",
|
||||
"PWD": "/Users/dtailor/Desktop/openmct",
|
||||
"npm_config_user": "377333698",
|
||||
"npm_config_node_version": "11.9.0",
|
||||
"npm_package_bugs_url": "https://github.com/nasa/openmct/issues",
|
||||
"npm_package_scripts_test_watch": "karma start --no-single-run",
|
||||
"npm_lifecycle_event": "test",
|
||||
"npm_package_devDependencies_v8_compile_cache": "^1.1.0",
|
||||
"npm_config_ignore_prepublish": "",
|
||||
"npm_config_save": "true",
|
||||
"npm_config_editor": "vi",
|
||||
"npm_config_auth_type": "legacy",
|
||||
"npm_package_repository_type": "git",
|
||||
"npm_package_devDependencies_vue": "2.5.6",
|
||||
"npm_package_devDependencies_marked": "^0.3.5",
|
||||
"npm_package_devDependencies_angular_route": "1.4.14",
|
||||
"npm_package_name": "openmct",
|
||||
"LANG": "en_US.UTF-8",
|
||||
"npm_config_script_shell": "",
|
||||
"npm_config_tag": "latest",
|
||||
"npm_config_global": "",
|
||||
"npm_config_progress": "true",
|
||||
"npm_package_scripts_start": "node app.js",
|
||||
"npm_package_devDependencies_karma_coverage_istanbul_reporter": "^2.1.1",
|
||||
"npm_config_ham_it_up": "",
|
||||
"npm_config_searchstaleness": "900",
|
||||
"npm_config_optional": "true",
|
||||
"npm_package_scripts_docs": "npm run jsdoc ; npm run otherdoc",
|
||||
"npm_package_devDependencies_istanbul_instrumenter_loader": "^3.0.1",
|
||||
"XPC_FLAGS": "0x0",
|
||||
"npm_config_save_prod": "",
|
||||
"npm_config_force": "",
|
||||
"npm_config_bin_links": "true",
|
||||
"npm_package_devDependencies_moment": "2.25.3",
|
||||
"npm_package_devDependencies_karma_webpack": "^3.0.0",
|
||||
"npm_package_devDependencies_express": "^4.13.1",
|
||||
"npm_config_searchopts": "",
|
||||
"npm_package_devDependencies_d3_time": "1.0.x",
|
||||
"FORCE_COLOR": "2",
|
||||
"npm_config_node_gyp": "/Users/dtailor/.nvm/versions/node/v11.9.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js",
|
||||
"npm_config_depth": "Infinity",
|
||||
"npm_package_scripts_build_prod": "cross-env NODE_ENV=production webpack",
|
||||
"npm_config_sso_poll_frequency": "500",
|
||||
"npm_config_rebuild_bundle": "true",
|
||||
"npm_package_version": "1.0.0-snapshot",
|
||||
"XPC_SERVICE_NAME": "0",
|
||||
"npm_config_unicode": "true",
|
||||
"npm_package_devDependencies_jsdoc": "^3.3.2",
|
||||
"SHLVL": "4",
|
||||
"HOME": "/Users/dtailor",
|
||||
"npm_config_fetch_retry_maxtimeout": "60000",
|
||||
"npm_package_scripts_test": "karma start --single-run",
|
||||
"npm_package_devDependencies_zepto": "^1.2.0",
|
||||
"npm_package_devDependencies_eslint_plugin_vue": "^6.0.0",
|
||||
"npm_config_ca": "",
|
||||
"npm_config_tag_version_prefix": "v",
|
||||
"npm_config_strict_ssl": "true",
|
||||
"npm_config_sso_type": "oauth",
|
||||
"npm_config_scripts_prepend_node_path": "warn-only",
|
||||
"npm_config_save_prefix": "^",
|
||||
"npm_config_loglevel": "notice",
|
||||
"npm_package_devDependencies_lodash": "^3.10.1",
|
||||
"npm_package_devDependencies_karma_cli": "^1.0.1",
|
||||
"npm_package_devDependencies_d3_color": "1.0.x",
|
||||
"npm_config_save_exact": "",
|
||||
"npm_config_dev": "",
|
||||
"npm_config_group": "1286109195",
|
||||
"npm_config_fetch_retry_factor": "10",
|
||||
"npm_package_devDependencies_webpack_hot_middleware": "^2.22.3",
|
||||
"npm_package_devDependencies_cross_env": "^6.0.3",
|
||||
"npm_package_devDependencies_babel_eslint": "8.2.6",
|
||||
"HOMEBREW_PREFIX": "/Users/dtailor/.homebrew",
|
||||
"npm_config_version": "",
|
||||
"npm_config_prefer_offline": "",
|
||||
"npm_config_cache_lock_stale": "60000",
|
||||
"npm_config_otp": "",
|
||||
"npm_config_cache_min": "10",
|
||||
"npm_package_devDependencies_vue_loader": "^15.2.6",
|
||||
"npm_config_searchexclude": "",
|
||||
"npm_config_cache": "/Users/dtailor/.npm",
|
||||
"npm_package_scripts_test_coverage": "./scripts/test-coverage.sh",
|
||||
"npm_package_devDependencies_d3_interpolate": "1.1.x",
|
||||
"npm_package_devDependencies_d3_format": "1.2.x",
|
||||
"LOGNAME": "dtailor",
|
||||
"npm_lifecycle_script": "karma start --single-run",
|
||||
"npm_config_color": "true",
|
||||
"npm_package_devDependencies_node_bourbon": "^4.2.3",
|
||||
"npm_package_devDependencies_karma_sourcemap_loader": "^0.3.7",
|
||||
"npm_package_devDependencies_karma_html_reporter": "^0.2.7",
|
||||
"npm_config_proxy": "",
|
||||
"npm_config_package_lock": "true",
|
||||
"npm_package_devDependencies_d3_time_format": "2.1.x",
|
||||
"npm_package_devDependencies_d3_axis": "1.0.x",
|
||||
"npm_config_package_lock_only": "",
|
||||
"npm_package_devDependencies_moment_timezone": "0.5.28",
|
||||
"npm_config_save_optional": "",
|
||||
"NVM_BIN": "/Users/dtailor/.nvm/versions/node/v11.9.0/bin",
|
||||
"npm_config_ignore_scripts": "",
|
||||
"npm_config_user_agent": "npm/6.5.0 node/v11.9.0 darwin x64",
|
||||
"npm_package_devDependencies_imports_loader": "^0.8.0",
|
||||
"npm_package_devDependencies_file_saver": "^1.3.8",
|
||||
"npm_config_cache_lock_wait": "10000",
|
||||
"npm_config_production": "",
|
||||
"npm_package_scripts_build_watch": "webpack --watch",
|
||||
"DISPLAY": "/private/tmp/com.apple.launchd.E3N8oC6RMf/org.macosforge.xquartz:0",
|
||||
"npm_config_send_metrics": "",
|
||||
"npm_config_save_bundle": "",
|
||||
"npm_package_scripts_prepare": "npm run build:prod",
|
||||
"npm_config_node_options": "",
|
||||
"npm_config_umask": "0022",
|
||||
"npm_config_init_version": "1.0.0",
|
||||
"npm_package_devDependencies_split": "^1.0.0",
|
||||
"npm_package_devDependencies_raw_loader": "^0.5.1",
|
||||
"npm_config_init_author_name": "",
|
||||
"npm_config_git": "git",
|
||||
"npm_config_scope": "",
|
||||
"npm_package_scripts_clean": "rm -rf ./dist",
|
||||
"npm_package_devDependencies_node_sass": "^4.9.2",
|
||||
"npm_package_devDependencies_css_loader": "^1.0.0",
|
||||
"DISABLE_UPDATE_CHECK": "1",
|
||||
"npm_config_onload_script": "",
|
||||
"npm_config_unsafe_perm": "true",
|
||||
"npm_config_tmp": "/var/folders/ks/ytghmh9x4lj3cchr5km5lhkcb7v9y2/T",
|
||||
"npm_package_devDependencies_d3_collection": "1.0.x",
|
||||
"npm_node_execpath": "/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node",
|
||||
"npm_config_link": "",
|
||||
"npm_config_prefix": "/Users/dtailor/.nvm/versions/node/v11.9.0",
|
||||
"npm_package_devDependencies_html_loader": "^0.5.5"
|
||||
},
|
||||
"userLimits": {
|
||||
"core_file_size_blocks": {
|
||||
"soft": 0,
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"data_seg_size_kbytes": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"file_size_blocks": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"max_locked_memory_bytes": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"max_memory_size_kbytes": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"open_files": {
|
||||
"soft": 24576,
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"stack_size_bytes": {
|
||||
"soft": 8388608,
|
||||
"hard": 67104768
|
||||
},
|
||||
"cpu_time_seconds": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"max_user_processes": {
|
||||
"soft": 1418,
|
||||
"hard": 2128
|
||||
},
|
||||
"virtual_memory_kbytes": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
}
|
||||
},
|
||||
"sharedObjects": [
|
||||
"/Users/dtailor/.nvm/versions/node/v11.9.0/bin/node",
|
||||
"/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation",
|
||||
"/usr/lib/libSystem.B.dylib",
|
||||
"/usr/lib/libc++.1.dylib",
|
||||
"/usr/lib/libobjc.A.dylib",
|
||||
"/usr/lib/libDiagnosticMessagesClient.dylib",
|
||||
"/usr/lib/libicucore.A.dylib",
|
||||
"/usr/lib/libz.1.dylib",
|
||||
"/usr/lib/libc++abi.dylib",
|
||||
"/usr/lib/system/libcache.dylib",
|
||||
"/usr/lib/system/libcommonCrypto.dylib",
|
||||
"/usr/lib/system/libcompiler_rt.dylib",
|
||||
"/usr/lib/system/libcopyfile.dylib",
|
||||
"/usr/lib/system/libcorecrypto.dylib",
|
||||
"/usr/lib/system/libdispatch.dylib",
|
||||
"/usr/lib/system/libdyld.dylib",
|
||||
"/usr/lib/system/libkeymgr.dylib",
|
||||
"/usr/lib/system/liblaunch.dylib",
|
||||
"/usr/lib/system/libmacho.dylib",
|
||||
"/usr/lib/system/libquarantine.dylib",
|
||||
"/usr/lib/system/libremovefile.dylib",
|
||||
"/usr/lib/system/libsystem_asl.dylib",
|
||||
"/usr/lib/system/libsystem_blocks.dylib",
|
||||
"/usr/lib/system/libsystem_c.dylib",
|
||||
"/usr/lib/system/libsystem_configuration.dylib",
|
||||
"/usr/lib/system/libsystem_coreservices.dylib",
|
||||
"/usr/lib/system/libsystem_darwin.dylib",
|
||||
"/usr/lib/system/libsystem_dnssd.dylib",
|
||||
"/usr/lib/system/libsystem_info.dylib",
|
||||
"/usr/lib/system/libsystem_m.dylib",
|
||||
"/usr/lib/system/libsystem_malloc.dylib",
|
||||
"/usr/lib/system/libsystem_networkextension.dylib",
|
||||
"/usr/lib/system/libsystem_notify.dylib",
|
||||
"/usr/lib/system/libsystem_sandbox.dylib",
|
||||
"/usr/lib/system/libsystem_secinit.dylib",
|
||||
"/usr/lib/system/libsystem_kernel.dylib",
|
||||
"/usr/lib/system/libsystem_platform.dylib",
|
||||
"/usr/lib/system/libsystem_pthread.dylib",
|
||||
"/usr/lib/system/libsystem_symptoms.dylib",
|
||||
"/usr/lib/system/libsystem_trace.dylib",
|
||||
"/usr/lib/system/libunwind.dylib",
|
||||
"/usr/lib/system/libxpc.dylib",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices",
|
||||
"/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics",
|
||||
"/System/Library/Frameworks/CoreText.framework/Versions/A/CoreText",
|
||||
"/System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO",
|
||||
"/System/Library/Frameworks/ColorSync.framework/Versions/A/ColorSync",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/ATS",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ColorSyncLegacy.framework/Versions/A/ColorSyncLegacy",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/HIServices",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/LangAnalysis.framework/Versions/A/LangAnalysis",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A/PrintCore",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/QD.framework/Versions/A/QD",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/SpeechSynthesis",
|
||||
"/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight",
|
||||
"/System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface",
|
||||
"/usr/lib/libxml2.2.dylib",
|
||||
"/System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate",
|
||||
"/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation",
|
||||
"/usr/lib/libcompression.dylib",
|
||||
"/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration",
|
||||
"/System/Library/Frameworks/CoreDisplay.framework/Versions/A/CoreDisplay",
|
||||
"/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit",
|
||||
"/System/Library/Frameworks/Metal.framework/Versions/A/Metal",
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders",
|
||||
"/System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/A/MultitouchSupport",
|
||||
"/System/Library/Frameworks/Security.framework/Versions/A/Security",
|
||||
"/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore",
|
||||
"/usr/lib/libbsm.0.dylib",
|
||||
"/usr/lib/liblzma.5.dylib",
|
||||
"/usr/lib/libauto.dylib",
|
||||
"/System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration",
|
||||
"/usr/lib/libarchive.2.dylib",
|
||||
"/usr/lib/liblangid.dylib",
|
||||
"/usr/lib/libCRFSuite.dylib",
|
||||
"/usr/lib/libenergytrace.dylib",
|
||||
"/usr/lib/system/libkxld.dylib",
|
||||
"/System/Library/PrivateFrameworks/AppleFSCompression.framework/Versions/A/AppleFSCompression",
|
||||
"/usr/lib/libOpenScriptingUtil.dylib",
|
||||
"/usr/lib/libcoretls.dylib",
|
||||
"/usr/lib/libcoretls_cfhelpers.dylib",
|
||||
"/usr/lib/libpam.2.dylib",
|
||||
"/usr/lib/libsqlite3.dylib",
|
||||
"/usr/lib/libxar.1.dylib",
|
||||
"/usr/lib/libbz2.1.0.dylib",
|
||||
"/usr/lib/libnetwork.dylib",
|
||||
"/usr/lib/libapple_nghttp2.dylib",
|
||||
"/usr/lib/libpcap.A.dylib",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/FSEvents",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Metadata",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/OSServices.framework/Versions/A/OSServices",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SearchKit.framework/Versions/A/SearchKit",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/AE",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/LaunchServices",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/DictionaryServices.framework/Versions/A/DictionaryServices",
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SharedFileList.framework/Versions/A/SharedFileList",
|
||||
"/System/Library/Frameworks/NetFS.framework/Versions/A/NetFS",
|
||||
"/System/Library/PrivateFrameworks/NetAuth.framework/Versions/A/NetAuth",
|
||||
"/System/Library/PrivateFrameworks/login.framework/Versions/A/Frameworks/loginsupport.framework/Versions/A/loginsupport",
|
||||
"/System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC",
|
||||
"/System/Library/PrivateFrameworks/CoreNLP.framework/Versions/A/CoreNLP",
|
||||
"/System/Library/PrivateFrameworks/MetadataUtilities.framework/Versions/A/MetadataUtilities",
|
||||
"/usr/lib/libmecabra.dylib",
|
||||
"/usr/lib/libmecab.1.0.0.dylib",
|
||||
"/usr/lib/libgermantok.dylib",
|
||||
"/usr/lib/libThaiTokenizer.dylib",
|
||||
"/usr/lib/libChineseTokenizer.dylib",
|
||||
"/usr/lib/libiconv.2.dylib",
|
||||
"/usr/lib/libcharset.1.dylib",
|
||||
"/System/Library/PrivateFrameworks/LanguageModeling.framework/Versions/A/LanguageModeling",
|
||||
"/System/Library/PrivateFrameworks/CoreEmoji.framework/Versions/A/CoreEmoji",
|
||||
"/System/Library/PrivateFrameworks/Lexicon.framework/Versions/A/Lexicon",
|
||||
"/System/Library/PrivateFrameworks/LinguisticData.framework/Versions/A/LinguisticData",
|
||||
"/usr/lib/libcmph.dylib",
|
||||
"/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData",
|
||||
"/System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework/Versions/A/CFOpenDirectory",
|
||||
"/System/Library/PrivateFrameworks/APFS.framework/Versions/A/APFS",
|
||||
"/usr/lib/libutil.dylib",
|
||||
"/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement",
|
||||
"/System/Library/PrivateFrameworks/BackgroundTaskManagement.framework/Versions/A/BackgroundTaskManagement",
|
||||
"/usr/lib/libxslt.1.dylib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vImage.framework/Versions/A/vImage",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/vecLib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvMisc.dylib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvDSP.dylib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBNNS.dylib",
|
||||
"/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparse.dylib",
|
||||
"/System/Library/PrivateFrameworks/GPUWrangler.framework/Versions/A/GPUWrangler",
|
||||
"/System/Library/PrivateFrameworks/IOAccelerator.framework/Versions/A/IOAccelerator",
|
||||
"/System/Library/PrivateFrameworks/IOPresentment.framework/Versions/A/IOPresentment",
|
||||
"/System/Library/PrivateFrameworks/DSExternalDisplay.framework/Versions/A/DSExternalDisplay",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreFSCache.dylib",
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSCore.framework/Versions/A/MPSCore",
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSImage.framework/Versions/A/MPSImage",
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSNeuralNetwork.framework/Versions/A/MPSNeuralNetwork",
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSMatrix.framework/Versions/A/MPSMatrix",
|
||||
"/System/Library/Frameworks/MetalPerformanceShaders.framework/Frameworks/MPSRayIntersector.framework/Versions/A/MPSRayIntersector",
|
||||
"/System/Library/PrivateFrameworks/MetalTools.framework/Versions/A/MetalTools",
|
||||
"/System/Library/PrivateFrameworks/AggregateDictionary.framework/Versions/A/AggregateDictionary",
|
||||
"/usr/lib/libMobileGestalt.dylib",
|
||||
"/System/Library/Frameworks/CoreImage.framework/Versions/A/CoreImage",
|
||||
"/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL",
|
||||
"/System/Library/PrivateFrameworks/GraphVisualizer.framework/Versions/A/GraphVisualizer",
|
||||
"/System/Library/PrivateFrameworks/FaceCore.framework/Versions/A/FaceCore",
|
||||
"/System/Library/Frameworks/OpenCL.framework/Versions/A/OpenCL",
|
||||
"/usr/lib/libFosl_dynamic.dylib",
|
||||
"/System/Library/PrivateFrameworks/OTSVG.framework/Versions/A/OTSVG",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontParser.dylib",
|
||||
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontRegistry.dylib",
|
||||
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJPEG.dylib",
|
||||
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib",
|
||||
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libPng.dylib",
|
||||
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libGIF.dylib",
|
||||
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJP2.dylib",
|
||||
"/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libRadiance.dylib",
|
||||
"/System/Library/PrivateFrameworks/AppleJPEG.framework/Versions/A/AppleJPEG",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGFXShared.dylib",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLImage.dylib",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCVMSPluginSupport.dylib",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreVMClient.dylib",
|
||||
"/usr/lib/libcups.2.dylib",
|
||||
"/System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos",
|
||||
"/System/Library/Frameworks/GSS.framework/Versions/A/GSS",
|
||||
"/usr/lib/libresolv.9.dylib",
|
||||
"/System/Library/PrivateFrameworks/Heimdal.framework/Versions/A/Heimdal",
|
||||
"/usr/lib/libheimdal-asn1.dylib",
|
||||
"/System/Library/Frameworks/OpenDirectory.framework/Versions/A/OpenDirectory",
|
||||
"/System/Library/PrivateFrameworks/CommonAuth.framework/Versions/A/CommonAuth",
|
||||
"/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation",
|
||||
"/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio",
|
||||
"/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox",
|
||||
"/System/Library/PrivateFrameworks/AppleSauce.framework/Versions/A/AppleSauce",
|
||||
"/System/Library/PrivateFrameworks/AssertionServices.framework/Versions/A/AssertionServices",
|
||||
"/System/Library/PrivateFrameworks/BaseBoard.framework/Versions/A/BaseBoard"
|
||||
]
|
||||
}
|
@ -268,7 +268,6 @@ define([
|
||||
this.install(this.plugins.ConditionWidget());
|
||||
this.install(this.plugins.URLTimeSettingsSynchronizer());
|
||||
this.install(this.plugins.NotificationIndicator());
|
||||
this.install(this.plugins.NewFolderAction());
|
||||
}
|
||||
|
||||
MCT.prototype = Object.create(EventEmitter.prototype);
|
||||
|
@ -35,8 +35,7 @@ define([
|
||||
'./services/LegacyObjectAPIInterceptor',
|
||||
'./views/installLegacyViews',
|
||||
'./policies/LegacyCompositionPolicyAdapter',
|
||||
'./actions/LegacyActionAdapter',
|
||||
'./services/LegacyPersistenceAdapter'
|
||||
'./actions/LegacyActionAdapter'
|
||||
], function (
|
||||
ActionDialogDecorator,
|
||||
AdapterCapability,
|
||||
@ -52,8 +51,7 @@ define([
|
||||
LegacyObjectAPIInterceptor,
|
||||
installLegacyViews,
|
||||
legacyCompositionPolicyAdapter,
|
||||
LegacyActionAdapter,
|
||||
LegacyPersistenceAdapter
|
||||
LegacyActionAdapter
|
||||
) {
|
||||
return {
|
||||
name: 'src/adapter',
|
||||
@ -116,13 +114,6 @@ define([
|
||||
"instantiate",
|
||||
"topic"
|
||||
]
|
||||
},
|
||||
{
|
||||
provides: "persistenceService",
|
||||
type: "provider",
|
||||
priority: "fallback",
|
||||
implementation: LegacyPersistenceAdapter.default,
|
||||
depends: ["openmct"]
|
||||
}
|
||||
],
|
||||
policies: [
|
||||
|
@ -25,11 +25,10 @@ define([
|
||||
], function (
|
||||
utils
|
||||
) {
|
||||
function ObjectServiceProvider(eventEmitter, objectService, instantiate, topic, $injector) {
|
||||
function ObjectServiceProvider(eventEmitter, objectService, instantiate, topic) {
|
||||
this.eventEmitter = eventEmitter;
|
||||
this.objectService = objectService;
|
||||
this.instantiate = instantiate;
|
||||
this.$injector = $injector;
|
||||
|
||||
this.generalTopic = topic('mutation');
|
||||
this.bridgeEventBuses();
|
||||
@ -69,53 +68,16 @@ define([
|
||||
removeGeneralTopicListener = this.generalTopic.listen(handleLegacyMutation);
|
||||
};
|
||||
|
||||
ObjectServiceProvider.prototype.create = async function (object) {
|
||||
let model = utils.toOldFormat(object);
|
||||
ObjectServiceProvider.prototype.save = function (object) {
|
||||
var key = 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();
|
||||
return object.getCapability('persistence')
|
||||
.persist()
|
||||
.then(function () {
|
||||
return utils.toNewFormat(object, key);
|
||||
});
|
||||
};
|
||||
|
||||
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!
|
||||
};
|
||||
@ -156,8 +118,7 @@ define([
|
||||
eventEmitter,
|
||||
objectService,
|
||||
instantiate,
|
||||
topic,
|
||||
openmct.$injector
|
||||
topic
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
import objectUtils from 'objectUtils';
|
||||
|
||||
function LegacyPersistenceProvider(openmct) {
|
||||
this.openmct = openmct;
|
||||
}
|
||||
|
||||
LegacyPersistenceProvider.prototype.listObjects = function () {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
LegacyPersistenceProvider.prototype.listSpaces = function () {
|
||||
return Promise.resolve(Object.keys(this.openmct.objects.providers));
|
||||
}
|
||||
|
||||
LegacyPersistenceProvider.prototype.updateObject = function (legacyDomainObject) {
|
||||
return this.openmct.objects.save(legacyDomainObject.useCapability('adapter'));
|
||||
}
|
||||
|
||||
LegacyPersistenceProvider.prototype.updateObject = function (legacyDomainObject) {
|
||||
return this.openmct.objects.save(legacyDomainObject.useCapability('adapter'));
|
||||
}
|
||||
|
||||
LegacyPersistenceProvider.prototype.readObject = function (keystring) {
|
||||
let identifier = objectUtils.parseKeyString(keystring);
|
||||
return this.openmct.legacyObject(this.openmct.objects.get(identifier));
|
||||
}
|
||||
|
||||
export default LegacyPersistenceProvider;
|
@ -101,25 +101,14 @@ define([
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create the given domain object in the corresponding persistence store
|
||||
* Save this domain object in its current state.
|
||||
*
|
||||
* @method create
|
||||
* @method save
|
||||
* @memberof module:openmct.ObjectProvider#
|
||||
* @param {module:openmct.DomainObject} domainObject the domain object to
|
||||
* create
|
||||
* save
|
||||
* @returns {Promise} a promise which will resolve when the domain object
|
||||
* 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
|
||||
* has been saved, or be rejected if it cannot be saved
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -172,41 +161,8 @@ define([
|
||||
throw new Error('Delete 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;
|
||||
ObjectAPI.prototype.save = function () {
|
||||
throw new Error('Save not implemented');
|
||||
};
|
||||
|
||||
/**
|
||||
@ -320,9 +276,5 @@ define([
|
||||
* @memberof module:openmct
|
||||
*/
|
||||
|
||||
function hasAlreadyBeenPersisted(domainObject) {
|
||||
return domainObject.persisted !== undefined &&
|
||||
domainObject.persisted === domainObject.modified;
|
||||
}
|
||||
return ObjectAPI;
|
||||
});
|
||||
|
@ -1,60 +0,0 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
@ -334,8 +334,8 @@ define([
|
||||
});
|
||||
if (subscriber.callbacks.length === 0) {
|
||||
subscriber.unsubscribe();
|
||||
delete this.subscribeCache[keyString];
|
||||
}
|
||||
delete this.subscribeCache[keyString];
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
|
@ -156,29 +156,6 @@ 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);
|
||||
|
@ -20,13 +20,20 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
export default function ladTableCompositionPolicy(openmct) {
|
||||
return function (parent, child) {
|
||||
export default class LADTableCompositionPolicy {
|
||||
|
||||
constructor(openmct) {
|
||||
this.openmct = openmct;
|
||||
return this.allow.bind(this);
|
||||
}
|
||||
|
||||
allow(parent, child) {
|
||||
if(parent.type === 'LadTable') {
|
||||
return openmct.telemetry.isTelemetryObject(child);
|
||||
return this.openmct.telemetry.isTelemetryObject(child);
|
||||
} else if(parent.type === 'LadTableSet') {
|
||||
return child.type === 'LadTable';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
formattedTimestamp() {
|
||||
return this.timestamp !== undefined ? this.getFormattedTimestamp(this.timestamp) : '---';
|
||||
return this.timestamp !== undefined ? this.formats[this.timestampKey].format(this.timestamp) : '---';
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -110,11 +110,11 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
updateValues(datum) {
|
||||
let newTimestamp = this.getParsedTimestamp(datum),
|
||||
let newTimestamp = this.formats[this.timestampKey].parse(datum),
|
||||
limit;
|
||||
|
||||
if(this.shouldUpdate(newTimestamp)) {
|
||||
this.timestamp = newTimestamp;
|
||||
this.timestamp = this.formats[this.timestampKey].parse(datum);
|
||||
this.value = this.formats[this.valueKey].format(datum);
|
||||
limit = this.limitEvaluator.evaluate(datum, this.valueMetadata);
|
||||
if (limit) {
|
||||
@ -125,12 +125,9 @@ export default {
|
||||
}
|
||||
},
|
||||
shouldUpdate(newTimestamp) {
|
||||
let newTimestampInBounds = this.inBounds(newTimestamp),
|
||||
noExistingTimestamp = this.timestamp === undefined,
|
||||
newTimestampIsLatest = newTimestamp > this.timestamp;
|
||||
|
||||
return newTimestampInBounds &&
|
||||
(noExistingTimestamp || newTimestampIsLatest);
|
||||
return (this.timestamp === undefined) ||
|
||||
(this.inBounds(newTimestamp) &&
|
||||
newTimestamp > this.timestamp);
|
||||
},
|
||||
requestHistory() {
|
||||
this.openmct
|
||||
@ -149,7 +146,6 @@ export default {
|
||||
updateBounds(bounds, isTick) {
|
||||
this.bounds = bounds;
|
||||
if(!isTick) {
|
||||
this.resetValues();
|
||||
this.requestHistory();
|
||||
}
|
||||
},
|
||||
@ -157,34 +153,13 @@ export default {
|
||||
return timestamp >= this.bounds.start && timestamp <= this.bounds.end;
|
||||
},
|
||||
updateTimeSystem(timeSystem) {
|
||||
this.resetValues();
|
||||
this.value = '---';
|
||||
this.timestamp = '---';
|
||||
this.valueClass = '';
|
||||
this.timestampKey = timeSystem.key;
|
||||
},
|
||||
showContextMenu(event) {
|
||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
|
||||
},
|
||||
resetValues() {
|
||||
this.value = '---';
|
||||
this.timestamp = undefined;
|
||||
this.valueClass = '';
|
||||
},
|
||||
getParsedTimestamp(timestamp) {
|
||||
if(this.timeSystemFormat()) {
|
||||
return this.formats[this.timestampKey].parse(timestamp);
|
||||
}
|
||||
},
|
||||
getFormattedTimestamp(timestamp) {
|
||||
if(this.timeSystemFormat()) {
|
||||
return this.formats[this.timestampKey].format(timestamp);
|
||||
}
|
||||
},
|
||||
timeSystemFormat() {
|
||||
if(this.formats[this.timestampKey]) {
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`No formatter for ${this.timestampKey} time system for ${this.domainObject.name}.`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
*****************************************************************************/
|
||||
import LADTableViewProvider from './LADTableViewProvider';
|
||||
import LADTableSetViewProvider from './LADTableSetViewProvider';
|
||||
import ladTableCompositionPolicy from './LADTableCompositionPolicy';
|
||||
import LADTableCompositionPolicy from './LADTableCompositionPolicy';
|
||||
|
||||
export default function plugin() {
|
||||
return function install(openmct) {
|
||||
@ -49,6 +49,6 @@ export default function plugin() {
|
||||
}
|
||||
});
|
||||
|
||||
openmct.composition.addPolicy(ladTableCompositionPolicy(openmct));
|
||||
openmct.composition.addPolicy(new LADTableCompositionPolicy(openmct));
|
||||
};
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
setAllSearchParams
|
||||
} from 'utils/openmctLocation';
|
||||
|
||||
const TIME_EVENTS = ['timeSystem', 'clock', 'clockOffsets'];
|
||||
const TIME_EVENTS = ['bounds', 'timeSystem', 'clock', 'clockOffsets'];
|
||||
const SEARCH_MODE = 'tc.mode';
|
||||
const SEARCH_TIME_SYSTEM = 'tc.timeSystem';
|
||||
const SEARCH_START_BOUND = 'tc.startBound';
|
||||
@ -42,7 +42,6 @@ export default class URLTimeSettingsSynchronizer {
|
||||
this.destroy = this.destroy.bind(this);
|
||||
this.updateTimeSettings = this.updateTimeSettings.bind(this);
|
||||
this.setUrlFromTimeApi = this.setUrlFromTimeApi.bind(this);
|
||||
this.updateBounds = this.updateBounds.bind(this);
|
||||
|
||||
openmct.on('start', this.initialize);
|
||||
openmct.on('destroy', this.destroy);
|
||||
@ -55,7 +54,7 @@ export default class URLTimeSettingsSynchronizer {
|
||||
TIME_EVENTS.forEach(event => {
|
||||
this.openmct.time.on(event, this.setUrlFromTimeApi);
|
||||
});
|
||||
this.openmct.time.on('bounds', this.updateBounds);
|
||||
|
||||
}
|
||||
|
||||
destroy() {
|
||||
@ -66,7 +65,6 @@ export default class URLTimeSettingsSynchronizer {
|
||||
TIME_EVENTS.forEach(event => {
|
||||
this.openmct.time.off(event, this.setUrlFromTimeApi);
|
||||
});
|
||||
this.openmct.time.on('bounds', this.updateBounds);
|
||||
}
|
||||
|
||||
updateTimeSettings() {
|
||||
@ -74,6 +72,7 @@ export default class URLTimeSettingsSynchronizer {
|
||||
if (!this.isUrlUpdateInProgress) {
|
||||
let timeParameters = this.parseParametersFromUrl();
|
||||
|
||||
|
||||
if (this.areTimeParametersValid(timeParameters)) {
|
||||
this.setTimeApiFromUrl(timeParameters);
|
||||
} else {
|
||||
@ -139,12 +138,6 @@ export default class URLTimeSettingsSynchronizer {
|
||||
}
|
||||
}
|
||||
|
||||
updateBounds(bounds, isTick) {
|
||||
if (!isTick) {
|
||||
this.setUrlFromTimeApi();
|
||||
}
|
||||
}
|
||||
|
||||
setUrlFromTimeApi() {
|
||||
let searchParams = getAllSearchParams();
|
||||
let clock = this.openmct.time.clock();
|
||||
|
@ -29,13 +29,10 @@ define([
|
||||
ClearDataAction,
|
||||
Vue
|
||||
) {
|
||||
return function plugin(appliesToObjects, options = {indicator: true}) {
|
||||
let installIndicator = options.indicator;
|
||||
|
||||
return function plugin(appliesToObjects) {
|
||||
appliesToObjects = appliesToObjects || [];
|
||||
|
||||
return function install(openmct) {
|
||||
if (installIndicator) {
|
||||
let component = new Vue ({
|
||||
provide: {
|
||||
openmct
|
||||
@ -50,7 +47,6 @@ define([
|
||||
};
|
||||
|
||||
openmct.indicators.add(indicator);
|
||||
}
|
||||
|
||||
openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
|
||||
};
|
||||
|
@ -150,7 +150,6 @@ export default class Condition extends EventEmitter {
|
||||
criterion = new TelemetryCriterion(criterionConfigurationWithId, this.openmct);
|
||||
}
|
||||
criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||
criterion.on('telemetryIsStale', (obj) => this.handleStaleCriterion(obj));
|
||||
if (!this.criteria) {
|
||||
this.criteria = [];
|
||||
}
|
||||
@ -179,12 +178,10 @@ export default class Condition extends EventEmitter {
|
||||
const newCriterionConfiguration = this.generateCriterion(criterionConfiguration);
|
||||
let newCriterion = new TelemetryCriterion(newCriterionConfiguration, this.openmct);
|
||||
newCriterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||
newCriterion.on('telemetryIsStale', (obj) => this.handleStaleCriterion(obj));
|
||||
|
||||
let criterion = found.item;
|
||||
criterion.unsubscribe();
|
||||
criterion.off('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||
criterion.off('telemetryIsStale', (obj) => this.handleStaleCriterion(obj));
|
||||
this.criteria.splice(found.index, 1, newCriterion);
|
||||
this.updateDescription();
|
||||
}
|
||||
@ -197,9 +194,6 @@ export default class Condition extends EventEmitter {
|
||||
criterion.off('criterionUpdated', (obj) => {
|
||||
this.handleCriterionUpdated(obj);
|
||||
});
|
||||
criterion.off('telemetryIsStale', (obj) => {
|
||||
this.handleStaleCriterion(obj);
|
||||
});
|
||||
criterion.destroy();
|
||||
this.criteria.splice(found.index, 1);
|
||||
this.updateDescription();
|
||||
@ -217,18 +211,6 @@ export default class Condition extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
handleStaleCriterion(updatedCriterion) {
|
||||
this.result = evaluateResults(this.criteria.map(criterion => criterion.result), this.trigger);
|
||||
let latestTimestamp = {};
|
||||
latestTimestamp = getLatestTimestamp(
|
||||
latestTimestamp,
|
||||
updatedCriterion.data,
|
||||
this.timeSystems,
|
||||
this.openmct.time.timeSystem()
|
||||
);
|
||||
this.conditionManager.updateCurrentCondition(latestTimestamp);
|
||||
}
|
||||
|
||||
updateDescription() {
|
||||
const triggerDescription = this.getTriggerDescription();
|
||||
let description = '';
|
||||
|
@ -103,8 +103,6 @@ export default class ConditionManager extends EventEmitter {
|
||||
criterion.operation = '';
|
||||
conditionChanged = true;
|
||||
}
|
||||
} else {
|
||||
conditionChanged = true;
|
||||
}
|
||||
});
|
||||
if (conditionChanged) {
|
||||
@ -317,10 +315,6 @@ export default class ConditionManager extends EventEmitter {
|
||||
condition.getResult(normalizedDatum);
|
||||
});
|
||||
|
||||
this.updateCurrentCondition(timestamp);
|
||||
}
|
||||
|
||||
updateCurrentCondition(timestamp) {
|
||||
const currentCondition = this.getCurrentCondition();
|
||||
|
||||
this.emit('conditionSetResultUpdated',
|
||||
|
@ -46,7 +46,6 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
if (this.isEditing) {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
if (this.conditionSetIdentifier) {
|
||||
this.applySelectedConditionStyle();
|
||||
@ -67,7 +66,6 @@ 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)
|
||||
@ -156,8 +154,8 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
this.applyStaticStyle();
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
delete this.stopProvidingTelemetry;
|
||||
this.conditionSetIdentifier = undefined;
|
||||
}
|
||||
|
||||
|
@ -27,13 +27,13 @@
|
||||
>
|
||||
{{ condition.configuration.name }}
|
||||
</span>
|
||||
<span v-if="!condition.isDefault"
|
||||
class="c-style__condition-desc__text"
|
||||
<span class="c-style__condition-desc__text"
|
||||
v-if="!condition.isDefault"
|
||||
>
|
||||
{{ description }}
|
||||
</span>
|
||||
<span v-else
|
||||
class="c-style__condition-desc__text"
|
||||
<span class="c-style__condition-desc__text"
|
||||
v-else
|
||||
>
|
||||
Match if no other condition is matched
|
||||
</span>
|
||||
|
@ -55,7 +55,6 @@
|
||||
>
|
||||
{{ option.name }}
|
||||
</option>
|
||||
<option value="dataReceived">any data received</option>
|
||||
</select>
|
||||
</span>
|
||||
<span v-if="criterion.telemetry && criterion.metadata"
|
||||
@ -84,7 +83,6 @@
|
||||
>
|
||||
<span v-if="inputIndex < inputCount-1">and</span>
|
||||
</span>
|
||||
<span v-if="criterion.metadata === 'dataReceived'">seconds</span>
|
||||
</template>
|
||||
<span v-else>
|
||||
<span v-if="inputCount && criterion.operation"
|
||||
@ -150,11 +148,7 @@ export default {
|
||||
return (this.index !== 0 ? operator : '') + ' when';
|
||||
},
|
||||
filteredOps: function () {
|
||||
if (this.criterion.metadata === 'dataReceived') {
|
||||
return this.operations.filter(op => op.name === 'isStale');
|
||||
} else {
|
||||
return this.operations.filter(op => op.appliesTo.indexOf(this.operationFormat) !== -1);
|
||||
}
|
||||
},
|
||||
setInputType: function () {
|
||||
let type = '';
|
||||
@ -220,8 +214,6 @@ export default {
|
||||
} else {
|
||||
this.operationFormat = 'number';
|
||||
}
|
||||
} else if (this.criterion.metadata === 'dataReceived') {
|
||||
this.operationFormat = 'number';
|
||||
}
|
||||
this.updateInputVisibilityAndValues();
|
||||
},
|
||||
|
@ -197,7 +197,6 @@ export default {
|
||||
}
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
},
|
||||
initialize(conditionSetDomainObject) {
|
||||
@ -211,7 +210,6 @@ export default {
|
||||
if (this.isEditing) {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
} else {
|
||||
this.subscribeToConditionSet();
|
||||
@ -309,7 +307,6 @@ export default {
|
||||
this.persist(domainObjectStyles);
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
},
|
||||
updateDomainObjectItemStyles(newItems) {
|
||||
@ -378,7 +375,6 @@ export default {
|
||||
subscribeToConditionSet() {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
if (this.conditionSetDomainObject) {
|
||||
this.openmct.telemetry.request(this.conditionSetDomainObject)
|
||||
|
@ -37,13 +37,12 @@
|
||||
>
|
||||
<style-editor class="c-inspect-styles__editor"
|
||||
:style-item="staticStyle"
|
||||
:is-editing="allowEditing"
|
||||
:is-editing="isEditing"
|
||||
:mixed-styles="mixedStyles"
|
||||
@persist="updateStaticStyle"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
v-if="allowEditing"
|
||||
id="addConditionSet"
|
||||
class="c-button c-button--major c-toggle-styling-button labeled"
|
||||
@click="addConditionSet"
|
||||
@ -64,7 +63,7 @@
|
||||
>
|
||||
<span class="c-object-label__name">{{ conditionSetDomainObject.name }}</span>
|
||||
</a>
|
||||
<template v-if="allowEditing">
|
||||
<template v-if="isEditing">
|
||||
<button
|
||||
id="changeConditionSet"
|
||||
class="c-button labeled"
|
||||
@ -97,7 +96,7 @@
|
||||
/>
|
||||
<style-editor class="c-inspect-styles__editor"
|
||||
:style-item="conditionStyle"
|
||||
:is-editing="allowEditing"
|
||||
:is-editing="isEditing"
|
||||
@persist="updateConditionalStyle"
|
||||
/>
|
||||
</div>
|
||||
@ -138,13 +137,7 @@ export default {
|
||||
conditions: undefined,
|
||||
conditionsLoaded: false,
|
||||
navigateToPath: '',
|
||||
selectedConditionId: '',
|
||||
locked: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
allowEditing() {
|
||||
return this.isEditing && !this.locked;
|
||||
selectedConditionId: ''
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
@ -190,7 +183,6 @@ export default {
|
||||
if (this.isEditing) {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
} else {
|
||||
this.subscribeToConditionSet();
|
||||
@ -232,13 +224,7 @@ export default {
|
||||
this.selection.forEach((selectionItem) => {
|
||||
const item = selectionItem[0].context.item;
|
||||
const layoutItem = selectionItem[0].context.layoutItem;
|
||||
const layoutDomainObject = selectionItem[0].context.item;
|
||||
const isChildItem = selectionItem.length > 1;
|
||||
|
||||
if (layoutDomainObject && layoutDomainObject.locked) {
|
||||
this.locked = true;
|
||||
}
|
||||
|
||||
if (!isChildItem) {
|
||||
domainObject = item;
|
||||
itemStyle = getApplicableStylesForItem(item);
|
||||
@ -326,7 +312,6 @@ export default {
|
||||
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
|
||||
if (this.unObserveObjects) {
|
||||
@ -339,7 +324,6 @@ export default {
|
||||
subscribeToConditionSet() {
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
if (this.conditionSetDomainObject) {
|
||||
this.openmct.telemetry.request(this.conditionSetDomainObject)
|
||||
@ -497,7 +481,6 @@ export default {
|
||||
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
}
|
||||
},
|
||||
removeConditionalStyles(domainObjectStyles, itemId) {
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
import TelemetryCriterion from './TelemetryCriterion';
|
||||
import { evaluateResults } from "../utils/evaluator";
|
||||
import {getLatestTimestamp, subscribeForStaleness} from '../utils/time';
|
||||
import { getLatestTimestamp } from '../utils/time';
|
||||
import { getOperatorText } from "@/plugins/condition/utils/operations";
|
||||
|
||||
export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||
@ -41,32 +41,6 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||
initialize() {
|
||||
this.telemetryObjects = { ...this.telemetryDomainObjectDefinition.telemetryObjects };
|
||||
this.telemetryDataCache = {};
|
||||
if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) {
|
||||
this.subscribeForStaleData(this.telemetryObjects || {});
|
||||
}
|
||||
}
|
||||
|
||||
subscribeForStaleData(telemetryObjects) {
|
||||
|
||||
if (!this.stalenessSubscription) {
|
||||
this.stalenessSubscription = {};
|
||||
}
|
||||
Object.values(telemetryObjects).forEach((telemetryObject) => {
|
||||
const id = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
if (!this.stalenessSubscription[id]) {
|
||||
this.stalenessSubscription[id] = subscribeForStaleness((data) => {
|
||||
this.handleStaleTelemetry(id, data);
|
||||
}, this.input[0]*1000);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
handleStaleTelemetry(id, data) {
|
||||
if (this.telemetryDataCache) {
|
||||
this.telemetryDataCache[id] = true;
|
||||
this.result = evaluateResults(Object.values(this.telemetryDataCache), this.telemetry);
|
||||
}
|
||||
this.emitEvent('telemetryIsStale', data);
|
||||
}
|
||||
|
||||
isValid() {
|
||||
@ -76,9 +50,6 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||
updateTelemetryObjects(telemetryObjects) {
|
||||
this.telemetryObjects = { ...telemetryObjects };
|
||||
this.removeTelemetryDataCache();
|
||||
if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) {
|
||||
this.subscribeForStaleData(this.telemetryObjects || {});
|
||||
}
|
||||
}
|
||||
|
||||
removeTelemetryDataCache() {
|
||||
@ -92,7 +63,6 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||
});
|
||||
telemetryCacheIds.forEach(id => {
|
||||
delete (this.telemetryDataCache[id]);
|
||||
delete (this.stalenessSubscription[id]);
|
||||
});
|
||||
}
|
||||
|
||||
@ -126,15 +96,8 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||
const validatedData = this.isValid() ? data : {};
|
||||
|
||||
if (validatedData) {
|
||||
if (this.isStalenessCheck()) {
|
||||
if (this.stalenessSubscription[validatedData.id]) {
|
||||
this.stalenessSubscription[validatedData.id].update(validatedData);
|
||||
}
|
||||
this.telemetryDataCache[validatedData.id] = false;
|
||||
} else {
|
||||
this.telemetryDataCache[validatedData.id] = this.computeResult(validatedData);
|
||||
}
|
||||
}
|
||||
|
||||
Object.values(telemetryObjects).forEach(telemetryObject => {
|
||||
const id = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
@ -199,7 +162,7 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||
|
||||
getDescription() {
|
||||
const telemetryDescription = this.telemetry === 'all' ? 'all telemetry' : 'any telemetry';
|
||||
let metadataValue = (this.metadata === 'dataReceived' ? '' : this.metadata);
|
||||
let metadataValue = this.metadata;
|
||||
let inputValue = this.input;
|
||||
if (this.metadata) {
|
||||
const telemetryObjects = Object.values(this.telemetryObjects);
|
||||
@ -219,9 +182,5 @@ export default class AllTelemetryCriterion extends TelemetryCriterion {
|
||||
destroy() {
|
||||
delete this.telemetryObjects;
|
||||
delete this.telemetryDataCache;
|
||||
if (this.stalenessSubscription) {
|
||||
Object.values(this.stalenessSubscription).forEach((subscription) => subscription.clear);
|
||||
delete this.stalenessSubscription;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
import EventEmitter from 'EventEmitter';
|
||||
import { OPERATIONS, getOperatorText } from '../utils/operations';
|
||||
import { subscribeForStaleness } from "../utils/time";
|
||||
|
||||
export default class TelemetryCriterion extends EventEmitter {
|
||||
|
||||
@ -44,7 +43,6 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
this.input = telemetryDomainObjectDefinition.input;
|
||||
this.metadata = telemetryDomainObjectDefinition.metadata;
|
||||
this.result = undefined;
|
||||
this.stalenessSubscription = undefined;
|
||||
|
||||
this.initialize();
|
||||
this.emitEvent('criterionUpdated', this);
|
||||
@ -53,40 +51,14 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
initialize() {
|
||||
this.telemetryObjectIdAsString = this.openmct.objects.makeKeyString(this.telemetryDomainObjectDefinition.telemetry);
|
||||
this.updateTelemetryObjects(this.telemetryDomainObjectDefinition.telemetryObjects);
|
||||
if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) {
|
||||
this.subscribeForStaleData()
|
||||
}
|
||||
}
|
||||
|
||||
subscribeForStaleData() {
|
||||
if (this.stalenessSubscription) {
|
||||
this.stalenessSubscription.clear();
|
||||
}
|
||||
this.stalenessSubscription = subscribeForStaleness(this.handleStaleTelemetry.bind(this), this.input[0]*1000);
|
||||
}
|
||||
|
||||
handleStaleTelemetry(data) {
|
||||
this.result = true;
|
||||
this.emitEvent('telemetryIsStale', data);
|
||||
}
|
||||
|
||||
isValid() {
|
||||
return this.telemetryObject && this.metadata && this.operation;
|
||||
}
|
||||
|
||||
isStalenessCheck() {
|
||||
return this.metadata && this.metadata === 'dataReceived';
|
||||
}
|
||||
|
||||
isValidInput() {
|
||||
return this.input instanceof Array && this.input.length;
|
||||
}
|
||||
|
||||
updateTelemetryObjects(telemetryObjects) {
|
||||
this.telemetryObject = telemetryObjects[this.telemetryObjectIdAsString];
|
||||
if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) {
|
||||
this.subscribeForStaleData()
|
||||
}
|
||||
}
|
||||
|
||||
createNormalizedDatum(telemetryDatum, endpoint) {
|
||||
@ -119,15 +91,8 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
|
||||
getResult(data) {
|
||||
const validatedData = this.isValid() ? data : {};
|
||||
if (this.isStalenessCheck()) {
|
||||
if (this.stalenessSubscription) {
|
||||
this.stalenessSubscription.update(validatedData);
|
||||
}
|
||||
this.result = false;
|
||||
} else {
|
||||
this.result = this.computeResult(validatedData);
|
||||
}
|
||||
}
|
||||
|
||||
requestLAD() {
|
||||
const options = {
|
||||
@ -171,7 +136,7 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
let comparator = this.findOperation(this.operation);
|
||||
let params = [];
|
||||
params.push(data[this.metadata]);
|
||||
if (this.isValidInput()) {
|
||||
if (this.input instanceof Array && this.input.length) {
|
||||
this.input.forEach(input => params.push(input));
|
||||
}
|
||||
if (typeof comparator === 'function') {
|
||||
@ -226,7 +191,7 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
description = `Unknown ${this.metadata} ${getOperatorText(this.operation, this.input)}`;
|
||||
} else {
|
||||
const metadataObject = this.getMetaDataObject(this.telemetryObject, this.metadata);
|
||||
const metadataValue = this.getMetadataValueFromMetaData(metadataObject) || (this.metadata === 'dataReceived' ? '' : this.metadata);
|
||||
const metadataValue = this.getMetadataValueFromMetaData(metadataObject) || this.metadata;
|
||||
const inputValue = this.getInputValueFromMetaData(metadataObject, this.input) || this.input;
|
||||
description = `${this.telemetryObject.name} ${metadataValue} ${getOperatorText(this.operation, inputValue)}`;
|
||||
}
|
||||
@ -237,8 +202,5 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
destroy() {
|
||||
delete this.telemetryObject;
|
||||
delete this.telemetryObjectIdAsString;
|
||||
if (this.stalenessSubscription) {
|
||||
delete this.stalenessSubscription;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,50 +25,19 @@ import ConditionPlugin from "./plugin";
|
||||
import StylesView from "./components/inspector/StylesView.vue";
|
||||
import Vue from 'vue';
|
||||
import {getApplicableStylesForItem} from "./utils/styleUtils";
|
||||
import ConditionManager from "@/plugins/condition/ConditionManager";
|
||||
|
||||
describe('the plugin', function () {
|
||||
let conditionSetDefinition;
|
||||
let mockConditionSetDomainObject;
|
||||
let mockListener;
|
||||
let element;
|
||||
let child;
|
||||
let openmct;
|
||||
let testTelemetryObject;
|
||||
|
||||
beforeAll(() => {
|
||||
resetApplicationState(openmct);
|
||||
});
|
||||
|
||||
beforeEach((done) => {
|
||||
testTelemetryObject = {
|
||||
identifier:{ namespace: "", key: "test-object"},
|
||||
type: "test-object",
|
||||
name: "Test Object",
|
||||
telemetry: {
|
||||
valueMetadatas: [{
|
||||
key: "some-key",
|
||||
name: "Some attribute",
|
||||
hints: {
|
||||
range: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "utc",
|
||||
name: "Time",
|
||||
format: "utc",
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
}, {
|
||||
key: "testSource",
|
||||
source: "value",
|
||||
name: "Test",
|
||||
format: "string"
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
openmct = createOpenMct();
|
||||
openmct.install(new ConditionPlugin());
|
||||
|
||||
@ -86,8 +55,6 @@ describe('the plugin', function () {
|
||||
type: 'conditionSet'
|
||||
};
|
||||
|
||||
mockListener = jasmine.createSpy('mockListener');
|
||||
|
||||
conditionSetDefinition.initialize(mockConditionSetDomainObject);
|
||||
|
||||
openmct.on('start', done);
|
||||
@ -389,113 +356,4 @@ describe('the plugin', function () {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('the condition check for staleness', () => {
|
||||
let conditionSetDomainObject;
|
||||
|
||||
beforeEach(()=>{
|
||||
conditionSetDomainObject = {
|
||||
"configuration":{
|
||||
"conditionTestData":[
|
||||
{
|
||||
"telemetry":"",
|
||||
"metadata":"",
|
||||
"input":""
|
||||
}
|
||||
],
|
||||
"conditionCollection":[
|
||||
{
|
||||
"id":"39584410-cbf9-499e-96dc-76f27e69885d",
|
||||
"configuration":{
|
||||
"name":"Unnamed Condition",
|
||||
"output":"Any stale telemetry",
|
||||
"trigger":"all",
|
||||
"criteria":[
|
||||
{
|
||||
"id":"35400132-63b0-425c-ac30-8197df7d5862",
|
||||
"telemetry":"any",
|
||||
"operation":"isStale",
|
||||
"input":[
|
||||
"1"
|
||||
],
|
||||
"metadata":"dataReceived"
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary":"Match if all criteria are met: Any telemetry is stale after 5 seconds"
|
||||
},
|
||||
{
|
||||
"isDefault":true,
|
||||
"id":"2532d90a-e0d6-4935-b546-3123522da2de",
|
||||
"configuration":{
|
||||
"name":"Default",
|
||||
"output":"Default",
|
||||
"trigger":"all",
|
||||
"criteria":[
|
||||
]
|
||||
},
|
||||
"summary":""
|
||||
}
|
||||
]
|
||||
},
|
||||
"composition":[
|
||||
{
|
||||
"namespace":"",
|
||||
"key":"test-object"
|
||||
}
|
||||
],
|
||||
"telemetry":{
|
||||
},
|
||||
"name":"Condition Set",
|
||||
"type":"conditionSet",
|
||||
"identifier":{
|
||||
"namespace":"",
|
||||
"key":"cf4456a9-296a-4e6b-b182-62ed29cd15b9"
|
||||
}
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
it('should evaluate as stale when telemetry is not received in the allotted time', (done) => {
|
||||
|
||||
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
|
||||
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
||||
conditionMgr.telemetryObjects = {
|
||||
"test-object": testTelemetryObject
|
||||
};
|
||||
conditionMgr.updateConditionTelemetryObjects();
|
||||
setTimeout(() => {
|
||||
expect(mockListener).toHaveBeenCalledWith({
|
||||
output: 'Any stale telemetry',
|
||||
id: { namespace: '', key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9' },
|
||||
conditionId: '39584410-cbf9-499e-96dc-76f27e69885d',
|
||||
utc: undefined
|
||||
});
|
||||
done();
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
it('should not evaluate as stale when telemetry is received in the allotted time', (done) => {
|
||||
const date = Date.now();
|
||||
conditionSetDomainObject.configuration.conditionCollection[0].configuration.criteria[0].input = ["2"];
|
||||
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
|
||||
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
||||
conditionMgr.telemetryObjects = {
|
||||
"test-object": testTelemetryObject
|
||||
};
|
||||
conditionMgr.updateConditionTelemetryObjects();
|
||||
conditionMgr.telemetryReceived(testTelemetryObject, {
|
||||
utc: date
|
||||
});
|
||||
setTimeout(() => {
|
||||
expect(mockListener).toHaveBeenCalledWith({
|
||||
output: 'Default',
|
||||
id: { namespace: '', key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9' },
|
||||
conditionId: '2532d90a-e0d6-4935-b546-3123522da2de',
|
||||
utc: undefined
|
||||
});
|
||||
done();
|
||||
}, 1500);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -283,18 +283,6 @@ export const OPERATIONS = [
|
||||
getDescription: function (values) {
|
||||
return ' is not one of ' + values[0];
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'isStale',
|
||||
operation: function () {
|
||||
return false;
|
||||
},
|
||||
text: 'is older than',
|
||||
appliesTo: ["number"],
|
||||
inputCount: 1,
|
||||
getDescription: function (values) {
|
||||
return ` is older than ${values[0] || ''} seconds`;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -50,26 +50,3 @@ function updateLatestTimeStamp(timestamp, timeSystems) {
|
||||
|
||||
return latest;
|
||||
}
|
||||
|
||||
export const subscribeForStaleness = (callback, timeout) => {
|
||||
let stalenessTimer = setTimeout(() => {
|
||||
clearTimeout(stalenessTimer);
|
||||
callback();
|
||||
}, timeout);
|
||||
return {
|
||||
update: (data) => {
|
||||
if (stalenessTimer) {
|
||||
clearTimeout(stalenessTimer);
|
||||
}
|
||||
stalenessTimer = setTimeout(() => {
|
||||
clearTimeout(stalenessTimer);
|
||||
callback(data);
|
||||
}, timeout);
|
||||
},
|
||||
clear: () => {
|
||||
if (stalenessTimer) {
|
||||
clearTimeout(stalenessTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,64 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import { subscribeForStaleness } from "./time";
|
||||
|
||||
describe('time related utils', () => {
|
||||
let subscription;
|
||||
let mockListener;
|
||||
|
||||
beforeEach(() => {
|
||||
mockListener = jasmine.createSpy('listener');
|
||||
subscription = subscribeForStaleness(mockListener, 100);
|
||||
});
|
||||
|
||||
describe('subscribe for staleness', () => {
|
||||
it('should call listeners when stale', (done) => {
|
||||
setTimeout(() => {
|
||||
expect(mockListener).toHaveBeenCalled();
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
it('should update the subscription', (done) => {
|
||||
function updated() {
|
||||
setTimeout(() => {
|
||||
expect(mockListener).not.toHaveBeenCalled();
|
||||
done();
|
||||
}, 50);
|
||||
}
|
||||
setTimeout(() => {
|
||||
subscription.update();
|
||||
updated();
|
||||
}, 50);
|
||||
});
|
||||
|
||||
it('should clear the subscription', (done) => {
|
||||
subscription.clear();
|
||||
|
||||
setTimeout(() => {
|
||||
expect(mockListener).not.toHaveBeenCalled();
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -73,7 +73,7 @@ define(['lodash'], function (_) {
|
||||
]
|
||||
}
|
||||
},
|
||||
VIEW_TYPES = {
|
||||
viewTypes = {
|
||||
'telemetry-view': {
|
||||
value: 'telemetry-view',
|
||||
name: 'Alphanumeric',
|
||||
@ -95,34 +95,28 @@ define(['lodash'], function (_) {
|
||||
class: 'icon-tabular-realtime'
|
||||
}
|
||||
},
|
||||
APPLICABLE_VIEWS = {
|
||||
applicableViews = {
|
||||
'telemetry-view': [
|
||||
VIEW_TYPES['telemetry.plot.overlay'],
|
||||
VIEW_TYPES['telemetry.plot.stacked'],
|
||||
VIEW_TYPES.table
|
||||
viewTypes['telemetry.plot.overlay'],
|
||||
viewTypes.table
|
||||
],
|
||||
'telemetry.plot.overlay': [
|
||||
VIEW_TYPES['telemetry.plot.stacked'],
|
||||
VIEW_TYPES.table,
|
||||
VIEW_TYPES['telemetry-view']
|
||||
],
|
||||
'telemetry.plot.stacked': [
|
||||
VIEW_TYPES['telemetry.plot.overlay'],
|
||||
VIEW_TYPES.table,
|
||||
VIEW_TYPES['telemetry-view']
|
||||
viewTypes['telemetry.plot.stacked'],
|
||||
viewTypes.table,
|
||||
viewTypes['telemetry-view']
|
||||
],
|
||||
'table': [
|
||||
VIEW_TYPES['telemetry.plot.overlay'],
|
||||
VIEW_TYPES['telemetry.plot.stacked'],
|
||||
VIEW_TYPES['telemetry-view']
|
||||
viewTypes['telemetry.plot.overlay'],
|
||||
viewTypes['telemetry.plot.stacked'],
|
||||
viewTypes['telemetry-view']
|
||||
],
|
||||
'telemetry-view-multi': [
|
||||
VIEW_TYPES['telemetry.plot.overlay'],
|
||||
VIEW_TYPES['telemetry.plot.stacked'],
|
||||
VIEW_TYPES.table
|
||||
viewTypes['telemetry.plot.overlay'],
|
||||
viewTypes['telemetry.plot.stacked'],
|
||||
viewTypes.table
|
||||
],
|
||||
'telemetry.plot.overlay-multi': [
|
||||
VIEW_TYPES['telemetry.plot.stacked']
|
||||
viewTypes['telemetry.plot.stacked']
|
||||
]
|
||||
};
|
||||
|
||||
@ -516,7 +510,7 @@ define(['lodash'], function (_) {
|
||||
selectedItemType = 'telemetry-view';
|
||||
}
|
||||
|
||||
let viewOptions = APPLICABLE_VIEWS[selectedItemType];
|
||||
let viewOptions = applicableViews[selectedItemType];
|
||||
|
||||
if (viewOptions) {
|
||||
return {
|
||||
@ -539,7 +533,7 @@ define(['lodash'], function (_) {
|
||||
domainObject: selectedParent,
|
||||
icon: "icon-object",
|
||||
title: "Merge into a telemetry table or plot",
|
||||
options: APPLICABLE_VIEWS['telemetry-view-multi'],
|
||||
options: applicableViews['telemetry-view-multi'],
|
||||
method: function (option) {
|
||||
displayLayoutContext.mergeMultipleTelemetryViews(selection, option.value);
|
||||
}
|
||||
@ -552,7 +546,7 @@ define(['lodash'], function (_) {
|
||||
domainObject: selectedParent,
|
||||
icon: "icon-object",
|
||||
title: "Merge into a stacked plot",
|
||||
options: APPLICABLE_VIEWS['telemetry.plot.overlay-multi'],
|
||||
options: applicableViews['telemetry.plot.overlay-multi'],
|
||||
method: function (option) {
|
||||
displayLayoutContext.mergeMultipleOverlayPlots(selection, option.value);
|
||||
}
|
||||
@ -596,7 +590,7 @@ define(['lodash'], function (_) {
|
||||
let selectedParent = selectionPath[1].context.item;
|
||||
let layoutItem = selectionPath[0].context.layoutItem;
|
||||
|
||||
if (!layoutItem || selectedParent.locked) {
|
||||
if (!layoutItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@
|
||||
<layout-frame
|
||||
:item="item"
|
||||
:grid-size="gridSize"
|
||||
:is-editing="isEditing"
|
||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||
@endMove="() => $emit('endMove')"
|
||||
>
|
||||
@ -71,11 +70,7 @@ export default {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
initSelect: Boolean,
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
initSelect: Boolean
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
|
@ -24,18 +24,14 @@
|
||||
<div
|
||||
class="l-layout"
|
||||
:class="{
|
||||
'is-multi-selected': selectedLayoutItems.length > 1,
|
||||
'allow-editing': isEditing
|
||||
'is-multi-selected': selectedLayoutItems.length > 1
|
||||
}"
|
||||
@dragover="handleDragOver"
|
||||
@click.capture="bypassSelection"
|
||||
@drop="handleDrop"
|
||||
>
|
||||
<!-- Background grid -->
|
||||
<div
|
||||
v-if="isEditing"
|
||||
class="l-layout__grid-holder c-grid"
|
||||
>
|
||||
<div class="l-layout__grid-holder c-grid">
|
||||
<div
|
||||
v-if="gridSize[0] >= 3"
|
||||
class="c-grid__x l-grid l-grid-x"
|
||||
@ -57,7 +53,6 @@
|
||||
:init-select="initSelectIndex === index"
|
||||
:index="index"
|
||||
:multi-select="selectedLayoutItems.length > 1"
|
||||
:is-editing="isEditing"
|
||||
@move="move"
|
||||
@endMove="endMove"
|
||||
@endLineResize="endLineResize"
|
||||
@ -83,30 +78,6 @@ import ImageView from './ImageView.vue'
|
||||
import EditMarquee from './EditMarquee.vue'
|
||||
import _ from 'lodash'
|
||||
|
||||
const TELEMETRY_IDENTIFIER_FUNCTIONS = {
|
||||
'table': (domainObject) => {
|
||||
return Promise.resolve(domainObject.composition);
|
||||
},
|
||||
'telemetry.plot.overlay': (domainObject) => {
|
||||
return Promise.resolve(domainObject.composition);
|
||||
},
|
||||
'telemetry.plot.stacked': (domainObject, openmct) => {
|
||||
let composition = openmct.composition.get(domainObject);
|
||||
|
||||
return composition.load().then((objects) => {
|
||||
let identifiers = [];
|
||||
objects.forEach(object => {
|
||||
if (object.type === 'telemetry.plot.overlay') {
|
||||
identifiers.push(...object.composition);
|
||||
} else {
|
||||
identifiers.push(object.identifier);
|
||||
}
|
||||
});
|
||||
return Promise.resolve(identifiers);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const ITEM_TYPE_VIEW_MAP = {
|
||||
'subobject-view': SubobjectView,
|
||||
'telemetry-view': TelemetryView,
|
||||
@ -143,10 +114,6 @@ export default {
|
||||
domainObject: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -173,7 +140,7 @@ export default {
|
||||
let selectionPath = this.selection[0];
|
||||
let singleSelectedLine = this.selection.length === 1 &&
|
||||
selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.type === 'line-view';
|
||||
return this.isEditing && selectionPath && selectionPath.length > 1 && !singleSelectedLine;
|
||||
return selectionPath && selectionPath.length > 1 && !singleSelectedLine;
|
||||
}
|
||||
},
|
||||
inject: ['openmct', 'options', 'objectPath'],
|
||||
@ -361,9 +328,6 @@ export default {
|
||||
.some(childId => this.openmct.objects.areIdsEqual(childId, identifier));
|
||||
},
|
||||
handleDragOver($event) {
|
||||
if (this.internalDomainObject.locked) {
|
||||
return;
|
||||
}
|
||||
// Get the ID of the dragged object
|
||||
let draggedKeyString = $event.dataTransfer.types
|
||||
.filter(type => type.startsWith(DRAG_OBJECT_TRANSFER_PREFIX))
|
||||
@ -457,43 +421,15 @@ export default {
|
||||
this.objectViewMap = {};
|
||||
this.layoutItems.forEach(this.trackItem);
|
||||
},
|
||||
isItemAlreadyTracked(child) {
|
||||
let found = false,
|
||||
keyString = this.openmct.objects.makeKeyString(child.identifier);
|
||||
|
||||
this.layoutItems.forEach(item => {
|
||||
if (item.identifier) {
|
||||
let itemKeyString = this.openmct.objects.makeKeyString(item.identifier);
|
||||
|
||||
if (itemKeyString === keyString) {
|
||||
found = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (found) {
|
||||
return true;
|
||||
} else if (this.isTelemetry(child)) {
|
||||
return this.telemetryViewMap[keyString] && this.objectViewMap[keyString];
|
||||
} else {
|
||||
return this.objectViewMap[keyString];
|
||||
}
|
||||
},
|
||||
addChild(child) {
|
||||
if (this.isItemAlreadyTracked(child)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let type;
|
||||
|
||||
let keyString = this.openmct.objects.makeKeyString(child.identifier);
|
||||
if (this.isTelemetry(child)) {
|
||||
type = 'telemetry-view';
|
||||
} else {
|
||||
type = 'subobject-view';
|
||||
if (!this.telemetryViewMap[keyString] && !this.objectViewMap[keyString]) {
|
||||
this.addItem('telemetry-view', child);
|
||||
}
|
||||
} else if (!this.objectViewMap[keyString]) {
|
||||
this.addItem('subobject-view', child);
|
||||
}
|
||||
|
||||
this.addItem(type, child);
|
||||
},
|
||||
removeChild(identifier) {
|
||||
let keyString = this.openmct.objects.makeKeyString(identifier);
|
||||
@ -587,17 +523,14 @@ export default {
|
||||
}
|
||||
},
|
||||
updateTelemetryFormat(item, format) {
|
||||
let index = this.layoutItems.findIndex((layoutItem) => {
|
||||
return layoutItem.id === item.id;
|
||||
});
|
||||
|
||||
let index = this.layoutItems.findIndex(item);
|
||||
item.format = format;
|
||||
this.mutate(`configuration.items[${index}]`, item);
|
||||
},
|
||||
createNewDomainObject(domainObject, composition, viewType, nameExtension, model) {
|
||||
let identifier = {
|
||||
key: uuid(),
|
||||
namespace: this.internalDomainObject.identifier.namespace
|
||||
namespace: domainObject.identifier.namespace
|
||||
},
|
||||
type = this.openmct.types.get(viewType),
|
||||
parentKeyString = this.openmct.objects.makeKeyString(this.internalDomainObject.identifier),
|
||||
@ -616,7 +549,7 @@ export default {
|
||||
object.identifier = identifier;
|
||||
object.location = parentKeyString;
|
||||
|
||||
this.openmct.objects.mutate(object, 'created', Date.now());
|
||||
this.openmct.objects.mutate(object, 'persisted', Date.now());
|
||||
|
||||
return object;
|
||||
},
|
||||
@ -738,43 +671,32 @@ export default {
|
||||
this.removeItem(selection);
|
||||
this.initSelectIndex = this.layoutItems.length - 1;
|
||||
},
|
||||
getTelemetryIdentifiers(domainObject) {
|
||||
let method = TELEMETRY_IDENTIFIER_FUNCTIONS[domainObject.type];
|
||||
|
||||
if (method) {
|
||||
return method(domainObject, this.openmct);
|
||||
} else {
|
||||
throw 'No method identified for domainObject type';
|
||||
}
|
||||
},
|
||||
switchViewType(context, viewType, selection) {
|
||||
let domainObject = context.item,
|
||||
layoutItem = context.layoutItem,
|
||||
position = [layoutItem.x, layoutItem.y],
|
||||
newDomainObject,
|
||||
layoutType = 'subobject-view';
|
||||
|
||||
if (layoutItem.type === 'telemetry-view') {
|
||||
let newDomainObject = this.createNewDomainObject(domainObject, [domainObject.identifier], viewType);
|
||||
|
||||
this.composition.add(newDomainObject);
|
||||
this.addItem(layoutType, newDomainObject, position);
|
||||
newDomainObject = this.createNewDomainObject(domainObject, [domainObject.identifier], viewType);
|
||||
} else {
|
||||
this.getTelemetryIdentifiers(domainObject).then((identifiers) => {
|
||||
if (viewType === 'telemetry-view') {
|
||||
identifiers.forEach((identifier, index) => {
|
||||
if (viewType !== 'telemetry-view') {
|
||||
newDomainObject = this.createNewDomainObject(domainObject, domainObject.composition, viewType);
|
||||
} else {
|
||||
domainObject.composition.forEach((identifier , index) => {
|
||||
let positionX = position[0] + (index * DUPLICATE_OFFSET),
|
||||
positionY = position[1] + (index * DUPLICATE_OFFSET);
|
||||
|
||||
this.convertToTelemetryView(identifier, [positionX, positionY]);
|
||||
});
|
||||
} else {
|
||||
let newDomainObject = this.createNewDomainObject(domainObject, identifiers, viewType);
|
||||
}
|
||||
}
|
||||
|
||||
if (newDomainObject) {
|
||||
this.composition.add(newDomainObject);
|
||||
this.addItem(layoutType, newDomainObject, position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.removeItem(selection);
|
||||
this.initSelectIndex = this.layoutItems.length - 1; //restore selection
|
||||
|
@ -24,7 +24,6 @@
|
||||
<layout-frame
|
||||
:item="item"
|
||||
:grid-size="gridSize"
|
||||
:is-editing="isEditing"
|
||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||
@endMove="() => $emit('endMove')"
|
||||
>
|
||||
@ -71,11 +70,7 @@ export default {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
initSelect: Boolean,
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
initSelect: Boolean
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
<div
|
||||
class="c-frame-edit__move"
|
||||
@mousedown="isEditing ? startMove([1,1], [0,0], $event) : null"
|
||||
@mousedown="startMove([1,1], [0,0], $event)"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
@ -54,10 +54,6 @@ export default {
|
||||
required: true,
|
||||
validator: (arr) => arr && arr.length === 2
|
||||
&& arr.every(el => typeof el === 'number')
|
||||
},
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -24,7 +24,6 @@
|
||||
:item="item"
|
||||
:grid-size="gridSize"
|
||||
:title="domainObject && domainObject.name"
|
||||
:is-editing="isEditing"
|
||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||
@endMove="() => $emit('endMove')"
|
||||
>
|
||||
@ -96,10 +95,6 @@ export default {
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
@ -24,23 +24,16 @@
|
||||
<layout-frame
|
||||
:item="item"
|
||||
:grid-size="gridSize"
|
||||
:is-editing="isEditing"
|
||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||
@endMove="() => $emit('endMove')"
|
||||
>
|
||||
<div
|
||||
v-if="domainObject"
|
||||
class="c-telemetry-view"
|
||||
:class="{
|
||||
styleClass,
|
||||
'is-missing': domainObject.status === 'missing'
|
||||
}"
|
||||
:class="styleClass"
|
||||
:style="styleObject"
|
||||
@contextmenu.prevent="showContextMenu"
|
||||
>
|
||||
<div class="is-missing__indicator"
|
||||
title="This item is missing"
|
||||
></div>
|
||||
<div
|
||||
v-if="showLabel"
|
||||
class="c-telemetry-view__label"
|
||||
@ -112,10 +105,6 @@ export default {
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
@ -24,7 +24,6 @@
|
||||
<layout-frame
|
||||
:item="item"
|
||||
:grid-size="gridSize"
|
||||
:is-editing="isEditing"
|
||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||
@endMove="() => $emit('endMove')"
|
||||
>
|
||||
@ -76,11 +75,7 @@ export default {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
initSelect: Boolean,
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
initSelect: Boolean
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
|
@ -45,7 +45,8 @@
|
||||
&[s-selected],
|
||||
&[s-selected-parent] {
|
||||
// Display grid and allow edit marquee to display in nested layouts when editing
|
||||
> * > * > .l-layout + .allow-editing {
|
||||
> * > * > .l-layout {
|
||||
background: $editUIGridColorBg;
|
||||
box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
|
||||
|
||||
> [class*='grid-holder'] {
|
||||
|
@ -26,15 +26,4 @@
|
||||
@include abs();
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
@include isMissing($absPos: true);
|
||||
|
||||
.is-missing__indicator {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&.is-missing {
|
||||
border: $borderMissing;
|
||||
}
|
||||
}
|
||||
|
@ -54,11 +54,10 @@ export default function DisplayLayoutPlugin(options) {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
domainObject: domainObject,
|
||||
isEditing: openmct.editor.isEditing()
|
||||
domainObject: domainObject
|
||||
};
|
||||
},
|
||||
template: '<layout ref="displayLayout" :domain-object="domainObject" :is-editing="isEditing"></layout>'
|
||||
template: '<layout ref="displayLayout" :domain-object="domainObject"></layout>'
|
||||
});
|
||||
},
|
||||
getSelectionContext() {
|
||||
@ -74,9 +73,6 @@ export default function DisplayLayoutPlugin(options) {
|
||||
mergeMultipleOverlayPlots: component && component.$refs.displayLayout.mergeMultipleOverlayPlots
|
||||
};
|
||||
},
|
||||
onEditModeChange: function (isEditing) {
|
||||
component.isEditing = isEditing;
|
||||
},
|
||||
destroy() {
|
||||
component.$destroy();
|
||||
}
|
||||
|
@ -53,7 +53,6 @@
|
||||
:index="i"
|
||||
:container-index="index"
|
||||
:is-editing="isEditing"
|
||||
:object-path="objectPath"
|
||||
/>
|
||||
|
||||
<drop-hint
|
||||
@ -106,14 +105,6 @@ export default {
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
locked: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
objectPath: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -139,10 +130,6 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
allowDrop(event, index) {
|
||||
if (this.locked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.dataTransfer.types.includes('openmct/domain-object-path')) {
|
||||
return true;
|
||||
}
|
||||
|
@ -57,8 +57,6 @@
|
||||
:container="container"
|
||||
:rows-layout="rowsLayout"
|
||||
:is-editing="isEditing"
|
||||
:locked="domainObject.locked"
|
||||
:object-path="objectPath"
|
||||
@move-frame="moveFrame"
|
||||
@new-frame="setFrameLocation"
|
||||
@persist="persist"
|
||||
@ -138,7 +136,7 @@ function sizeToFill(items) {
|
||||
}
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'objectPath', 'layoutObject'],
|
||||
inject: ['openmct', 'layoutObject'],
|
||||
components: {
|
||||
ContainerComponent,
|
||||
ResizeHandle,
|
||||
|
@ -37,7 +37,7 @@
|
||||
v-if="domainObject"
|
||||
ref="objectFrame"
|
||||
:domain-object="domainObject"
|
||||
:object-path="currentObjectPath"
|
||||
:object-path="objectPath"
|
||||
:has-frame="hasFrame"
|
||||
:show-edit-view="false"
|
||||
/>
|
||||
@ -77,16 +77,12 @@ export default {
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
objectPath: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
domainObject: undefined,
|
||||
currentObjectPath: undefined
|
||||
objectPath: undefined
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -111,7 +107,7 @@ export default {
|
||||
methods: {
|
||||
setDomainObject(object) {
|
||||
this.domainObject = object;
|
||||
this.currentObjectPath = [object].concat(this.objectPath);
|
||||
this.objectPath = [object];
|
||||
this.setSelection();
|
||||
},
|
||||
setSelection() {
|
||||
|
@ -38,7 +38,7 @@ define([
|
||||
canEdit: function (domainObject) {
|
||||
return domainObject.type === 'flexible-layout';
|
||||
},
|
||||
view: function (domainObject, objectPath) {
|
||||
view: function (domainObject) {
|
||||
let component;
|
||||
|
||||
return {
|
||||
@ -46,7 +46,6 @@ define([
|
||||
component = new Vue({
|
||||
provide: {
|
||||
openmct,
|
||||
objectPath,
|
||||
layoutObject: domainObject
|
||||
},
|
||||
el: element,
|
||||
|
@ -70,10 +70,6 @@ function ToolbarProvider(openmct) {
|
||||
}
|
||||
|
||||
if (primary.context.type === 'frame') {
|
||||
if (secondary.context.item.locked) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let frameId = primary.context.frameId;
|
||||
let layoutObject = tertiary.context.item;
|
||||
let containers = layoutObject
|
||||
@ -147,9 +143,6 @@ function ToolbarProvider(openmct) {
|
||||
toggleContainer.domainObject = secondary.context.item;
|
||||
|
||||
} else if (primary.context.type === 'container') {
|
||||
if (primary.context.item.locked) {
|
||||
return [];
|
||||
}
|
||||
|
||||
deleteContainer = {
|
||||
control: "button",
|
||||
@ -194,9 +187,6 @@ function ToolbarProvider(openmct) {
|
||||
};
|
||||
|
||||
} else if (primary.context.type === 'flexible-layout') {
|
||||
if (primary.context.item.locked) {
|
||||
return [];
|
||||
}
|
||||
|
||||
addContainer = {
|
||||
control: "button",
|
||||
|
@ -1,18 +1,13 @@
|
||||
<template>
|
||||
<a
|
||||
class="l-grid-view__item c-grid-item"
|
||||
: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
|
||||
}"
|
||||
:class="{ 'is-alias': item.isAlias === true }"
|
||||
: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
|
||||
@ -27,9 +22,6 @@
|
||||
</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,19 +7,13 @@
|
||||
<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-object-label__type-icon c-list-item__type-icon"
|
||||
class="c-list-item__type-icon"
|
||||
:class="item.type.cssClass"
|
||||
>
|
||||
<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>
|
||||
></div>
|
||||
<div class="c-list-item__name-value">{{ item.model.name }}</div>
|
||||
</a>
|
||||
</td>
|
||||
<td class="c-list-item__type">
|
||||
|
@ -38,15 +38,7 @@
|
||||
// Object is an alias to an original.
|
||||
[class*='__type-icon'] {
|
||||
@include isAlias();
|
||||
}
|
||||
}
|
||||
|
||||
&.is-missing {
|
||||
@include isMissing();
|
||||
|
||||
[class*='__type-icon'],
|
||||
[class*='__details'] {
|
||||
opacity: $opacityMissing;
|
||||
color: $colorIconAliasForKeyFilter;
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,14 +85,15 @@
|
||||
body.desktop & {
|
||||
$transOutMs: 300ms;
|
||||
flex-flow: column nowrap;
|
||||
transition: $transOutMs ease-in-out;
|
||||
transition: background $transOutMs ease-in-out;
|
||||
|
||||
&:hover {
|
||||
filter: $filterItemHoverFg;
|
||||
background: $colorItemBgHov;
|
||||
transition: $transIn;
|
||||
|
||||
.c-grid-item__type-icon {
|
||||
transform: scale(1.1);
|
||||
filter: $colorKeyFilterHov;
|
||||
transform: scale(1);
|
||||
transition: $transInBounce;
|
||||
}
|
||||
}
|
||||
@ -110,7 +103,7 @@
|
||||
}
|
||||
|
||||
&__controls {
|
||||
align-items: baseline;
|
||||
align-items: start;
|
||||
flex: 0 0 auto;
|
||||
order: 1;
|
||||
.c-info-button,
|
||||
@ -122,6 +115,7 @@
|
||||
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,17 +1,37 @@
|
||||
/******************************* LIST ITEM */
|
||||
.c-list-item {
|
||||
&__type-icon {
|
||||
color: $colorItemTreeIcon;
|
||||
&__name a {
|
||||
display: flex;
|
||||
|
||||
> * + * { margin-left: $interiorMarginSm; }
|
||||
}
|
||||
|
||||
&__name {
|
||||
&__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;
|
||||
}
|
||||
|
||||
&__name-value {
|
||||
@include ellipsize();
|
||||
}
|
||||
|
||||
&.is-alias {
|
||||
// Object is an alias to an original.
|
||||
[class*='__type-icon'] {
|
||||
@include isAlias();
|
||||
&: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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,7 @@
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: $colorItemTreeHoverBg;
|
||||
filter: $filterHov;
|
||||
background: $colorListItemBgHov;
|
||||
transition: $transIn;
|
||||
}
|
||||
}
|
||||
|
@ -24,15 +24,14 @@
|
||||
</div>
|
||||
<div class="main-image s-image-main c-imagery__main-image"
|
||||
:class="{'paused unnsynced': paused(),'stale':false }"
|
||||
:style="{'background-image': getImageUrl() ? `url(${getImageUrl()})` : 'none',
|
||||
:style="{'background-image': `url(${getImageUrl()})`,
|
||||
'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)`}"
|
||||
>
|
||||
</div>
|
||||
<div class="c-imagery__control-bar">
|
||||
<div class="c-imagery__timestamp">{{ getTime() }}</div>
|
||||
<div class="h-local-controls flex-elem">
|
||||
<a
|
||||
class="c-button icon-pause pause-play"
|
||||
<a class="c-button icon-pause pause-play"
|
||||
:class="{'is-paused': paused()}"
|
||||
@click="paused(!paused())"
|
||||
></a>
|
||||
@ -186,10 +185,6 @@ export default {
|
||||
setSelectedImage(image) {
|
||||
// If we are paused and the current image IS selected, unpause
|
||||
// Otherwise, set current image and pause
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isPaused && image.selected) {
|
||||
this.paused(false);
|
||||
this.unselectAllImages();
|
||||
@ -202,7 +197,7 @@ export default {
|
||||
}
|
||||
},
|
||||
boundsChange(bounds, isTick) {
|
||||
if (!isTick) {
|
||||
if(!isTick) {
|
||||
this.requestHistory();
|
||||
}
|
||||
},
|
||||
|
@ -41,7 +41,7 @@ define([], function () {
|
||||
this.timeFormat = 'local-format';
|
||||
this.durationFormat = 'duration';
|
||||
|
||||
this.isUTCBased = true;
|
||||
this.isUTCBased = false;
|
||||
}
|
||||
|
||||
return LocalTimeSystem;
|
||||
|
@ -1,82 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
import uuid from 'uuid';
|
||||
|
||||
export default class NewFolderAction {
|
||||
constructor(openmct) {
|
||||
this.name = 'Add New Folder';
|
||||
this.key = 'newFolder';
|
||||
this.description = 'Create a new folder';
|
||||
this.cssClass = 'icon-folder-new';
|
||||
|
||||
this._openmct = openmct;
|
||||
this._dialogForm = {
|
||||
name: "Add New Folder",
|
||||
sections: [
|
||||
{
|
||||
rows: [
|
||||
{
|
||||
key: "name",
|
||||
control: "textfield",
|
||||
name: "Folder Name",
|
||||
pattern: "\\S+",
|
||||
required: true,
|
||||
cssClass: "l-input-lg"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
invoke(objectPath) {
|
||||
let domainObject = objectPath[0],
|
||||
parentKeystring = this._openmct.objects.makeKeyString(domainObject.identifier),
|
||||
composition = this._openmct.composition.get(domainObject),
|
||||
dialogService = this._openmct.$injector.get('dialogService'),
|
||||
folderType = this._openmct.types.get('folder');
|
||||
|
||||
dialogService.getUserInput(this._dialogForm, {name: 'Unnamed Folder'}).then((userInput) => {
|
||||
let name = userInput.name,
|
||||
identifier = {
|
||||
key: uuid(),
|
||||
namespace: domainObject.identifier.namespace
|
||||
},
|
||||
objectModel = {
|
||||
identifier,
|
||||
type: 'folder',
|
||||
location: parentKeystring
|
||||
};
|
||||
|
||||
folderType.definition.initialize(objectModel);
|
||||
objectModel.name = name || 'New Folder';
|
||||
|
||||
this._openmct.objects.mutate(objectModel, 'created', Date.now());
|
||||
composition.add(objectModel);
|
||||
});
|
||||
}
|
||||
appliesTo(objectPath) {
|
||||
let domainObject = objectPath[0];
|
||||
|
||||
return domainObject.type === 'folder';
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import NewFolderAction from './newFolderAction';
|
||||
|
||||
export default function () {
|
||||
return function (openmct) {
|
||||
openmct.contextMenu.registerAction(new NewFolderAction(openmct));
|
||||
};
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import {
|
||||
createOpenMct,
|
||||
resetApplicationState
|
||||
} from 'utils/testing';
|
||||
|
||||
describe("the plugin", () => {
|
||||
let openmct,
|
||||
compositionAPI,
|
||||
newFolderAction,
|
||||
mockObjectPath,
|
||||
mockDialogService,
|
||||
mockComposition,
|
||||
mockPromise,
|
||||
newFolderName = 'New Folder';
|
||||
|
||||
beforeEach((done) => {
|
||||
openmct = createOpenMct();
|
||||
|
||||
openmct.on('start', done);
|
||||
openmct.startHeadless();
|
||||
|
||||
newFolderAction = openmct.contextMenu._allActions.filter(action => {
|
||||
return action.key === 'newFolder';
|
||||
})[0];
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetApplicationState(openmct);
|
||||
});
|
||||
|
||||
it('installs the new folder action', () => {
|
||||
expect(newFolderAction).toBeDefined();
|
||||
});
|
||||
|
||||
describe('when invoked', () => {
|
||||
|
||||
beforeEach((done) => {
|
||||
compositionAPI = openmct.composition;
|
||||
mockObjectPath = [{
|
||||
name: 'mock folder',
|
||||
type: 'folder',
|
||||
identifier: {
|
||||
key: 'mock-folder',
|
||||
namespace: ''
|
||||
}
|
||||
}];
|
||||
mockPromise = {
|
||||
then: (callback) => {
|
||||
callback({name: newFolderName});
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
mockDialogService = jasmine.createSpyObj('dialogService', ['getUserInput']);
|
||||
mockComposition = jasmine.createSpyObj('composition', ['add']);
|
||||
|
||||
mockDialogService.getUserInput.and.returnValue(mockPromise);
|
||||
|
||||
spyOn(openmct.$injector, 'get').and.returnValue(mockDialogService);
|
||||
spyOn(compositionAPI, 'get').and.returnValue(mockComposition);
|
||||
spyOn(openmct.objects, 'mutate');
|
||||
|
||||
newFolderAction.invoke(mockObjectPath);
|
||||
});
|
||||
|
||||
it('gets user input for folder name', () => {
|
||||
expect(mockDialogService.getUserInput).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('creates a new folder object', () => {
|
||||
expect(openmct.objects.mutate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('adds new folder object to parent composition', () => {
|
||||
expect(mockComposition.add).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
@ -60,7 +60,6 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.addPopupMenuItems();
|
||||
this.exportImageService = this.openmct.$injector.get('exportImageService');
|
||||
},
|
||||
methods: {
|
||||
addPopupMenuItems() {
|
||||
@ -206,7 +205,7 @@ export default {
|
||||
},
|
||||
openSnapshot() {
|
||||
const self = this;
|
||||
this.snapshot = new Vue({
|
||||
const snapshot = new Vue({
|
||||
data: () => {
|
||||
return {
|
||||
embed: self.embed
|
||||
@ -214,15 +213,14 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
formatTime: self.formatTime,
|
||||
annotateSnapshot: self.annotateSnapshot,
|
||||
exportImage: self.exportImage
|
||||
annotateSnapshot: self.annotateSnapshot
|
||||
},
|
||||
template: SnapshotTemplate
|
||||
});
|
||||
|
||||
const snapshotOverlay = this.openmct.overlays.overlay({
|
||||
element: this.snapshot.$mount().$el,
|
||||
onDestroy: () => { this.snapshot.$destroy(true) },
|
||||
element: snapshot.$mount().$el,
|
||||
onDestroy: () => { snapshot.$destroy(true) },
|
||||
size: 'large',
|
||||
dismissable: true,
|
||||
buttons: [
|
||||
@ -236,15 +234,6 @@ export default {
|
||||
]
|
||||
});
|
||||
},
|
||||
exportImage(type) {
|
||||
let element = this.snapshot.$refs['snapshot-image'];
|
||||
|
||||
if (type === 'png') {
|
||||
this.exportImageService.exportPNG(element, this.embed.name);
|
||||
} else {
|
||||
this.exportImageService.exportJPG(element, this.embed.name);
|
||||
}
|
||||
},
|
||||
previewEmbed() {
|
||||
const self = this;
|
||||
const previewAction = new PreviewAction(self.openmct);
|
||||
|
@ -2,17 +2,14 @@
|
||||
<div class="c-snapshots-h">
|
||||
<div class="l-browse-bar">
|
||||
<div class="l-browse-bar__start">
|
||||
<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">
|
||||
<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>
|
||||
</div>
|
||||
<PopupMenu v-if="snapshots.length > 0"
|
||||
:popup-menu-items="popupMenuItems"
|
||||
/>
|
||||
|
@ -15,31 +15,13 @@
|
||||
<div class="l-browse-bar__snapshot-datetime">
|
||||
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
||||
</div>
|
||||
<span class="c-button-set c-button-set--strip-h">
|
||||
<button
|
||||
class="c-button icon-download"
|
||||
title="Export This View's Data as PNG"
|
||||
@click="exportImage('png')"
|
||||
>
|
||||
<span class="c-button__label">PNG</span>
|
||||
</button>
|
||||
<button
|
||||
class="c-button"
|
||||
title="Export This View's Data as JPG"
|
||||
@click="exportImage('jpg')"
|
||||
>
|
||||
<span class="c-button__label">JPG</span>
|
||||
</button>
|
||||
</span>
|
||||
<a class="l-browse-bar__annotate-button c-button icon-pencil" title="Annotate" @click="annotateSnapshot">
|
||||
<span class="title-label">Annotate</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
ref="snapshot-image"
|
||||
class="c-notebook-snapshot__image"
|
||||
<div class="c-notebook-snapshot__image"
|
||||
:style="{ backgroundImage: 'url(' + embed.snapshot.src + ')' }"
|
||||
>
|
||||
</div>
|
||||
|
@ -1,53 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* A CouchDocument describes domain object model in a format
|
||||
* which is easily read-written to CouchDB. This includes
|
||||
* Couch's _id and _rev fields, as well as a separate
|
||||
* metadata field which contains a subset of information found
|
||||
* in the model itself (to support search optimization with
|
||||
* CouchDB views.)
|
||||
* @memberof platform/persistence/couch
|
||||
* @constructor
|
||||
* @param {string} id the id under which to store this mode
|
||||
* @param {object} model the model to store
|
||||
* @param {string} rev the revision to include (or undefined,
|
||||
* if no revision should be noted for couch)
|
||||
* @param {boolean} whether or not to mark this document as
|
||||
* deleted (see CouchDB docs for _deleted)
|
||||
*/
|
||||
export default function CouchDocument(id, model, rev, markDeleted) {
|
||||
return {
|
||||
"_id": id,
|
||||
"_rev": rev,
|
||||
"_deleted": markDeleted,
|
||||
"metadata": {
|
||||
"category": "domain object",
|
||||
"type": model.type,
|
||||
"owner": "admin",
|
||||
"name": model.name,
|
||||
"created": Date.now()
|
||||
},
|
||||
"model": model
|
||||
};
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
import CouchDocument from "./CouchDocument";
|
||||
|
||||
const REV = "_rev";
|
||||
const ID = "_id";
|
||||
|
||||
export default class CouchObjectProvider {
|
||||
constructor(openmct, url, namespace) {
|
||||
this.openmct = openmct;
|
||||
this.url = url;
|
||||
this.namespace = namespace; this.namespace = namespace; this.namespace = namespace;
|
||||
this.revs = {};
|
||||
}
|
||||
|
||||
request(subPath, method, value) {
|
||||
console.log(subPath, method, value);
|
||||
return fetch(this.url + '/' + subPath, {
|
||||
method: method,
|
||||
body: value
|
||||
}).then(response => response.json())
|
||||
.then(function (response) {
|
||||
return response;
|
||||
}, function () {
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
// Check the response to a create/update/delete request;
|
||||
// track the rev if it's valid, otherwise return false to
|
||||
// indicate that the request failed.
|
||||
checkResponse(response) {
|
||||
if (response && response.ok) {
|
||||
this.revs[response.id] = response.rev;
|
||||
return response.ok;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
getModel(response) {
|
||||
if (response && response.model) {
|
||||
let key = response[ID];
|
||||
this.revs[key] = response[REV];
|
||||
let object = response.model;
|
||||
object.identifier = {
|
||||
namespace: this.namespace,
|
||||
key: key
|
||||
};
|
||||
return object;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
get(identifier) {
|
||||
return this.request(identifier.key, "GET").then(this.getModel.bind(this));
|
||||
}
|
||||
|
||||
create(model) {
|
||||
return this.request(model.identifier, "PUT", new CouchDocument(model.identifier.key, model)).then(this.checkResponse.bind(this));
|
||||
}
|
||||
|
||||
update(model) {
|
||||
return this.request(model.identifier, "PUT", model).then(this.checkResponse.bind(this));
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import CouchObjectProvider from './CouchObjectProvider';
|
||||
const NAMESPACE = '';
|
||||
|
||||
export default function CouchPlugin(config) {
|
||||
return function install(openmct) {
|
||||
openmct.objects.addProvider(NAMESPACE, new CouchObjectProvider(openmct, config, NAMESPACE));
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import CouchPlugin from './plugin.js';
|
||||
import {
|
||||
createOpenMct,
|
||||
resetApplicationState
|
||||
} from 'utils/testing';
|
||||
|
||||
fdescribe("the plugin", () => {
|
||||
let openmct;
|
||||
let element;
|
||||
let child;
|
||||
let provider;
|
||||
let testSpace = "testSpace";
|
||||
let testPath = "/test/db";
|
||||
let mockDomainObject = { identifier: {namespace: '', key: "some-value"} };
|
||||
|
||||
beforeEach((done) => {
|
||||
openmct = createOpenMct(false);
|
||||
openmct.install(new CouchPlugin(testSpace, testPath));
|
||||
|
||||
element = document.createElement('div');
|
||||
child = document.createElement('div');
|
||||
element.appendChild(child);
|
||||
|
||||
openmct.on('start', done);
|
||||
openmct.startHeadless();
|
||||
|
||||
provider = openmct.objects.getProvider(mockDomainObject.identifier);
|
||||
});
|
||||
|
||||
it('registers a provider for objects', () => {
|
||||
expect(provider).toBeDefined();
|
||||
});
|
||||
|
||||
it('gets an object', () => {
|
||||
openmct.objects.get(mockDomainObject.identifier).then((result) => {
|
||||
expect(provider.get).toHaveBeenCalled();
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('creates an object', () => {
|
||||
openmct.objects.save(mockDomainObject).then((result) => {
|
||||
expect(provider.create).toHaveBeenCalled();
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('updates an object', () => {
|
||||
openmct.objects.save(mockDomainObject).then((result) => {
|
||||
openmct.objects.save(mockDomainObject).then((updatedResult) => {
|
||||
expect(provider.update).toHaveBeenCalled();
|
||||
expect(updatedResult).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -28,22 +28,17 @@
|
||||
ng-click="legend.set('expanded', !legend.get('expanded'));">
|
||||
</div>
|
||||
|
||||
<div class="c-plot-legend__wrapper"
|
||||
ng-class="{ 'is-cursor-locked': !!lockHighlightPoint }">
|
||||
<div class="c-plot-legend__wrapper">
|
||||
|
||||
<!-- COLLAPSED PLOT LEGEND -->
|
||||
<div class="plot-wrapper-collapsed-legend"
|
||||
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>
|
||||
ng-class="{'icon-cursor-lock': !!lockHighlightPoint}">
|
||||
<div class="plot-legend-item"
|
||||
ng-class="{'is-missing': series.domainObject.status === 'missing'}"
|
||||
ng-repeat="series in series track by $index"
|
||||
>
|
||||
ng-repeat="series in series track by $index">
|
||||
<div class="plot-series-swatch-and-name">
|
||||
<span class="plot-series-color-swatch "
|
||||
<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 }}"
|
||||
@ -60,10 +55,7 @@
|
||||
</div>
|
||||
|
||||
<!-- EXPANDED PLOT 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>
|
||||
<div class="plot-wrapper-expanded-legend">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -84,15 +76,12 @@
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<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">
|
||||
<tr ng-repeat="series in series" class="plot-legend-item">
|
||||
<td class="plot-series-swatch-and-name"
|
||||
ng-class="{'icon-cursor-lock': !!lockHighlightPoint}">
|
||||
<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>
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="The rendering method to join lines for this series.">Line Method</div>
|
||||
title="The line rendering style for this series.">Line Style</div>
|
||||
<div class="grid-cell value">{{ {
|
||||
'none': 'None',
|
||||
'linear': 'Linear interpolation',
|
||||
@ -56,7 +56,7 @@
|
||||
<div class="grid-cell label"
|
||||
title="Whether markers are displayed, and their size.">Markers</div>
|
||||
<div class="grid-cell value">
|
||||
{{ series.markerOptionsDisplayText() }}
|
||||
{{series.get('markers') ? "Enabled: " + series.get('markerSize') + "px" : "Disabled"}}
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
|
@ -52,7 +52,7 @@
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="The rendering method to join lines for this series.">Line Method</div>
|
||||
title="The line rendering style for this series.">Line Style</div>
|
||||
<div class="grid-cell value">
|
||||
<select ng-model="form.interpolate">
|
||||
<option value="none">None</option>
|
||||
@ -64,27 +64,12 @@
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Whether markers are displayed.">Markers</div>
|
||||
<div class="grid-cell value">
|
||||
<input type="checkbox" ng-model="form.markers"/>
|
||||
<select
|
||||
ng-show="form.markers"
|
||||
ng-model="form.markerShape">
|
||||
<option
|
||||
ng-repeat="option in markerShapeOptions"
|
||||
value="{{ option.value }}"
|
||||
ng-selected="option.value == form.markerShape"
|
||||
>
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="grid-cell value"><input type="checkbox" ng-model="form.markers"/></div>
|
||||
</li>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
title="Display markers visually denoting points in alarm.">Alarm Markers</div>
|
||||
<div class="grid-cell value">
|
||||
<input type="checkbox" ng-model="form.alarmMarkers"/>
|
||||
</div>
|
||||
<div class="grid-cell value"><input type="checkbox" ng-model="form.alarmMarkers"/></div>
|
||||
</li>
|
||||
<li class="grid-row" ng-show="form.markers || form.alarmMarkers">
|
||||
<div class="grid-cell label"
|
||||
|
@ -19,12 +19,12 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div ng-if="!domainObject.model.locked && domainObject.getCapability('editor').inEditContext()">
|
||||
<div ng-if="domainObject.getCapability('editor').inEditContext()">
|
||||
<mct-representation key="'plot-options-edit'"
|
||||
mct-object="domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<div ng-if="domainObject.model.locked || !domainObject.getCapability('editor').inEditContext()">
|
||||
<div ng-if="!domainObject.getCapability('editor').inEditContext()">
|
||||
<mct-representation key="'plot-options-browse'"
|
||||
mct-object="domainObject">
|
||||
</mct-representation>
|
||||
|
@ -30,7 +30,8 @@ define([
|
||||
'./MCTChartPointSet',
|
||||
'./MCTChartAlarmPointSet',
|
||||
'../draw/DrawLoader',
|
||||
'../lib/eventHelpers'
|
||||
'../lib/eventHelpers',
|
||||
'lodash'
|
||||
],
|
||||
function (
|
||||
MCTChartLineLinear,
|
||||
@ -38,7 +39,8 @@ function (
|
||||
MCTChartPointSet,
|
||||
MCTChartAlarmPointSet,
|
||||
DrawLoader,
|
||||
eventHelpers
|
||||
eventHelpers,
|
||||
_
|
||||
) {
|
||||
|
||||
var MARKER_SIZE = 6.0,
|
||||
@ -371,8 +373,7 @@ function (
|
||||
chartElement.getBuffer(),
|
||||
chartElement.color().asRGBAArray(),
|
||||
chartElement.count,
|
||||
chartElement.series.get('markerSize'),
|
||||
chartElement.series.get('markerShape')
|
||||
chartElement.series.get('markerSize')
|
||||
);
|
||||
};
|
||||
|
||||
@ -396,10 +397,9 @@ function (
|
||||
this.offset.yVal(highlight.point, highlight.series)
|
||||
]),
|
||||
color = highlight.series.get('color').asRGBAArray(),
|
||||
pointCount = 1,
|
||||
shape = highlight.series.get('markerShape');
|
||||
pointCount = 1;
|
||||
|
||||
this.drawAPI.drawPoints(points, color, pointCount, HIGHLIGHT_SIZE, shape);
|
||||
this.drawAPI.drawPoints(points, color, pointCount, HIGHLIGHT_SIZE);
|
||||
};
|
||||
|
||||
MCTChartController.prototype.drawRectangles = function () {
|
||||
|
@ -22,11 +22,13 @@
|
||||
/*global define*/
|
||||
|
||||
define([
|
||||
'lodash',
|
||||
'EventEmitter',
|
||||
'./Model',
|
||||
'../lib/extend',
|
||||
'../lib/eventHelpers'
|
||||
], function (
|
||||
_,
|
||||
EventEmitter,
|
||||
Model,
|
||||
extend,
|
||||
|
@ -25,14 +25,12 @@ define([
|
||||
'lodash',
|
||||
'../configuration/Model',
|
||||
'../lib/extend',
|
||||
'EventEmitter',
|
||||
'../draw/MarkerShapes'
|
||||
'EventEmitter'
|
||||
], function (
|
||||
_,
|
||||
Model,
|
||||
extend,
|
||||
EventEmitter,
|
||||
MARKER_SHAPES
|
||||
EventEmitter
|
||||
) {
|
||||
|
||||
/**
|
||||
@ -58,7 +56,6 @@ define([
|
||||
* `linear` (points are connected via straight lines), or
|
||||
* `stepAfter` (points are connected by steps).
|
||||
* `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.
|
||||
* `alarmMarkers`: whether or not to display alarm markers for this series.
|
||||
* `stats`: An object that tracks the min and max y values observed in this
|
||||
@ -104,7 +101,6 @@ define([
|
||||
xKey: options.collection.plot.xAxis.get('key'),
|
||||
yKey: range.key,
|
||||
markers: true,
|
||||
markerShape: 'point',
|
||||
markerSize: 2.0,
|
||||
alarmMarkers: true
|
||||
};
|
||||
@ -414,18 +410,6 @@ define([
|
||||
} else {
|
||||
this.filters = deepCopiedFilters;
|
||||
}
|
||||
},
|
||||
markerOptionsDisplayText: function () {
|
||||
const showMarkers = this.get('markers');
|
||||
if (!showMarkers) {
|
||||
return "Disabled";
|
||||
}
|
||||
|
||||
const markerShapeKey = this.get('markerShape');
|
||||
const markerShape = MARKER_SHAPES[markerShapeKey].label;
|
||||
const markerSize = this.get('markerSize');
|
||||
|
||||
return `${markerShape}: ${markerSize}px`;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -22,13 +22,13 @@
|
||||
|
||||
|
||||
define([
|
||||
'lodash',
|
||||
'EventEmitter',
|
||||
'../lib/eventHelpers',
|
||||
'./MarkerShapes'
|
||||
'../lib/eventHelpers'
|
||||
], function (
|
||||
_,
|
||||
EventEmitter,
|
||||
eventHelpers,
|
||||
MARKER_SHAPES
|
||||
eventHelpers
|
||||
) {
|
||||
|
||||
/**
|
||||
@ -123,17 +123,18 @@ define([
|
||||
buf,
|
||||
color,
|
||||
points,
|
||||
pointSize,
|
||||
shape
|
||||
pointSize
|
||||
) {
|
||||
const drawC2DShape = MARKER_SHAPES[shape].drawC2D.bind(this);
|
||||
var i = 0,
|
||||
offset = pointSize / 2;
|
||||
|
||||
this.setColor(color);
|
||||
|
||||
for (let i = 0; i < points; i++) {
|
||||
drawC2DShape(
|
||||
this.x(buf[i * 2]),
|
||||
this.y(buf[i * 2 + 1]),
|
||||
for (; i < points; i++) {
|
||||
this.c2d.fillRect(
|
||||
this.x(buf[i * 2]) - offset,
|
||||
this.y(buf[i * 2 + 1]) - offset,
|
||||
pointSize,
|
||||
pointSize
|
||||
);
|
||||
}
|
||||
|
@ -22,65 +22,33 @@
|
||||
|
||||
|
||||
define([
|
||||
'lodash',
|
||||
'EventEmitter',
|
||||
'../lib/eventHelpers',
|
||||
'./MarkerShapes'
|
||||
'../lib/eventHelpers'
|
||||
], function (
|
||||
_,
|
||||
EventEmitter,
|
||||
eventHelpers,
|
||||
MARKER_SHAPES
|
||||
eventHelpers
|
||||
) {
|
||||
|
||||
// WebGL shader sources (for drawing plain colors)
|
||||
const FRAGMENT_SHADER = `
|
||||
precision mediump float;
|
||||
uniform vec4 uColor;
|
||||
uniform int uMarkerShape;
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = uColor;
|
||||
|
||||
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;
|
||||
uniform vec2 uDimensions;
|
||||
uniform vec2 uOrigin;
|
||||
uniform float uPointSize;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1);
|
||||
gl_PointSize = uPointSize;
|
||||
}
|
||||
`;
|
||||
var FRAGMENT_SHADER = [
|
||||
"precision mediump float;",
|
||||
"uniform vec4 uColor;",
|
||||
"void main(void) {",
|
||||
"gl_FragColor = uColor;",
|
||||
"}"
|
||||
].join('\n'),
|
||||
VERTEX_SHADER = [
|
||||
"attribute vec2 aVertexPosition;",
|
||||
"uniform vec2 uDimensions;",
|
||||
"uniform vec2 uOrigin;",
|
||||
"uniform float uPointSize;",
|
||||
"void main(void) {",
|
||||
"gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1);",
|
||||
"gl_PointSize = uPointSize;",
|
||||
"}"
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Create a draw api utilizing WebGL.
|
||||
@ -124,7 +92,6 @@ define([
|
||||
this.vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER);
|
||||
this.gl.shaderSource(this.vertexShader, VERTEX_SHADER);
|
||||
this.gl.compileShader(this.vertexShader);
|
||||
|
||||
this.fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER);
|
||||
this.gl.shaderSource(this.fragmentShader, FRAGMENT_SHADER);
|
||||
this.gl.compileShader(this.fragmentShader);
|
||||
@ -140,7 +107,6 @@ define([
|
||||
// shader programs (to pass values into shaders at draw-time)
|
||||
this.aVertexPosition = this.gl.getAttribLocation(this.program, "aVertexPosition");
|
||||
this.uColor = this.gl.getUniformLocation(this.program, "uColor");
|
||||
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");
|
||||
@ -150,6 +116,9 @@ define([
|
||||
// Create a buffer to holds points which will be drawn
|
||||
this.buffer = this.gl.createBuffer();
|
||||
|
||||
// Use a line width of 2.0 for legibility
|
||||
this.gl.lineWidth(2.0);
|
||||
|
||||
// Enable blending, for smoothness
|
||||
this.gl.enable(this.gl.BLEND);
|
||||
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
|
||||
@ -171,18 +140,14 @@ define([
|
||||
((v - this.origin[1]) / this.dimensions[1]) * this.height;
|
||||
};
|
||||
|
||||
DrawWebGL.prototype.doDraw = function (drawType, buf, color, points, shape) {
|
||||
DrawWebGL.prototype.doDraw = function (drawType, buf, color, points) {
|
||||
if (this.isContextLost) {
|
||||
return;
|
||||
}
|
||||
|
||||
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.uMarkerShape, shapeCode)
|
||||
this.gl.drawArrays(drawType, 0, points);
|
||||
};
|
||||
|
||||
@ -247,12 +212,12 @@ define([
|
||||
* Draw the buffer as points.
|
||||
*
|
||||
*/
|
||||
DrawWebGL.prototype.drawPoints = function (buf, color, points, pointSize, shape) {
|
||||
DrawWebGL.prototype.drawPoints = function (buf, color, points, pointSize) {
|
||||
if (this.isContextLost) {
|
||||
return;
|
||||
}
|
||||
this.gl.uniform1f(this.uPointSize, pointSize);
|
||||
this.doDraw(this.gl.POINTS, buf, color, points, shape);
|
||||
this.doDraw(this.gl.POINTS, buf, color, points);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,90 +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
|
||||
* @drawC2D function (required) canvas2d draw function
|
||||
*/
|
||||
const MARKER_SHAPES = {
|
||||
point: {
|
||||
label: 'Point',
|
||||
drawWebGL: 1,
|
||||
drawC2D: function (x, y, size) {
|
||||
const offset = size / 2;
|
||||
|
||||
this.c2d.fillRect(x - offset, y - offset, size, size);
|
||||
}
|
||||
},
|
||||
circle: {
|
||||
label: 'Circle',
|
||||
drawWebGL: 2,
|
||||
drawC2D: function (x, y, size) {
|
||||
const radius = size / 2;
|
||||
|
||||
this.c2d.beginPath();
|
||||
this.c2d.arc(x, y, radius, 0, 2 * Math.PI, false);
|
||||
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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return MARKER_SHAPES;
|
||||
});
|
@ -23,11 +23,13 @@
|
||||
define([
|
||||
'../configuration/configStore',
|
||||
'../lib/eventHelpers',
|
||||
'objectUtils'
|
||||
'objectUtils',
|
||||
'lodash'
|
||||
], function (
|
||||
configStore,
|
||||
eventHelpers,
|
||||
objectUtils
|
||||
objectUtils,
|
||||
_
|
||||
) {
|
||||
|
||||
function PlotOptionsController($scope, openmct, $timeout) {
|
||||
|
@ -22,11 +22,9 @@
|
||||
|
||||
define([
|
||||
'./PlotModelFormController',
|
||||
'../draw/MarkerShapes',
|
||||
'lodash'
|
||||
], function (
|
||||
PlotModelFormController,
|
||||
MARKER_SHAPES,
|
||||
_
|
||||
) {
|
||||
|
||||
@ -95,13 +93,6 @@ define([
|
||||
value: o.key
|
||||
};
|
||||
});
|
||||
this.$scope.markerShapeOptions = Object.entries(MARKER_SHAPES)
|
||||
.map(([key, obj]) => {
|
||||
return {
|
||||
name: obj.label,
|
||||
value: key
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
fields: [
|
||||
@ -117,10 +108,6 @@ define([
|
||||
modelProp: 'markers',
|
||||
objectPath: dynamicPathForKey('markers')
|
||||
},
|
||||
{
|
||||
modelProp: 'markerShape',
|
||||
objectPath: dynamicPathForKey('markerShape')
|
||||
},
|
||||
{
|
||||
modelProp: 'markerSize',
|
||||
coerce: Number,
|
||||
|
@ -21,9 +21,11 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'./PlotModelFormController'
|
||||
'./PlotModelFormController',
|
||||
'lodash'
|
||||
], function (
|
||||
PlotModelFormController
|
||||
PlotModelFormController,
|
||||
_
|
||||
) {
|
||||
|
||||
var PlotYAxisFormController = PlotModelFormController.extend({
|
||||
|
@ -71,6 +71,8 @@ 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 () {
|
||||
@ -81,6 +83,11 @@ 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;
|
||||
|
||||
@ -236,16 +243,12 @@ 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 (event.altKey) {
|
||||
if (this.allowPan) {
|
||||
return this.startPan($event);
|
||||
} else {
|
||||
}
|
||||
if (this.allowMarquee) {
|
||||
return this.startMarquee($event);
|
||||
}
|
||||
};
|
||||
@ -258,11 +261,11 @@ define([
|
||||
this.$scope.lockHighlightPoint = !this.$scope.lockHighlightPoint;
|
||||
}
|
||||
|
||||
if (this.pan) {
|
||||
if (this.allowPan) {
|
||||
return this.endPan($event);
|
||||
}
|
||||
|
||||
if (this.marquee) {
|
||||
if (this.allowMarquee) {
|
||||
return this.endMarquee($event);
|
||||
}
|
||||
};
|
||||
@ -286,9 +289,6 @@ 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,9 +444,6 @@ define([
|
||||
};
|
||||
|
||||
MCTPlotController.prototype.startPan = function ($event) {
|
||||
this.$canvas.addClass('plot-drag');
|
||||
this.$canvas.removeClass('plot-marquee');
|
||||
|
||||
this.trackMousePosition($event);
|
||||
this.freeze();
|
||||
this.pan = {
|
||||
@ -489,6 +486,32 @@ 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);
|
||||
|
@ -20,7 +20,12 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([], function () {
|
||||
define([
|
||||
'lodash'
|
||||
], function (
|
||||
_
|
||||
) {
|
||||
|
||||
function StackedPlotController($scope, openmct, objectService, $element, exportImageService) {
|
||||
var tickWidth = 0,
|
||||
composition,
|
||||
@ -120,13 +125,12 @@ define([], function () {
|
||||
$scope.$watch('domainObject.getModel().composition', onCompositionChange);
|
||||
|
||||
$scope.$on('plot:tickWidth', function ($e, width) {
|
||||
const plotId = $e.targetScope.domainObject.getId();
|
||||
var plotId = $e.targetScope.domainObject.getId();
|
||||
if (!tickWidthMap.hasOwnProperty(plotId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tickWidthMap[plotId] = Math.max(width, tickWidthMap[plotId]);
|
||||
const newTickWidth = Math.max(...Object.values(tickWidthMap));
|
||||
var newTickWidth = _.max(tickWidthMap);
|
||||
if (newTickWidth !== tickWidth || width !== tickWidth) {
|
||||
tickWidth = newTickWidth;
|
||||
$scope.$broadcast('plot:tickWidth', tickWidth);
|
||||
|
@ -53,9 +53,7 @@ define([
|
||||
'./themes/maelstrom',
|
||||
'./themes/snow',
|
||||
'./URLTimeSettingsSynchronizer/plugin',
|
||||
'./notificationIndicator/plugin',
|
||||
'./newFolderAction/plugin',
|
||||
'./persistence/couch/plugin'
|
||||
'./notificationIndicator/plugin'
|
||||
], function (
|
||||
_,
|
||||
UTCTimeSystem,
|
||||
@ -89,13 +87,12 @@ define([
|
||||
Maelstrom,
|
||||
Snow,
|
||||
URLTimeSettingsSynchronizer,
|
||||
NotificationIndicator,
|
||||
NewFolderAction,
|
||||
CouchDBPlugin
|
||||
NotificationIndicator
|
||||
) {
|
||||
var bundleMap = {
|
||||
LocalStorage: 'platform/persistence/local',
|
||||
MyItems: 'platform/features/my-items',
|
||||
CouchDB: 'platform/persistence/couch',
|
||||
Elasticsearch: 'platform/persistence/elastic'
|
||||
};
|
||||
|
||||
@ -127,7 +124,27 @@ define([
|
||||
|
||||
plugins.Conductor = TimeConductorPlugin.default;
|
||||
|
||||
plugins.CouchDB = CouchDBPlugin.default;
|
||||
plugins.CouchDB = function (url) {
|
||||
return function (openmct) {
|
||||
if (url) {
|
||||
var bundleName = "config/couch";
|
||||
openmct.legacyRegistry.register(bundleName, {
|
||||
"extensions": {
|
||||
"constants": [
|
||||
{
|
||||
"key": "COUCHDB_PATH",
|
||||
"value": url,
|
||||
"priority": "mandatory"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
openmct.legacyRegistry.enable(bundleName);
|
||||
}
|
||||
|
||||
openmct.legacyRegistry.enable(bundleMap.CouchDB);
|
||||
};
|
||||
};
|
||||
|
||||
plugins.Elasticsearch = function (url) {
|
||||
return function (openmct) {
|
||||
@ -181,7 +198,6 @@ define([
|
||||
plugins.ConditionWidget = ConditionWidgetPlugin.default;
|
||||
plugins.URLTimeSettingsSynchronizer = URLTimeSettingsSynchronizer.default;
|
||||
plugins.NotificationIndicator = NotificationIndicator.default;
|
||||
plugins.NewFolderAction = NewFolderAction.default;
|
||||
|
||||
return plugins;
|
||||
});
|
||||
|
@ -101,12 +101,6 @@ export default class RemoveAction {
|
||||
appliesTo(objectPath) {
|
||||
let parent = objectPath[1];
|
||||
let parentType = parent && this.openmct.types.get(parent.type);
|
||||
let child = objectPath[0];
|
||||
let locked = child.locked ? child.locked : parent && parent.locked;
|
||||
|
||||
if (locked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parentType &&
|
||||
parentType.definition.creatable &&
|
||||
|
7
src/plugins/tabs/README.md
Normal file
7
src/plugins/tabs/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Espresso Theme
|
||||
A light colored theme for the Open MCT user interface.
|
||||
|
||||
## Installation
|
||||
```js
|
||||
openmct.install(openmct.plugins.Snow());
|
||||
```
|
@ -3,7 +3,7 @@
|
||||
<div
|
||||
class="c-tabs-view__tabs-holder c-tabs"
|
||||
:class="{
|
||||
'is-dragging': isDragging && allowEditing,
|
||||
'is-dragging': isDragging,
|
||||
'is-mouse-over': allowDrop
|
||||
}"
|
||||
>
|
||||
@ -22,24 +22,14 @@
|
||||
<button
|
||||
v-for="(tab,index) in tabsList"
|
||||
:key="index"
|
||||
class="c-tab c-tabs-view__tab"
|
||||
:class="{
|
||||
'is-current': isCurrent(tab)
|
||||
}"
|
||||
class="c-tabs-view__tab c-tab"
|
||||
:class="[
|
||||
{'is-current': isCurrent(tab)},
|
||||
tab.type.definition.cssClass
|
||||
]"
|
||||
@click="showTab(tab, index)"
|
||||
>
|
||||
<div class="c-object-label"
|
||||
:class="{'is-missing': tab.domainObject.status === 'missing'}"
|
||||
>
|
||||
<div class="c-object-label__type-icon"
|
||||
:class="tab.type.definition.cssClass"
|
||||
>
|
||||
<span class="is-missing__indicator"
|
||||
title="This item is missing"
|
||||
></span>
|
||||
</div>
|
||||
<span class="c-button__label c-object-label__name">{{ tab.domainObject.name }}</span>
|
||||
</div>
|
||||
<span class="c-button__label">{{ tab.domainObject.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
@ -48,6 +38,15 @@
|
||||
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"
|
||||
@ -59,12 +58,6 @@
|
||||
|
||||
<script>
|
||||
import ObjectView from '../../../ui/components/ObjectView.vue';
|
||||
import {
|
||||
getSearchParam,
|
||||
setSearchParam,
|
||||
deleteSearchParam
|
||||
} from 'utils/openmctLocation';
|
||||
|
||||
|
||||
var unknownObjectType = {
|
||||
definition: {
|
||||
@ -78,45 +71,26 @@ 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,
|
||||
searchTabKey: `tabs.pos.${keyString}`
|
||||
allowDrop: false
|
||||
};
|
||||
},
|
||||
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 currentTabIndexFromURL = getSearchParam(this.searchTabKey);
|
||||
let currentTabIndexFromDomainObject = this.internalDomainObject.currentTabIndex;
|
||||
let currentTabIndex = this.domainObject.currentTabIndex;
|
||||
|
||||
if (currentTabIndexFromURL !== null) {
|
||||
this.setCurrentTabByIndex(currentTabIndexFromURL);
|
||||
} else if (currentTabIndexFromDomainObject !== undefined) {
|
||||
this.setCurrentTabByIndex(currentTabIndexFromDomainObject);
|
||||
this.storeCurrentTabIndexInURL(currentTabIndexFromDomainObject);
|
||||
if (currentTabIndex !== undefined && this.tabsList.length > currentTabIndex) {
|
||||
this.currentTab = this.tabsList[currentTabIndex];
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -126,29 +100,20 @@ export default {
|
||||
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.storeCurrentTabIndexInURL(index);
|
||||
this.storeCurrentTabIndex(index);
|
||||
}
|
||||
|
||||
this.currentTab = tab;
|
||||
@ -168,10 +133,6 @@ 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
|
||||
@ -183,10 +144,6 @@ 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();
|
||||
@ -197,7 +154,7 @@ export default {
|
||||
},
|
||||
onDrop(e) {
|
||||
this.setCurrentTab = true;
|
||||
this.storeCurrentTabIndexInURL(this.tabsList.length);
|
||||
this.storeCurrentTabIndex(this.tabsList.length);
|
||||
},
|
||||
dragstart(e) {
|
||||
if (e.dataTransfer.types.includes('openmct/domain-object-path')) {
|
||||
@ -220,19 +177,8 @@ export default {
|
||||
updateInternalDomainObject(domainObject) {
|
||||
this.internalDomainObject = domainObject;
|
||||
},
|
||||
persistCurrentTabIndex(index) {
|
||||
storeCurrentTabIndex(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,28 +42,20 @@ define([
|
||||
let component;
|
||||
|
||||
return {
|
||||
show: function (element, editMode) {
|
||||
show: function (element) {
|
||||
component = new Vue({
|
||||
el: element,
|
||||
components: {
|
||||
TabsComponent: TabsComponent.default
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isEditing: editMode
|
||||
};
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject,
|
||||
composition: openmct.composition.get(domainObject)
|
||||
},
|
||||
template: '<tabs-component :isEditing="isEditing"></tabs-component>'
|
||||
template: '<tabs-component></tabs-component>'
|
||||
});
|
||||
},
|
||||
onEditModeChange(editMode) {
|
||||
component.isEditing = editMode;
|
||||
},
|
||||
destroy: function (element) {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
|
@ -22,12 +22,7 @@
|
||||
<template>
|
||||
<div
|
||||
class="c-conductor"
|
||||
:class="[
|
||||
{ 'is-zooming': isZooming },
|
||||
{ 'is-panning': isPanning },
|
||||
{ 'alt-pressed': altPressed },
|
||||
isFixed ? 'is-fixed-mode' : 'is-realtime-mode'
|
||||
]"
|
||||
:class="[isFixed ? 'is-fixed-mode' : 'is-realtime-mode']"
|
||||
>
|
||||
<form
|
||||
ref="conductorForm"
|
||||
@ -57,7 +52,7 @@
|
||||
type="text"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
@change="validateAllBounds('startDate'); submitForm()"
|
||||
@change="validateAllBounds(); submitForm()"
|
||||
>
|
||||
<date-picker
|
||||
v-if="isFixed && isUTCBased"
|
||||
@ -97,7 +92,7 @@
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
:disabled="!isFixed"
|
||||
@change="validateAllBounds('endDate'); submitForm()"
|
||||
@change="validateAllBounds(); submitForm()"
|
||||
>
|
||||
<date-picker
|
||||
v-if="isFixed && isUTCBased"
|
||||
@ -127,25 +122,14 @@
|
||||
|
||||
<conductor-axis
|
||||
class="c-conductor__ticks"
|
||||
:view-bounds="viewBounds"
|
||||
:is-fixed="isFixed"
|
||||
:alt-pressed="altPressed"
|
||||
@endPan="endPan"
|
||||
@endZoom="endZoom"
|
||||
@panAxis="pan"
|
||||
@zoomAxis="zoom"
|
||||
:bounds="rawBounds"
|
||||
@panAxis="setViewFromBounds"
|
||||
/>
|
||||
|
||||
</div>
|
||||
<div class="c-conductor__controls">
|
||||
<!-- Mode, time system menu buttons and duration slider -->
|
||||
<ConductorMode class="c-conductor__mode-select" />
|
||||
<ConductorTimeSystem class="c-conductor__time-system-select" />
|
||||
<ConductorHistory
|
||||
v-if="isFixed"
|
||||
class="c-conductor__history-select"
|
||||
:bounds="openmct.time.bounds()"
|
||||
:time-system="timeSystem"
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
type="submit"
|
||||
@ -161,7 +145,6 @@ import ConductorTimeSystem from './ConductorTimeSystem.vue';
|
||||
import DatePicker from './DatePicker.vue';
|
||||
import ConductorAxis from './ConductorAxis.vue';
|
||||
import ConductorModeIcon from './ConductorModeIcon.vue';
|
||||
import ConductorHistory from './ConductorHistory.vue'
|
||||
|
||||
const DEFAULT_DURATION_FORMATTER = 'duration';
|
||||
|
||||
@ -172,8 +155,7 @@ export default {
|
||||
ConductorTimeSystem,
|
||||
DatePicker,
|
||||
ConductorAxis,
|
||||
ConductorModeIcon,
|
||||
ConductorHistory
|
||||
ConductorModeIcon
|
||||
},
|
||||
data() {
|
||||
let bounds = this.openmct.time.bounds();
|
||||
@ -183,7 +165,6 @@ export default {
|
||||
let durationFormatter = this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
||||
|
||||
return {
|
||||
timeSystem: timeSystem,
|
||||
timeFormatter: timeFormatter,
|
||||
durationFormatter: durationFormatter,
|
||||
offsets: {
|
||||
@ -194,68 +175,29 @@ export default {
|
||||
start: timeFormatter.format(bounds.start),
|
||||
end: timeFormatter.format(bounds.end)
|
||||
},
|
||||
viewBounds: {
|
||||
rawBounds: {
|
||||
start: bounds.start,
|
||||
end: bounds.end
|
||||
},
|
||||
isFixed: this.openmct.time.clock() === undefined,
|
||||
isUTCBased: timeSystem.isUTCBased,
|
||||
showDatePicker: false,
|
||||
altPressed: false,
|
||||
isPanning: false,
|
||||
isZooming: false
|
||||
showDatePicker: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
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('timeSystem', this.setTimeSystem);
|
||||
this.openmct.time.on('clock', this.setViewFromClock);
|
||||
this.openmct.time.on('clockOffsets', this.setViewFromOffsets)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.handleKeyDown);
|
||||
document.removeEventListener('keyup', this.handleKeyUp);
|
||||
},
|
||||
methods: {
|
||||
handleKeyDown(event) {
|
||||
if (event.key === 'Alt') {
|
||||
this.altPressed = true;
|
||||
}
|
||||
},
|
||||
handleKeyUp(event) {
|
||||
if (event.key === 'Alt') {
|
||||
this.altPressed = false;
|
||||
}
|
||||
},
|
||||
pan(bounds) {
|
||||
this.isPanning = true;
|
||||
this.setViewFromBounds(bounds);
|
||||
},
|
||||
endPan(bounds) {
|
||||
this.isPanning = false;
|
||||
if (bounds) {
|
||||
this.openmct.time.bounds(bounds);
|
||||
}
|
||||
},
|
||||
zoom(bounds) {
|
||||
this.isZooming = true;
|
||||
this.formattedBounds.start = this.timeFormatter.format(bounds.start);
|
||||
this.formattedBounds.end = this.timeFormatter.format(bounds.end);
|
||||
},
|
||||
endZoom(bounds) {
|
||||
const _bounds = bounds ? bounds : this.openmct.time.bounds();
|
||||
this.isZooming = false;
|
||||
|
||||
this.openmct.time.bounds(_bounds);
|
||||
},
|
||||
setTimeSystem(timeSystem) {
|
||||
this.timeSystem = timeSystem
|
||||
this.timeFormatter = this.getFormatter(timeSystem.timeFormat);
|
||||
this.durationFormatter = this.getFormatter(
|
||||
timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
||||
|
||||
this.isUTCBased = timeSystem.isUTCBased;
|
||||
},
|
||||
setOffsetsFromView($event) {
|
||||
@ -295,8 +237,8 @@ export default {
|
||||
setViewFromBounds(bounds) {
|
||||
this.formattedBounds.start = this.timeFormatter.format(bounds.start);
|
||||
this.formattedBounds.end = this.timeFormatter.format(bounds.end);
|
||||
this.viewBounds.start = bounds.start;
|
||||
this.viewBounds.end = bounds.end;
|
||||
this.rawBounds.start = bounds.start;
|
||||
this.rawBounds.end = bounds.end;
|
||||
},
|
||||
setViewFromOffsets(offsets) {
|
||||
this.offsets.start = this.durationFormatter.format(Math.abs(offsets.start));
|
||||
@ -309,15 +251,6 @@ export default {
|
||||
this.setOffsetsFromView();
|
||||
}
|
||||
},
|
||||
getBoundsLimit() {
|
||||
const configuration = this.configuration.menuOptions
|
||||
.filter(option => option.timeSystem === this.timeSystem.key)
|
||||
.find(option => option.limit);
|
||||
|
||||
const limit = configuration ? configuration.limit : undefined;
|
||||
|
||||
return limit;
|
||||
},
|
||||
clearAllValidation() {
|
||||
if (this.isFixed) {
|
||||
[this.$refs.startDate, this.$refs.endDate].forEach(this.clearValidationForInput);
|
||||
@ -329,52 +262,36 @@ export default {
|
||||
input.setCustomValidity('');
|
||||
input.title = '';
|
||||
},
|
||||
validateAllBounds(ref) {
|
||||
if (!this.areBoundsFormatsValid()) {
|
||||
return false;
|
||||
validateAllBounds() {
|
||||
return [this.$refs.startDate, this.$refs.endDate].every((input) => {
|
||||
let validationResult = true;
|
||||
let formattedDate;
|
||||
|
||||
if (input === this.$refs.startDate) {
|
||||
formattedDate = this.formattedBounds.start;
|
||||
} else {
|
||||
formattedDate = this.formattedBounds.end;
|
||||
}
|
||||
|
||||
let validationResult = true;
|
||||
const currentInput = this.$refs[ref];
|
||||
|
||||
return [this.$refs.startDate, this.$refs.endDate].every((input) => {
|
||||
if (!this.timeFormatter.validate(formattedDate)) {
|
||||
validationResult = 'Invalid date';
|
||||
} else {
|
||||
let boundsValues = {
|
||||
start: this.timeFormatter.parse(this.formattedBounds.start),
|
||||
end: this.timeFormatter.parse(this.formattedBounds.end)
|
||||
};
|
||||
const limit = this.getBoundsLimit();
|
||||
|
||||
if (
|
||||
this.timeSystem.isUTCBased
|
||||
&& limit
|
||||
&& boundsValues.end - boundsValues.start > limit
|
||||
) {
|
||||
if (input === currentInput) {
|
||||
validationResult = "Start and end difference exceeds allowable limit";
|
||||
}
|
||||
} else {
|
||||
if (input === currentInput) {
|
||||
validationResult = this.openmct.time.validateBounds(boundsValues);
|
||||
}
|
||||
|
||||
if (validationResult !== true) {
|
||||
input.setCustomValidity(validationResult);
|
||||
input.title = validationResult;
|
||||
return false;
|
||||
} else {
|
||||
input.setCustomValidity('');
|
||||
input.title = '';
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.handleValidationResults(input, validationResult);
|
||||
});
|
||||
},
|
||||
areBoundsFormatsValid() {
|
||||
let validationResult = true;
|
||||
|
||||
return [this.$refs.startDate, this.$refs.endDate].every((input) => {
|
||||
const formattedDate = input === this.$refs.startDate
|
||||
? this.formattedBounds.start
|
||||
: this.formattedBounds.end
|
||||
;
|
||||
|
||||
if (!this.timeFormatter.validate(formattedDate)) {
|
||||
validationResult = 'Invalid date';
|
||||
}
|
||||
|
||||
return this.handleValidationResults(input, validationResult);
|
||||
});
|
||||
},
|
||||
validateAllOffsets(event) {
|
||||
@ -398,10 +315,6 @@ export default {
|
||||
validationResult = this.openmct.time.validateOffsets(offsetValues);
|
||||
}
|
||||
|
||||
return this.handleValidationResults(input, validationResult);
|
||||
});
|
||||
},
|
||||
handleValidationResults(input, validationResult) {
|
||||
if (validationResult !== true) {
|
||||
input.setCustomValidity(validationResult);
|
||||
input.title = validationResult;
|
||||
@ -411,6 +324,7 @@ export default {
|
||||
input.title = '';
|
||||
return true;
|
||||
}
|
||||
});
|
||||
},
|
||||
submitForm() {
|
||||
// Allow Vue model to catch up to user input.
|
||||
@ -424,12 +338,12 @@ export default {
|
||||
},
|
||||
startDateSelected(date) {
|
||||
this.formattedBounds.start = this.timeFormatter.format(date);
|
||||
this.validateAllBounds('startDate');
|
||||
this.validateAllBounds();
|
||||
this.submitForm();
|
||||
},
|
||||
endDateSelected(date) {
|
||||
this.formattedBounds.end = this.timeFormatter.format(date);
|
||||
this.validateAllBounds('endDate');
|
||||
this.validateAllBounds();
|
||||
this.submitForm();
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,7 @@
|
||||
ref="axisHolder"
|
||||
class="c-conductor-axis"
|
||||
@mousedown="dragStart($event)"
|
||||
>
|
||||
<div
|
||||
class="c-conductor-axis__zoom-indicator"
|
||||
:style="zoomStyle"
|
||||
></div>
|
||||
</div>
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -48,81 +43,52 @@ const PIXELS_PER_TICK_WIDE = 200;
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
viewBounds: {
|
||||
bounds: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isFixed: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
altPressed: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inPanMode: false,
|
||||
dragStartX: undefined,
|
||||
dragX: undefined,
|
||||
zoomStyle: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
inZoomMode() {
|
||||
return !this.inPanMode;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
viewBounds: {
|
||||
handler() {
|
||||
bounds: {
|
||||
handler(bounds) {
|
||||
this.setScale();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let vis = d3Selection.select(this.$refs.axisHolder).append("svg:svg");
|
||||
let axisHolder = this.$refs.axisHolder;
|
||||
let height = axisHolder.offsetHeight;
|
||||
let vis = d3Selection.select(axisHolder)
|
||||
.append("svg:svg")
|
||||
.attr("width", "100%")
|
||||
.attr("height", height);
|
||||
|
||||
this.width = this.$refs.axisHolder.clientWidth;
|
||||
this.xAxis = d3Axis.axisTop();
|
||||
this.dragging = false;
|
||||
|
||||
// draw x axis with labels. CSS is used to position them.
|
||||
this.axisElement = vis.append("g")
|
||||
.attr("class", "axis");
|
||||
this.axisElement = vis.append("g");
|
||||
|
||||
this.setViewFromTimeSystem(this.openmct.time.timeSystem());
|
||||
this.setAxisDimensions();
|
||||
this.setScale();
|
||||
|
||||
//Respond to changes in conductor
|
||||
this.openmct.time.on("timeSystem", this.setViewFromTimeSystem);
|
||||
setInterval(this.resize, RESIZE_POLL_INTERVAL);
|
||||
},
|
||||
methods: {
|
||||
setAxisDimensions() {
|
||||
const axisHolder = this.$refs.axisHolder;
|
||||
const rect = axisHolder.getBoundingClientRect();
|
||||
|
||||
this.left = Math.round(rect.left);
|
||||
this.width = axisHolder.clientWidth;
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
setScale() {
|
||||
if (!this.width) {
|
||||
return;
|
||||
}
|
||||
|
||||
let timeSystem = this.openmct.time.timeSystem();
|
||||
let bounds = this.bounds;
|
||||
|
||||
if (timeSystem.isUTCBased) {
|
||||
this.xScale.domain(
|
||||
[new Date(this.viewBounds.start), new Date(this.viewBounds.end)]
|
||||
);
|
||||
this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]);
|
||||
} else {
|
||||
this.xScale.domain(
|
||||
[this.viewBounds.start, this.viewBounds.end]
|
||||
);
|
||||
this.xScale.domain([bounds.start, bounds.end]);
|
||||
}
|
||||
|
||||
this.xAxis.scale(this.xScale);
|
||||
@ -136,7 +102,7 @@ export default {
|
||||
this.xAxis.ticks(this.width / PIXELS_PER_TICK);
|
||||
}
|
||||
|
||||
this.msPerPixel = (this.viewBounds.end - this.viewBounds.start) / this.width;
|
||||
this.msPerPixel = (bounds.end - bounds.start) / this.width;
|
||||
},
|
||||
setViewFromTimeSystem(timeSystem) {
|
||||
//The D3 scale used depends on the type of time system as d3
|
||||
@ -154,8 +120,9 @@ export default {
|
||||
},
|
||||
getActiveFormatter() {
|
||||
let timeSystem = this.openmct.time.timeSystem();
|
||||
let isFixed = this.openmct.time.clock() === undefined;
|
||||
|
||||
if (this.isFixed) {
|
||||
if (isFixed) {
|
||||
return this.getFormatter(timeSystem.timeFormat);
|
||||
} else {
|
||||
return this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
||||
@ -167,131 +134,45 @@ export default {
|
||||
}).formatter;
|
||||
},
|
||||
dragStart($event) {
|
||||
if (this.isFixed) {
|
||||
let isFixed = this.openmct.time.clock() === undefined;
|
||||
if (isFixed) {
|
||||
this.dragStartX = $event.clientX;
|
||||
|
||||
if (this.altPressed) {
|
||||
this.inPanMode = true;
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', this.drag);
|
||||
document.addEventListener('mouseup', this.dragEnd, {
|
||||
once: true
|
||||
});
|
||||
|
||||
if (this.inZoomMode) {
|
||||
this.startZoom();
|
||||
}
|
||||
}
|
||||
},
|
||||
drag($event) {
|
||||
if (!this.dragging) {
|
||||
this.dragging = true;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
this.dragX = $event.clientX;
|
||||
this.inPanMode ? this.pan() : this.zoom();
|
||||
this.dragging = false;
|
||||
requestAnimationFrame(()=>{
|
||||
let deltaX = $event.clientX - this.dragStartX;
|
||||
let percX = deltaX / this.width;
|
||||
let bounds = this.openmct.time.bounds();
|
||||
let deltaTime = bounds.end - bounds.start;
|
||||
let newStart = bounds.start - percX * deltaTime;
|
||||
this.$emit('panAxis',{
|
||||
start: newStart,
|
||||
end: newStart + deltaTime
|
||||
});
|
||||
this.dragging = false;
|
||||
})
|
||||
} else {
|
||||
console.log('Rejected drag due to RAF cap');
|
||||
}
|
||||
},
|
||||
dragEnd() {
|
||||
this.inPanMode ? this.endPan() : this.endZoom();
|
||||
|
||||
document.removeEventListener('mousemove', this.drag);
|
||||
this.dragStartX = undefined;
|
||||
this.dragX = undefined;
|
||||
},
|
||||
pan() {
|
||||
const panBounds = this.getPanBounds();
|
||||
this.$emit('panAxis', panBounds);
|
||||
},
|
||||
endPan() {
|
||||
const panBounds = this.dragStartX && this.dragX && this.dragStartX !== this.dragX
|
||||
? this.getPanBounds()
|
||||
: undefined;
|
||||
this.$emit('endPan', panBounds);
|
||||
this.inPanMode = false;
|
||||
},
|
||||
getPanBounds() {
|
||||
const bounds = this.openmct.time.bounds();
|
||||
const deltaTime = bounds.end - bounds.start;
|
||||
const deltaX = this.dragX - this.dragStartX;
|
||||
const percX = deltaX / this.width;
|
||||
const panStart = bounds.start - percX * deltaTime;
|
||||
|
||||
return {
|
||||
start: panStart,
|
||||
end: panStart + deltaTime
|
||||
};
|
||||
},
|
||||
startZoom() {
|
||||
const x = this.scaleToBounds(this.dragStartX);
|
||||
|
||||
this.zoomStyle = {
|
||||
left: `${this.dragStartX - this.left}px`
|
||||
};
|
||||
|
||||
this.$emit('zoomAxis', {
|
||||
start: x,
|
||||
end: x
|
||||
this.openmct.time.bounds({
|
||||
start: this.bounds.start,
|
||||
end: this.bounds.end
|
||||
});
|
||||
},
|
||||
zoom() {
|
||||
const zoomRange = this.getZoomRange();
|
||||
|
||||
this.zoomStyle = {
|
||||
left: `${zoomRange.start - this.left}px`,
|
||||
width: `${zoomRange.end - zoomRange.start}px`
|
||||
};
|
||||
|
||||
this.$emit('zoomAxis', {
|
||||
start: this.scaleToBounds(zoomRange.start),
|
||||
end: this.scaleToBounds(zoomRange.end)
|
||||
});
|
||||
},
|
||||
endZoom() {
|
||||
const zoomRange = this.dragStartX && this.dragX && this.dragStartX !== this.dragX
|
||||
? this.getZoomRange()
|
||||
: undefined;
|
||||
|
||||
const zoomBounds = zoomRange
|
||||
? {
|
||||
start: this.scaleToBounds(zoomRange.start),
|
||||
end: this.scaleToBounds(zoomRange.end)
|
||||
}
|
||||
: this.openmct.time.bounds();
|
||||
|
||||
this.zoomStyle = {};
|
||||
this.$emit('endZoom', zoomBounds);
|
||||
},
|
||||
getZoomRange() {
|
||||
const leftBound = this.left;
|
||||
const rightBound = this.left + this.width;
|
||||
|
||||
const zoomStart = this.dragX < leftBound
|
||||
? leftBound
|
||||
: Math.min(this.dragX, this.dragStartX);
|
||||
|
||||
const zoomEnd = this.dragX > rightBound
|
||||
? rightBound
|
||||
: Math.max(this.dragX, this.dragStartX);
|
||||
|
||||
return {
|
||||
start: zoomStart,
|
||||
end: zoomEnd
|
||||
};
|
||||
},
|
||||
scaleToBounds(value) {
|
||||
const bounds = this.openmct.time.bounds();
|
||||
const timeDelta = bounds.end - bounds.start;
|
||||
const valueDelta = value - this.left;
|
||||
const offset = valueDelta / this.width * timeDelta;
|
||||
return bounds.start + offset;
|
||||
},
|
||||
resize() {
|
||||
if (this.$refs.axisHolder.clientWidth !== this.width) {
|
||||
this.setAxisDimensions();
|
||||
this.width = this.$refs.axisHolder.clientWidth;
|
||||
this.setScale();
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user