mirror of
https://github.com/nasa/openmct.git
synced 2024-12-20 21:53:08 +00:00
* Implement transactions in Object API and retire legacy transactions #4089 * Added `objectAPI.refresh` Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
parent
5eaf222f88
commit
d0c5731287
@ -34,9 +34,6 @@ define([
|
||||
"./src/policies/EditPersistableObjectsPolicy",
|
||||
"./src/representers/EditRepresenter",
|
||||
"./src/capabilities/EditorCapability",
|
||||
"./src/capabilities/TransactionCapabilityDecorator",
|
||||
"./src/services/TransactionManager",
|
||||
"./src/services/TransactionService",
|
||||
"./src/creation/CreateMenuController",
|
||||
"./src/creation/LocatorController",
|
||||
"./src/creation/CreationPolicy",
|
||||
@ -63,9 +60,6 @@ define([
|
||||
EditPersistableObjectsPolicy,
|
||||
EditRepresenter,
|
||||
EditorCapability,
|
||||
TransactionCapabilityDecorator,
|
||||
TransactionManager,
|
||||
TransactionService,
|
||||
CreateMenuController,
|
||||
LocatorController,
|
||||
CreationPolicy,
|
||||
@ -263,26 +257,6 @@ define([
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"type": "decorator",
|
||||
"provides": "capabilityService",
|
||||
"implementation": TransactionCapabilityDecorator,
|
||||
"depends": [
|
||||
"$q",
|
||||
"transactionManager"
|
||||
],
|
||||
"priority": "fallback"
|
||||
},
|
||||
{
|
||||
"type": "provider",
|
||||
"provides": "transactionService",
|
||||
"implementation": TransactionService,
|
||||
"depends": [
|
||||
"$q",
|
||||
"$log",
|
||||
"cacheService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "CreateActionProvider",
|
||||
"provides": "actionService",
|
||||
@ -320,7 +294,6 @@ define([
|
||||
"description": "Provides transactional editing capabilities",
|
||||
"implementation": EditorCapability,
|
||||
"depends": [
|
||||
"transactionService",
|
||||
"openmct"
|
||||
]
|
||||
}
|
||||
@ -331,15 +304,6 @@ define([
|
||||
"template": locatorTemplate
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
{
|
||||
"key": "transactionManager",
|
||||
"implementation": TransactionManager,
|
||||
"depends": [
|
||||
"transactionService"
|
||||
]
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
depends: [
|
||||
|
@ -155,8 +155,8 @@ function (
|
||||
}
|
||||
|
||||
function undirtyOriginals(object) {
|
||||
return Promise.all(toUndirty.map(undirty))
|
||||
.then(() => {
|
||||
return object.getCapability("persistence").persist()
|
||||
.then(function () {
|
||||
return object;
|
||||
});
|
||||
}
|
||||
|
@ -30,32 +30,17 @@ define(
|
||||
* Once initiated, any persist operations will be queued pending a
|
||||
* subsequent call to [.save()](@link #save) or [.finish()](@link
|
||||
* #finish).
|
||||
* @param transactionService
|
||||
* @param domainObject
|
||||
* @constructor
|
||||
*/
|
||||
function EditorCapability(
|
||||
transactionService,
|
||||
openmct,
|
||||
domainObject
|
||||
) {
|
||||
this.transactionService = transactionService;
|
||||
this.openmct = openmct;
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate an editing session. This will start a transaction during
|
||||
* which any persist operations will be deferred until either save()
|
||||
* or finish() are called.
|
||||
*/
|
||||
EditorCapability.prototype.edit = function () {
|
||||
if (!this.openmct.editor.isEditing()) {
|
||||
this.openmct.editor.edit();
|
||||
this.domainObject.getCapability('status').set('editing', true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether this object, or any of its ancestors are
|
||||
* currently being edited.
|
||||
@ -74,34 +59,6 @@ define(
|
||||
return this.openmct.editor.isEditing();
|
||||
};
|
||||
|
||||
/**
|
||||
* Save any unsaved changes from this editing session. This will
|
||||
* end the current transaction and continue with a new one.
|
||||
* @returns {*}
|
||||
*/
|
||||
EditorCapability.prototype.save = function () {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
|
||||
|
||||
/**
|
||||
* Finish the current editing session. This will discard any pending
|
||||
* persist operations
|
||||
* @returns {*}
|
||||
*/
|
||||
EditorCapability.prototype.finish = function () {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if there have been any domain model
|
||||
* modifications since the last persist, false otherwise.
|
||||
*/
|
||||
EditorCapability.prototype.dirty = function () {
|
||||
return this.transactionService.size() > 0;
|
||||
};
|
||||
|
||||
return EditorCapability;
|
||||
}
|
||||
);
|
||||
|
@ -1,75 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(
|
||||
['./TransactionalPersistenceCapability'],
|
||||
function (TransactionalPersistenceCapability) {
|
||||
|
||||
/**
|
||||
* Wraps the [PersistenceCapability]{@link PersistenceCapability} with
|
||||
* transactional capabilities.
|
||||
* @param $q
|
||||
* @param transactionService
|
||||
* @param capabilityService
|
||||
* @see TransactionalPersistenceCapability
|
||||
* @constructor
|
||||
*/
|
||||
function TransactionCapabilityDecorator(
|
||||
$q,
|
||||
transactionService,
|
||||
capabilityService
|
||||
) {
|
||||
this.capabilityService = capabilityService;
|
||||
this.transactionService = transactionService;
|
||||
this.$q = $q;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorate PersistenceCapability to queue persistence calls when a
|
||||
* transaction is in progress.
|
||||
*/
|
||||
TransactionCapabilityDecorator.prototype.getCapabilities = function () {
|
||||
var self = this,
|
||||
capabilities = this.capabilityService.getCapabilities
|
||||
.apply(this.capabilityService, arguments),
|
||||
persistenceCapability = capabilities.persistence;
|
||||
|
||||
capabilities.persistence = function (domainObject) {
|
||||
var original =
|
||||
(typeof persistenceCapability === 'function')
|
||||
? persistenceCapability(domainObject)
|
||||
: persistenceCapability;
|
||||
|
||||
return new TransactionalPersistenceCapability(
|
||||
self.$q,
|
||||
self.transactionService,
|
||||
original,
|
||||
domainObject
|
||||
);
|
||||
};
|
||||
|
||||
return capabilities;
|
||||
};
|
||||
|
||||
return TransactionCapabilityDecorator;
|
||||
}
|
||||
);
|
@ -1,91 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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 () {
|
||||
|
||||
/**
|
||||
* Wraps persistence capability to enable transactions. Transactions
|
||||
* will cause persist calls not to be invoked immediately, but
|
||||
* rather queued until [EditorCapability.save()]{@link EditorCapability#save}
|
||||
* or [EditorCapability.cancel()]{@link EditorCapability#cancel} are
|
||||
* called.
|
||||
* @memberof platform/commonUI/edit/capabilities
|
||||
* @param $q
|
||||
* @param transactionManager
|
||||
* @param persistenceCapability
|
||||
* @param domainObject
|
||||
* @constructor
|
||||
*/
|
||||
function TransactionalPersistenceCapability(
|
||||
$q,
|
||||
transactionManager,
|
||||
persistenceCapability,
|
||||
domainObject
|
||||
) {
|
||||
this.transactionManager = transactionManager;
|
||||
this.persistenceCapability = persistenceCapability;
|
||||
this.domainObject = domainObject;
|
||||
this.$q = $q;
|
||||
}
|
||||
|
||||
/**
|
||||
* The wrapped persist function. If a transaction is active, persist
|
||||
* will be queued until the transaction is committed or cancelled.
|
||||
* @returns {*}
|
||||
*/
|
||||
TransactionalPersistenceCapability.prototype.persist = function () {
|
||||
var wrappedPersistence = this.persistenceCapability;
|
||||
|
||||
if (this.transactionManager.isActive()) {
|
||||
this.transactionManager.addToTransaction(
|
||||
this.domainObject.getId(),
|
||||
wrappedPersistence.persist.bind(wrappedPersistence),
|
||||
wrappedPersistence.refresh.bind(wrappedPersistence)
|
||||
);
|
||||
|
||||
//Need to return a promise from this function
|
||||
return this.$q.when(true);
|
||||
} else {
|
||||
return this.persistenceCapability.persist();
|
||||
}
|
||||
};
|
||||
|
||||
TransactionalPersistenceCapability.prototype.refresh = function () {
|
||||
this.transactionManager
|
||||
.clearTransactionsFor(this.domainObject.getId());
|
||||
|
||||
return this.persistenceCapability.refresh();
|
||||
};
|
||||
|
||||
TransactionalPersistenceCapability.prototype.getSpace = function () {
|
||||
return this.persistenceCapability.getSpace();
|
||||
};
|
||||
|
||||
TransactionalPersistenceCapability.prototype.persisted = function () {
|
||||
return this.persistenceCapability.persisted();
|
||||
};
|
||||
|
||||
return TransactionalPersistenceCapability;
|
||||
}
|
||||
);
|
@ -1,49 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(['./Transaction'], function (Transaction) {
|
||||
/**
|
||||
* A nested transaction is a transaction which takes place in the context
|
||||
* of a larger parent transaction. It becomes part of the parent
|
||||
* transaction when (and only when) committed.
|
||||
* @param parent
|
||||
* @constructor
|
||||
* @extends {platform/commonUI/edit/services.Transaction}
|
||||
* @memberof platform/commonUI/edit/services
|
||||
*/
|
||||
function NestedTransaction(parent) {
|
||||
this.parent = parent;
|
||||
Transaction.call(this, parent.$log);
|
||||
}
|
||||
|
||||
NestedTransaction.prototype = Object.create(Transaction.prototype);
|
||||
|
||||
NestedTransaction.prototype.commit = function () {
|
||||
this.parent.add(
|
||||
Transaction.prototype.commit.bind(this),
|
||||
Transaction.prototype.cancel.bind(this)
|
||||
);
|
||||
|
||||
return Promise.resolve(true);
|
||||
};
|
||||
|
||||
return NestedTransaction;
|
||||
});
|
@ -1,99 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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 () {
|
||||
/**
|
||||
* A Transaction represents a set of changes that are intended to
|
||||
* be kept or discarded as a unit.
|
||||
* @param $log Angular's `$log` service, for logging messages
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit/services
|
||||
*/
|
||||
function Transaction($log) {
|
||||
this.$log = $log;
|
||||
this.callbacks = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a change to the current transaction, as expressed by functions
|
||||
* to either keep or discard the change.
|
||||
* @param {Function} commit called when the transaction is committed
|
||||
* @param {Function} cancel called when the transaction is cancelled
|
||||
* @returns {Function) a function which may be called to remove this
|
||||
* pair of callbacks from the transaction
|
||||
*/
|
||||
Transaction.prototype.add = function (commit, cancel) {
|
||||
var callback = {
|
||||
commit: commit,
|
||||
cancel: cancel
|
||||
};
|
||||
this.callbacks.push(callback);
|
||||
|
||||
return function () {
|
||||
this.callbacks = this.callbacks.filter(function (c) {
|
||||
return c !== callback;
|
||||
});
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the number of changes in the current transaction.
|
||||
* @returns {number} the size of the current transaction
|
||||
*/
|
||||
Transaction.prototype.size = function () {
|
||||
return this.callbacks.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Keep all changes associated with this transaction.
|
||||
* @method {platform/commonUI/edit/services.Transaction#commit}
|
||||
* @returns {Promise} a promise which will resolve when all callbacks
|
||||
* have been handled.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Discard all changes associated with this transaction.
|
||||
* @method {platform/commonUI/edit/services.Transaction#cancel}
|
||||
* @returns {Promise} a promise which will resolve when all callbacks
|
||||
* have been handled.
|
||||
*/
|
||||
|
||||
['commit', 'cancel'].forEach(function (method) {
|
||||
Transaction.prototype[method] = function () {
|
||||
var promises = [];
|
||||
var callback;
|
||||
|
||||
while (this.callbacks.length > 0) {
|
||||
callback = this.callbacks.shift();
|
||||
try {
|
||||
promises.push(callback[method]());
|
||||
} catch (e) {
|
||||
this.$log
|
||||
.error("Error trying to " + method + " transaction.");
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
};
|
||||
});
|
||||
|
||||
return Transaction;
|
||||
});
|
@ -1,119 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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 () {
|
||||
/**
|
||||
* Manages transactions to support the TransactionalPersistenceCapability.
|
||||
* This assumes that all commit/cancel callbacks for a given domain
|
||||
* object are equivalent, and only need to be added once to any active
|
||||
* transaction. Violating this assumption may cause unexpected behavior.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/edit
|
||||
*/
|
||||
function TransactionManager(transactionService) {
|
||||
this.transactionService = transactionService;
|
||||
this.clearTransactionFns = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a transaction is currently active.
|
||||
* @returns {boolean} true if there is a transaction active
|
||||
*/
|
||||
TransactionManager.prototype.isActive = function () {
|
||||
return this.transactionService.isActive();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if callbacks associated with this domain object have already
|
||||
* been added to the active transaction.
|
||||
* @private
|
||||
* @param {string} id the identifier of the domain object to check
|
||||
* @returns {boolean} true if callbacks have been added
|
||||
*/
|
||||
TransactionManager.prototype.isScheduled = function (id) {
|
||||
return Boolean(this.clearTransactionFns[id]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add callbacks associated with this domain object to the active
|
||||
* transaction. Both callbacks are expected to return promises that
|
||||
* resolve when their associated behavior is complete.
|
||||
*
|
||||
* If callbacks associated with this domain object have already been
|
||||
* added to the active transaction, this call will be ignored.
|
||||
*
|
||||
* @param {string} id the identifier of the associated domain object
|
||||
* @param {Function} onCommit behavior to invoke when committing transaction
|
||||
* @param {Function} onCancel behavior to invoke when cancelling transaction
|
||||
*/
|
||||
TransactionManager.prototype.addToTransaction = function (
|
||||
id,
|
||||
onCommit,
|
||||
onCancel
|
||||
) {
|
||||
var release = this.releaseClearFn.bind(this, id);
|
||||
|
||||
function chain(promiseFn, nextFn) {
|
||||
return function () {
|
||||
return promiseFn().then(nextFn);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any existing persistence calls for object with given ID. This ensures only the most recent persistence
|
||||
* call is executed. This should prevent stale objects being persisted and overwriting fresh ones.
|
||||
*/
|
||||
if (this.isScheduled(id)) {
|
||||
this.clearTransactionsFor(id);
|
||||
}
|
||||
|
||||
this.clearTransactionFns[id] =
|
||||
this.transactionService.addToTransaction(
|
||||
chain(onCommit, release),
|
||||
chain(onCancel, release)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove any callbacks associated with this domain object from the
|
||||
* active transaction.
|
||||
* @param {string} id the identifier for the domain object
|
||||
*/
|
||||
TransactionManager.prototype.clearTransactionsFor = function (id) {
|
||||
if (this.isScheduled(id)) {
|
||||
this.clearTransactionFns[id]();
|
||||
this.releaseClearFn(id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Release the cached "remove from transaction" function that has been
|
||||
* stored in association with this domain object.
|
||||
* @param {string} id the identifier for the domain object
|
||||
* @private
|
||||
*/
|
||||
TransactionManager.prototype.releaseClearFn = function (id) {
|
||||
delete this.clearTransactionFns[id];
|
||||
};
|
||||
|
||||
return TransactionManager;
|
||||
});
|
@ -1,138 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(
|
||||
['./Transaction', './NestedTransaction'],
|
||||
function (Transaction, NestedTransaction) {
|
||||
/**
|
||||
* Implements an application-wide transaction state. Once a
|
||||
* transaction is started, calls to
|
||||
* [PersistenceCapability.persist()]{@link PersistenceCapability#persist}
|
||||
* will be deferred until a subsequent call to
|
||||
* [TransactionService.commit]{@link TransactionService#commit} is made.
|
||||
*
|
||||
* @memberof platform/commonUI/edit/services
|
||||
* @param $q
|
||||
* @constructor
|
||||
*/
|
||||
function TransactionService($q, $log, cacheService) {
|
||||
this.$q = $q;
|
||||
this.$log = $log;
|
||||
this.cacheService = cacheService;
|
||||
this.transactions = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a transaction. While a transaction is active all calls to
|
||||
* [PersistenceCapability.persist](@link PersistenceCapability#persist)
|
||||
* will be queued until [commit]{@link #commit} or [cancel]{@link
|
||||
* #cancel} are called
|
||||
*/
|
||||
TransactionService.prototype.startTransaction = function () {
|
||||
var transaction = this.isActive()
|
||||
? new NestedTransaction(this.transactions[0])
|
||||
: new Transaction(this.$log);
|
||||
|
||||
this.transactions.push(transaction);
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {boolean} If true, indicates that a transaction is in progress
|
||||
*/
|
||||
TransactionService.prototype.isActive = function () {
|
||||
return this.transactions.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds provided functions to a queue to be called on
|
||||
* [.commit()]{@link #commit} or
|
||||
* [.cancel()]{@link #commit}
|
||||
* @param onCommit A function to call on commit
|
||||
* @param onCancel A function to call on cancel
|
||||
*/
|
||||
TransactionService.prototype.addToTransaction = function (onCommit, onCancel) {
|
||||
if (this.isActive()) {
|
||||
return this.activeTransaction().add(onCommit, onCancel);
|
||||
} else {
|
||||
//Log error because this is a programming error if it occurs.
|
||||
this.$log.error("No transaction in progress");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the transaction at the top of the stack.
|
||||
* @private
|
||||
*/
|
||||
TransactionService.prototype.activeTransaction = function () {
|
||||
return this.transactions[this.transactions.length - 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* All persist calls deferred since the beginning of the transaction
|
||||
* will be committed. If this is the last transaction, clears the
|
||||
* cache.
|
||||
*
|
||||
* @returns {Promise} resolved when all persist operations have
|
||||
* completed. Will reject if any commit operations fail
|
||||
*/
|
||||
TransactionService.prototype.commit = function () {
|
||||
var transaction = this.transactions.pop();
|
||||
if (!transaction) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
if (!this.isActive()) {
|
||||
return transaction.commit()
|
||||
.then(function (r) {
|
||||
this.cacheService.flush();
|
||||
|
||||
return r;
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
return transaction.commit();
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel the current transaction, replacing any dirty objects from
|
||||
* persistence. Not a true rollback, as it cannot be used to undo any
|
||||
* persist calls that were successful in the event one of a batch of
|
||||
* persists failing.
|
||||
*
|
||||
* @returns {*}
|
||||
*/
|
||||
TransactionService.prototype.cancel = function () {
|
||||
var transaction = this.transactions.pop();
|
||||
|
||||
return transaction ? transaction.cancel() : Promise.reject();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the size (the number of commit/cancel callbacks) of
|
||||
* the active transaction.
|
||||
* @returns {number} size of the active transaction
|
||||
*/
|
||||
TransactionService.prototype.size = function () {
|
||||
return this.isActive() ? this.activeTransaction().size() : 0;
|
||||
};
|
||||
|
||||
return TransactionService;
|
||||
});
|
@ -1,192 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(
|
||||
["../../src/capabilities/EditorCapability"],
|
||||
function (EditorCapability) {
|
||||
|
||||
xdescribe("The editor capability", function () {
|
||||
var mockDomainObject,
|
||||
capabilities,
|
||||
mockParentObject,
|
||||
mockTransactionService,
|
||||
mockStatusCapability,
|
||||
mockParentStatus,
|
||||
mockContextCapability,
|
||||
capability;
|
||||
|
||||
function fastPromise(val) {
|
||||
return {
|
||||
then: function (callback) {
|
||||
return callback(val);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getModel", "hasCapability", "getCapability", "useCapability"]
|
||||
);
|
||||
mockParentObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getModel", "hasCapability", "getCapability", "useCapability"]
|
||||
);
|
||||
mockTransactionService = jasmine.createSpyObj(
|
||||
"transactionService",
|
||||
[
|
||||
"startTransaction",
|
||||
"size",
|
||||
"commit",
|
||||
"cancel"
|
||||
]
|
||||
);
|
||||
mockTransactionService.commit.and.returnValue(fastPromise());
|
||||
mockTransactionService.cancel.and.returnValue(fastPromise());
|
||||
mockTransactionService.isActive = jasmine.createSpy('isActive');
|
||||
|
||||
mockStatusCapability = jasmine.createSpyObj(
|
||||
"statusCapability",
|
||||
["get", "set"]
|
||||
);
|
||||
mockParentStatus = jasmine.createSpyObj(
|
||||
"statusCapability",
|
||||
["get", "set"]
|
||||
);
|
||||
mockContextCapability = jasmine.createSpyObj(
|
||||
"contextCapability",
|
||||
["getParent"]
|
||||
);
|
||||
mockContextCapability.getParent.and.returnValue(mockParentObject);
|
||||
|
||||
capabilities = {
|
||||
context: mockContextCapability,
|
||||
status: mockStatusCapability
|
||||
};
|
||||
|
||||
mockDomainObject.hasCapability.and.callFake(function (name) {
|
||||
return capabilities[name] !== undefined;
|
||||
});
|
||||
|
||||
mockDomainObject.getCapability.and.callFake(function (name) {
|
||||
return capabilities[name];
|
||||
});
|
||||
|
||||
mockParentObject.getCapability.and.returnValue(mockParentStatus);
|
||||
mockParentObject.hasCapability.and.returnValue(false);
|
||||
|
||||
capability = new EditorCapability(
|
||||
mockTransactionService,
|
||||
mockDomainObject
|
||||
);
|
||||
});
|
||||
|
||||
it("starts a transaction when edit is invoked", function () {
|
||||
capability.edit();
|
||||
expect(mockTransactionService.startTransaction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sets editing status on object", function () {
|
||||
capability.edit();
|
||||
expect(mockStatusCapability.set).toHaveBeenCalledWith("editing", true);
|
||||
});
|
||||
|
||||
it("uses editing status to determine editing context root", function () {
|
||||
capability.edit();
|
||||
mockStatusCapability.get.and.returnValue(false);
|
||||
expect(capability.isEditContextRoot()).toBe(false);
|
||||
mockStatusCapability.get.and.returnValue(true);
|
||||
expect(capability.isEditContextRoot()).toBe(true);
|
||||
});
|
||||
|
||||
it("inEditingContext returns true if parent object is being"
|
||||
+ " edited", function () {
|
||||
mockStatusCapability.get.and.returnValue(false);
|
||||
mockParentStatus.get.and.returnValue(false);
|
||||
expect(capability.inEditContext()).toBe(false);
|
||||
mockParentStatus.get.and.returnValue(true);
|
||||
expect(capability.inEditContext()).toBe(true);
|
||||
});
|
||||
|
||||
describe("save", function () {
|
||||
beforeEach(function () {
|
||||
capability.edit();
|
||||
capability.save();
|
||||
});
|
||||
it("commits the transaction", function () {
|
||||
expect(mockTransactionService.commit).toHaveBeenCalled();
|
||||
});
|
||||
it("begins a new transaction", function () {
|
||||
expect(mockTransactionService.startTransaction).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("finish", function () {
|
||||
beforeEach(function () {
|
||||
mockTransactionService.isActive.and.returnValue(true);
|
||||
capability.edit();
|
||||
capability.finish();
|
||||
});
|
||||
it("cancels the transaction", function () {
|
||||
expect(mockTransactionService.cancel).toHaveBeenCalled();
|
||||
});
|
||||
it("resets the edit state", function () {
|
||||
expect(mockStatusCapability.set).toHaveBeenCalledWith('editing', false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("finish", function () {
|
||||
beforeEach(function () {
|
||||
mockTransactionService.isActive.and.returnValue(false);
|
||||
capability.edit();
|
||||
});
|
||||
|
||||
it("does not cancel transaction when transaction is not active", function () {
|
||||
capability.finish();
|
||||
expect(mockTransactionService.cancel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns a promise", function () {
|
||||
expect(capability.finish() instanceof Promise).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("dirty", function () {
|
||||
var model = {};
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObject.getModel.and.returnValue(model);
|
||||
capability.edit();
|
||||
capability.finish();
|
||||
});
|
||||
it("returns true if the object has been modified since it"
|
||||
+ " was last persisted", function () {
|
||||
mockTransactionService.size.and.returnValue(0);
|
||||
expect(capability.dirty()).toBe(false);
|
||||
mockTransactionService.size.and.returnValue(1);
|
||||
expect(capability.dirty()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -1,111 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(
|
||||
[
|
||||
"../../src/capabilities/TransactionalPersistenceCapability"
|
||||
],
|
||||
function (TransactionalPersistenceCapability) {
|
||||
|
||||
function fastPromise(val) {
|
||||
return {
|
||||
then: function (callback) {
|
||||
return callback(val);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("The transactional persistence decorator", function () {
|
||||
var mockQ,
|
||||
mockTransactionManager,
|
||||
mockPersistence,
|
||||
mockDomainObject,
|
||||
testId,
|
||||
capability;
|
||||
|
||||
beforeEach(function () {
|
||||
testId = "test-id";
|
||||
|
||||
mockQ = jasmine.createSpyObj("$q", ["when"]);
|
||||
mockQ.when.and.callFake(function (val) {
|
||||
return fastPromise(val);
|
||||
});
|
||||
mockTransactionManager = jasmine.createSpyObj(
|
||||
"transactionService",
|
||||
["isActive", "addToTransaction", "clearTransactionsFor"]
|
||||
);
|
||||
mockPersistence = jasmine.createSpyObj(
|
||||
"persistenceCapability",
|
||||
["persist", "refresh", "getSpace"]
|
||||
);
|
||||
mockPersistence.persist.and.returnValue(fastPromise());
|
||||
mockPersistence.refresh.and.returnValue(fastPromise());
|
||||
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getModel", "getId"]
|
||||
);
|
||||
mockDomainObject.getModel.and.returnValue({persisted: 1});
|
||||
mockDomainObject.getId.and.returnValue(testId);
|
||||
|
||||
capability = new TransactionalPersistenceCapability(
|
||||
mockQ,
|
||||
mockTransactionManager,
|
||||
mockPersistence,
|
||||
mockDomainObject
|
||||
);
|
||||
});
|
||||
|
||||
it("if no transaction is active, passes through to persistence"
|
||||
+ " provider", function () {
|
||||
mockTransactionManager.isActive.and.returnValue(false);
|
||||
capability.persist();
|
||||
expect(mockPersistence.persist).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("if transaction is active, persist and cancel calls are"
|
||||
+ " queued", function () {
|
||||
mockTransactionManager.isActive.and.returnValue(true);
|
||||
capability.persist();
|
||||
expect(mockTransactionManager.addToTransaction).toHaveBeenCalled();
|
||||
mockTransactionManager.addToTransaction.calls.mostRecent().args[1]();
|
||||
expect(mockPersistence.persist).toHaveBeenCalled();
|
||||
mockTransactionManager.addToTransaction.calls.mostRecent().args[2]();
|
||||
expect(mockPersistence.refresh).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("wraps getSpace", function () {
|
||||
mockPersistence.getSpace.and.returnValue('foo');
|
||||
expect(capability.getSpace()).toEqual('foo');
|
||||
});
|
||||
|
||||
it("clears transactions and delegates refresh calls", function () {
|
||||
capability.refresh();
|
||||
expect(mockTransactionManager.clearTransactionsFor)
|
||||
.toHaveBeenCalledWith(testId);
|
||||
expect(mockPersistence.refresh)
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -1,75 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(["../../src/services/NestedTransaction"], function (NestedTransaction) {
|
||||
var TRANSACTION_METHODS = ['add', 'commit', 'cancel', 'size'];
|
||||
|
||||
describe("A NestedTransaction", function () {
|
||||
var mockTransaction,
|
||||
nestedTransaction;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTransaction =
|
||||
jasmine.createSpyObj('transaction', TRANSACTION_METHODS);
|
||||
nestedTransaction = new NestedTransaction(mockTransaction);
|
||||
});
|
||||
|
||||
it("exposes a Transaction's interface", function () {
|
||||
TRANSACTION_METHODS.forEach(function (method) {
|
||||
expect(nestedTransaction[method])
|
||||
.toEqual(jasmine.any(Function));
|
||||
});
|
||||
});
|
||||
|
||||
describe("when callbacks are added", function () {
|
||||
var mockCommit,
|
||||
mockCancel;
|
||||
|
||||
beforeEach(function () {
|
||||
mockCommit = jasmine.createSpy('commit');
|
||||
mockCancel = jasmine.createSpy('cancel');
|
||||
nestedTransaction.add(mockCommit, mockCancel);
|
||||
});
|
||||
|
||||
it("does not interact with its parent transaction", function () {
|
||||
TRANSACTION_METHODS.forEach(function (method) {
|
||||
expect(mockTransaction[method])
|
||||
.not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("and the transaction is committed", function () {
|
||||
beforeEach(function () {
|
||||
nestedTransaction.commit();
|
||||
});
|
||||
|
||||
it("adds to its parent transaction", function () {
|
||||
expect(mockTransaction.add).toHaveBeenCalledWith(
|
||||
jasmine.any(Function),
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,141 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(
|
||||
["../../src/services/TransactionManager"],
|
||||
function (TransactionManager) {
|
||||
describe("TransactionManager", function () {
|
||||
var mockTransactionService,
|
||||
testId,
|
||||
mockOnCommit,
|
||||
mockOnCancel,
|
||||
mockRemoves,
|
||||
mockPromise,
|
||||
manager;
|
||||
|
||||
beforeEach(function () {
|
||||
mockRemoves = [];
|
||||
mockTransactionService = jasmine.createSpyObj(
|
||||
"transactionService",
|
||||
["addToTransaction", "isActive"]
|
||||
);
|
||||
mockOnCommit = jasmine.createSpy('commit');
|
||||
mockOnCancel = jasmine.createSpy('cancel');
|
||||
testId = 'test-id';
|
||||
mockPromise = jasmine.createSpyObj('promise', ['then']);
|
||||
|
||||
mockOnCommit.and.returnValue(mockPromise);
|
||||
mockOnCancel.and.returnValue(mockPromise);
|
||||
|
||||
mockTransactionService.addToTransaction.and.callFake(function () {
|
||||
var mockRemove =
|
||||
jasmine.createSpy('remove-' + mockRemoves.length);
|
||||
mockRemoves.push(mockRemove);
|
||||
|
||||
return mockRemove;
|
||||
});
|
||||
|
||||
manager = new TransactionManager(mockTransactionService);
|
||||
});
|
||||
|
||||
it("delegates isActive calls", function () {
|
||||
[false, true].forEach(function (state) {
|
||||
mockTransactionService.isActive.and.returnValue(state);
|
||||
expect(manager.isActive()).toBe(state);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when addToTransaction is called", function () {
|
||||
beforeEach(function () {
|
||||
manager.addToTransaction(
|
||||
testId,
|
||||
mockOnCommit,
|
||||
mockOnCancel
|
||||
);
|
||||
});
|
||||
|
||||
it("adds callbacks to the active transaction", function () {
|
||||
expect(mockTransactionService.addToTransaction)
|
||||
.toHaveBeenCalledWith(
|
||||
jasmine.any(Function),
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("invokes passed-in callbacks from its own callbacks", function () {
|
||||
expect(mockOnCommit).not.toHaveBeenCalled();
|
||||
mockTransactionService.addToTransaction
|
||||
.calls.mostRecent().args[0]();
|
||||
expect(mockOnCommit).toHaveBeenCalled();
|
||||
|
||||
expect(mockOnCancel).not.toHaveBeenCalled();
|
||||
mockTransactionService.addToTransaction
|
||||
.calls.mostRecent().args[1]();
|
||||
expect(mockOnCancel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("Adds callbacks to transaction", function () {
|
||||
beforeEach(function () {
|
||||
spyOn(manager, 'clearTransactionsFor');
|
||||
manager.clearTransactionsFor.and.callThrough();
|
||||
});
|
||||
|
||||
it("and clears pending calls if same object", function () {
|
||||
manager.addToTransaction(
|
||||
testId,
|
||||
jasmine.createSpy(),
|
||||
jasmine.createSpy()
|
||||
);
|
||||
expect(manager.clearTransactionsFor).toHaveBeenCalledWith(testId);
|
||||
});
|
||||
|
||||
it("and does not clear pending calls if different object", function () {
|
||||
manager.addToTransaction(
|
||||
'other-id',
|
||||
jasmine.createSpy(),
|
||||
jasmine.createSpy()
|
||||
);
|
||||
expect(manager.clearTransactionsFor).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
expect(mockTransactionService.addToTransaction.calls.count()).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
it("does not remove callbacks from the transaction", function () {
|
||||
expect(mockRemoves[0]).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("and clearTransactionsFor is subsequently called", function () {
|
||||
beforeEach(function () {
|
||||
manager.clearTransactionsFor(testId);
|
||||
});
|
||||
|
||||
it("removes callbacks from the transaction", function () {
|
||||
expect(mockRemoves[0]).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -1,139 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(
|
||||
["../../src/services/TransactionService"],
|
||||
function (TransactionService) {
|
||||
|
||||
describe("The Transaction Service", function () {
|
||||
var mockQ,
|
||||
mockLog,
|
||||
mockCacheService,
|
||||
transactionService;
|
||||
|
||||
function fastPromise(val) {
|
||||
return {
|
||||
then: function (callback) {
|
||||
return fastPromise(callback(val));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockQ = jasmine.createSpyObj("$q", ["all"]);
|
||||
mockCacheService = jasmine.createSpyObj("cacheService", ["flush"]);
|
||||
mockQ.all.and.returnValue(fastPromise());
|
||||
mockLog = jasmine.createSpyObj("$log", ["error"]);
|
||||
transactionService = new TransactionService(mockQ, mockLog, mockCacheService);
|
||||
});
|
||||
|
||||
it("isActive returns true if a transaction is in progress", function () {
|
||||
expect(transactionService.isActive()).toBe(false);
|
||||
transactionService.startTransaction();
|
||||
expect(transactionService.isActive()).toBe(true);
|
||||
});
|
||||
|
||||
it("addToTransaction queues onCommit and onCancel functions", function () {
|
||||
var onCommit = jasmine.createSpy('onCommit'),
|
||||
onCancel = jasmine.createSpy('onCancel');
|
||||
|
||||
transactionService.startTransaction();
|
||||
transactionService.addToTransaction(onCommit, onCancel);
|
||||
expect(transactionService.size()).toBe(1);
|
||||
});
|
||||
|
||||
it("size function returns size of commit and cancel queues", function () {
|
||||
var onCommit = jasmine.createSpy('onCommit'),
|
||||
onCancel = jasmine.createSpy('onCancel');
|
||||
|
||||
transactionService.startTransaction();
|
||||
transactionService.addToTransaction(onCommit, onCancel);
|
||||
transactionService.addToTransaction(onCommit, onCancel);
|
||||
transactionService.addToTransaction(onCommit, onCancel);
|
||||
expect(transactionService.size()).toBe(3);
|
||||
});
|
||||
|
||||
describe("commit", function () {
|
||||
var onCommits;
|
||||
|
||||
beforeEach(function () {
|
||||
onCommits = [0, 1, 2].map(function (val) {
|
||||
return jasmine.createSpy("onCommit" + val);
|
||||
});
|
||||
|
||||
transactionService.startTransaction();
|
||||
onCommits.forEach(transactionService.addToTransaction.bind(transactionService));
|
||||
});
|
||||
|
||||
it("commit calls all queued commit functions", function () {
|
||||
expect(transactionService.size()).toBe(3);
|
||||
|
||||
return transactionService.commit().then(() => {
|
||||
onCommits.forEach(function (spy) {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("commit resets active state and clears queues", function () {
|
||||
return transactionService.commit().then(() => {
|
||||
expect(transactionService.isActive()).toBe(false);
|
||||
expect(transactionService.size()).toBe(0);
|
||||
expect(transactionService.size()).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("cancel", function () {
|
||||
var onCancels;
|
||||
|
||||
beforeEach(function () {
|
||||
onCancels = [0, 1, 2].map(function (val) {
|
||||
return jasmine.createSpy("onCancel" + val);
|
||||
});
|
||||
|
||||
transactionService.startTransaction();
|
||||
onCancels.forEach(function (onCancel) {
|
||||
transactionService.addToTransaction(undefined, onCancel);
|
||||
});
|
||||
});
|
||||
|
||||
it("cancel calls all queued cancel functions", function () {
|
||||
expect(transactionService.size()).toBe(3);
|
||||
transactionService.cancel();
|
||||
onCancels.forEach(function (spy) {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("cancel resets active state and clears queues", function () {
|
||||
transactionService.cancel();
|
||||
expect(transactionService.isActive()).toBe(false);
|
||||
expect(transactionService.size()).toBe(0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -1,109 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(
|
||||
["../../src/services/Transaction"],
|
||||
function (Transaction) {
|
||||
|
||||
describe("A Transaction", function () {
|
||||
var mockLog,
|
||||
transaction;
|
||||
|
||||
beforeEach(function () {
|
||||
mockLog = jasmine.createSpyObj(
|
||||
'$log',
|
||||
['warn', 'info', 'error', 'debug']
|
||||
);
|
||||
transaction = new Transaction(mockLog);
|
||||
});
|
||||
|
||||
it("initially has a size of zero", function () {
|
||||
expect(transaction.size()).toEqual(0);
|
||||
});
|
||||
|
||||
describe("when callbacks are added", function () {
|
||||
var mockCommit,
|
||||
mockCancel,
|
||||
remove;
|
||||
|
||||
beforeEach(function () {
|
||||
mockCommit = jasmine.createSpy('commit');
|
||||
mockCancel = jasmine.createSpy('cancel');
|
||||
remove = transaction.add(mockCommit, mockCancel);
|
||||
});
|
||||
|
||||
it("reports a new size", function () {
|
||||
expect(transaction.size()).toEqual(1);
|
||||
});
|
||||
|
||||
it("returns a function to remove those callbacks", function () {
|
||||
expect(remove).toEqual(jasmine.any(Function));
|
||||
remove();
|
||||
expect(transaction.size()).toEqual(0);
|
||||
});
|
||||
|
||||
describe("and the transaction is committed", function () {
|
||||
beforeEach(function () {
|
||||
transaction.commit();
|
||||
});
|
||||
|
||||
it("triggers the commit callback", function () {
|
||||
expect(mockCommit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not trigger the cancel callback", function () {
|
||||
expect(mockCancel).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("and the transaction is cancelled", function () {
|
||||
beforeEach(function () {
|
||||
transaction.cancel();
|
||||
});
|
||||
|
||||
it("triggers the cancel callback", function () {
|
||||
expect(mockCancel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not trigger the commit callback", function () {
|
||||
expect(mockCommit).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("and an exception is encountered during commit", function () {
|
||||
beforeEach(function () {
|
||||
mockCommit.and.callFake(function () {
|
||||
throw new Error("test error");
|
||||
});
|
||||
transaction.commit();
|
||||
});
|
||||
|
||||
it("logs an error", function () {
|
||||
expect(mockLog.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -45,7 +45,6 @@ define([
|
||||
"./src/capabilities/MutationCapability",
|
||||
"./src/capabilities/DelegationCapability",
|
||||
"./src/capabilities/InstantiationCapability",
|
||||
"./src/runs/TransactingMutationListener",
|
||||
"./src/services/Now",
|
||||
"./src/services/Throttle",
|
||||
"./src/services/Topic",
|
||||
@ -75,7 +74,6 @@ define([
|
||||
MutationCapability,
|
||||
DelegationCapability,
|
||||
InstantiationCapability,
|
||||
TransactingMutationListener,
|
||||
Now,
|
||||
Throttle,
|
||||
Topic,
|
||||
@ -363,12 +361,6 @@ define([
|
||||
]
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"implementation": TransactingMutationListener,
|
||||
"depends": ["topic", "transactionService", "cacheService"]
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
"key": "PERSISTENCE_SPACE",
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT Web includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([], function () {
|
||||
|
||||
/**
|
||||
* Listens for mutation on domain objects and triggers persistence when
|
||||
* it occurs.
|
||||
* @param {Topic} topic the `topic` service; used to listen for mutation
|
||||
* @memberof platform/core
|
||||
*/
|
||||
function TransactingMutationListener(
|
||||
topic,
|
||||
transactionService,
|
||||
cacheService
|
||||
) {
|
||||
|
||||
function hasChanged(domainObject) {
|
||||
var model = domainObject.getModel();
|
||||
|
||||
return model.persisted === undefined || model.modified > model.persisted;
|
||||
}
|
||||
|
||||
var mutationTopic = topic('mutation');
|
||||
mutationTopic.listen(function (domainObject) {
|
||||
var persistence = domainObject.getCapability('persistence');
|
||||
cacheService.put(domainObject.getId(), domainObject.getModel());
|
||||
|
||||
if (hasChanged(domainObject)) {
|
||||
persistence.persist();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return TransactingMutationListener;
|
||||
});
|
@ -1,112 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, 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(
|
||||
["../../src/runs/TransactingMutationListener"],
|
||||
function (TransactingMutationListener) {
|
||||
|
||||
describe("TransactingMutationListener", function () {
|
||||
var mockTopic,
|
||||
mockMutationTopic,
|
||||
mockCacheService,
|
||||
mockTransactionService,
|
||||
mockDomainObject,
|
||||
mockModel,
|
||||
mockPersistence;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTopic = jasmine.createSpy('topic');
|
||||
mockMutationTopic =
|
||||
jasmine.createSpyObj('mutation', ['listen']);
|
||||
mockCacheService =
|
||||
jasmine.createSpyObj('cacheService', [
|
||||
'put'
|
||||
]);
|
||||
mockTransactionService =
|
||||
jasmine.createSpyObj('transactionService', [
|
||||
'isActive',
|
||||
'startTransaction',
|
||||
'commit'
|
||||
]);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
'domainObject',
|
||||
['getId', 'getCapability', 'getModel']
|
||||
);
|
||||
mockPersistence = jasmine.createSpyObj(
|
||||
'persistence',
|
||||
['persist', 'refresh', 'persisted']
|
||||
);
|
||||
|
||||
mockTopic.and.callFake(function (t) {
|
||||
expect(t).toBe('mutation');
|
||||
|
||||
return mockMutationTopic;
|
||||
});
|
||||
|
||||
mockDomainObject.getId.and.returnValue('mockId');
|
||||
mockDomainObject.getCapability.and.callFake(function (c) {
|
||||
expect(c).toBe('persistence');
|
||||
|
||||
return mockPersistence;
|
||||
});
|
||||
mockModel = {};
|
||||
mockDomainObject.getModel.and.returnValue(mockModel);
|
||||
|
||||
mockPersistence.persisted.and.returnValue(true);
|
||||
|
||||
return new TransactingMutationListener(
|
||||
mockTopic,
|
||||
mockTransactionService,
|
||||
mockCacheService
|
||||
);
|
||||
});
|
||||
|
||||
it("listens for mutation", function () {
|
||||
expect(mockMutationTopic.listen)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("calls persist if the model has changed", function () {
|
||||
mockModel.persisted = Date.now();
|
||||
|
||||
//Mark the model dirty by setting the mutated date later than the last persisted date.
|
||||
mockModel.modified = mockModel.persisted + 1;
|
||||
|
||||
mockMutationTopic.listen.calls.mostRecent()
|
||||
.args[0](mockDomainObject);
|
||||
|
||||
expect(mockPersistence.persist).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not call persist if the model has not changed", function () {
|
||||
mockModel.persisted = Date.now();
|
||||
|
||||
mockModel.modified = mockModel.persisted;
|
||||
|
||||
mockMutationTopic.listen.calls.mostRecent()
|
||||
.args[0](mockDomainObject);
|
||||
|
||||
expect(mockPersistence.persist).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -34,7 +34,6 @@ export default class Editor extends EventEmitter {
|
||||
* Initiate an editing session. This will start a transaction during
|
||||
* which any persist operations will be deferred until either save()
|
||||
* or finish() are called.
|
||||
* @private
|
||||
*/
|
||||
edit() {
|
||||
if (this.editing === true) {
|
||||
@ -42,8 +41,8 @@ export default class Editor extends EventEmitter {
|
||||
}
|
||||
|
||||
this.editing = true;
|
||||
this.getTransactionService().startTransaction();
|
||||
this.emit('isEditing', true);
|
||||
this.openmct.objects.startTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,41 +55,36 @@ export default class Editor extends EventEmitter {
|
||||
/**
|
||||
* Save any unsaved changes from this editing session. This will
|
||||
* end the current transaction.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
save() {
|
||||
return this.getTransactionService().commit().then((result) => {
|
||||
this.editing = false;
|
||||
this.emit('isEditing', false);
|
||||
const transaction = this.openmct.objects.getActiveTransaction();
|
||||
|
||||
return result;
|
||||
}).catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
return transaction.commit()
|
||||
.then(() => {
|
||||
this.editing = false;
|
||||
this.emit('isEditing', false);
|
||||
}).catch(error => {
|
||||
throw error;
|
||||
}).finally(() => {
|
||||
this.openmct.objects.endTransaction();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* End the currently active transaction and discard unsaved changes.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
cancel() {
|
||||
let cancelPromise = this.getTransactionService().cancel();
|
||||
this.editing = false;
|
||||
this.emit('isEditing', false);
|
||||
|
||||
return cancelPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
getTransactionService() {
|
||||
if (!this.transactionService) {
|
||||
this.transactionService = this.openmct.$injector.get('transactionService');
|
||||
}
|
||||
|
||||
return this.transactionService;
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = this.openmct.objects.getActiveTransaction();
|
||||
transaction.cancel()
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.finally(() => {
|
||||
this.openmct.objects.endTransaction();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -129,9 +129,7 @@ class MutableDomainObject {
|
||||
|
||||
mutable.$observe('$_synchronize_model', (updatedObject) => {
|
||||
let clone = JSON.parse(JSON.stringify(updatedObject));
|
||||
let deleted = _.difference(Object.keys(mutable), Object.keys(updatedObject));
|
||||
deleted.forEach((propertyName) => delete mutable[propertyName]);
|
||||
Object.assign(mutable, clone);
|
||||
utils.refresh(mutable, clone);
|
||||
});
|
||||
|
||||
return mutable;
|
||||
|
@ -26,6 +26,7 @@ import RootRegistry from './RootRegistry';
|
||||
import RootObjectProvider from './RootObjectProvider';
|
||||
import EventEmitter from 'EventEmitter';
|
||||
import InterceptorRegistry from './InterceptorRegistry';
|
||||
import Transaction from './Transaction';
|
||||
|
||||
/**
|
||||
* Utilities for loading, saving, and manipulating domain objects.
|
||||
@ -34,12 +35,14 @@ import InterceptorRegistry from './InterceptorRegistry';
|
||||
*/
|
||||
|
||||
function ObjectAPI(typeRegistry, openmct) {
|
||||
this.openmct = openmct;
|
||||
|
||||
this.typeRegistry = typeRegistry;
|
||||
this.eventEmitter = new EventEmitter();
|
||||
this.providers = {};
|
||||
this.rootRegistry = new RootRegistry();
|
||||
this.injectIdentifierService = function () {
|
||||
this.identifierService = openmct.$injector.get("identifierService");
|
||||
this.identifierService = this.openmct.$injector.get("identifierService");
|
||||
};
|
||||
|
||||
this.rootProvider = new RootObjectProvider(this.rootRegistry);
|
||||
@ -86,6 +89,14 @@ ObjectAPI.prototype.getProvider = function (identifier) {
|
||||
return this.providers[namespace] || this.fallbackProvider;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an active transaction instance
|
||||
* @returns {Transaction} a transaction object
|
||||
*/
|
||||
ObjectAPI.prototype.getActiveTransaction = function () {
|
||||
return this.transaction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the root-level object.
|
||||
* @returns {Promise.<DomainObject>} a promise for the root object
|
||||
@ -323,6 +334,24 @@ ObjectAPI.prototype.save = function (domainObject) {
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* After entering into edit mode, creates a new instance of Transaction to keep track of changes in Objects
|
||||
*/
|
||||
ObjectAPI.prototype.startTransaction = function () {
|
||||
if (this.isTransactionActive()) {
|
||||
throw new Error("Unable to start new Transaction: Previous Transaction is active");
|
||||
}
|
||||
|
||||
this.transaction = new Transaction(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear instance of Transaction
|
||||
*/
|
||||
ObjectAPI.prototype.endTransaction = function () {
|
||||
this.transaction = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a root-level object.
|
||||
* @param {module:openmct.ObjectAPI~Identifier|function} an array of
|
||||
@ -412,6 +441,12 @@ ObjectAPI.prototype.mutate = function (domainObject, path, value) {
|
||||
//Destroy temporary mutable object
|
||||
this.destroyMutable(mutableDomainObject);
|
||||
}
|
||||
|
||||
if (this.isTransactionActive()) {
|
||||
this.transaction.add(domainObject);
|
||||
} else {
|
||||
this.save(domainObject);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -448,6 +483,23 @@ ObjectAPI.prototype._toMutable = function (object) {
|
||||
return mutableObject;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates a domain object based on its latest persisted state. Note that this will mutate the provided object.
|
||||
* @param {module:openmct.DomainObject} domainObject an object to refresh from its persistence store
|
||||
* @returns {Promise} the provided object, updated to reflect the latest persisted state of the object.
|
||||
*/
|
||||
ObjectAPI.prototype.refresh = async function (domainObject) {
|
||||
const refreshedObject = await this.get(domainObject.identifier);
|
||||
|
||||
if (domainObject.isMutable) {
|
||||
domainObject.$refresh(refreshedObject);
|
||||
} else {
|
||||
utils.refresh(domainObject, refreshedObject);
|
||||
}
|
||||
|
||||
return domainObject;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param module:openmct.ObjectAPI~Identifier identifier An object identifier
|
||||
* @returns {boolean} true if the object can be mutated, otherwise returns false
|
||||
@ -524,6 +576,10 @@ ObjectAPI.prototype.isObjectPathToALink = function (domainObject, objectPath) {
|
||||
&& domainObject.location !== this.makeKeyString(objectPath[1].identifier);
|
||||
};
|
||||
|
||||
ObjectAPI.prototype.isTransactionActive = function () {
|
||||
return Boolean(this.transaction && this.openmct.editor.isEditing());
|
||||
};
|
||||
|
||||
/**
|
||||
* Uniquely identifies a domain object.
|
||||
*
|
||||
|
@ -26,6 +26,10 @@ describe("The Object API", () => {
|
||||
|
||||
openmct.$injector.get.and.returnValue(mockIdentifierService);
|
||||
objectAPI = new ObjectAPI(typeRegistry, openmct);
|
||||
|
||||
openmct.editor = {};
|
||||
openmct.editor.isEditing = () => false;
|
||||
|
||||
mockDomainObject = {
|
||||
identifier: {
|
||||
namespace: TEST_NAMESPACE,
|
||||
@ -223,6 +227,28 @@ describe("The Object API", () => {
|
||||
expect(testObject.name).toBe(MUTATED_NAME);
|
||||
});
|
||||
|
||||
it('Provides a way of refreshing an object from the persistence store', () => {
|
||||
const modifiedTestObject = JSON.parse(JSON.stringify(testObject));
|
||||
const OTHER_ATTRIBUTE_VALUE = 'Modified value';
|
||||
const NEW_ATTRIBUTE_VALUE = 'A new attribute';
|
||||
modifiedTestObject.otherAttribute = OTHER_ATTRIBUTE_VALUE;
|
||||
modifiedTestObject.newAttribute = NEW_ATTRIBUTE_VALUE;
|
||||
delete modifiedTestObject.objectAttribute;
|
||||
|
||||
spyOn(objectAPI, 'get');
|
||||
objectAPI.get.and.returnValue(Promise.resolve(modifiedTestObject));
|
||||
|
||||
expect(objectAPI.get).not.toHaveBeenCalled();
|
||||
|
||||
return objectAPI.refresh(testObject).then(() => {
|
||||
expect(objectAPI.get).toHaveBeenCalledWith(testObject.identifier);
|
||||
|
||||
expect(testObject.otherAttribute).toEqual(OTHER_ATTRIBUTE_VALUE);
|
||||
expect(testObject.newAttribute).toEqual(NEW_ATTRIBUTE_VALUE);
|
||||
expect(testObject.objectAttribute).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe ('uses a MutableDomainObject', () => {
|
||||
it('and retains properties of original object ', function () {
|
||||
expect(hasOwnProperty(mutable, 'identifier')).toBe(true);
|
||||
|
@ -20,35 +20,52 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
"../../src/capabilities/TransactionalPersistenceCapability",
|
||||
"../../src/capabilities/TransactionCapabilityDecorator"
|
||||
],
|
||||
function (TransactionalPersistenceCapability, TransactionCapabilityDecorator) {
|
||||
export default class Transaction {
|
||||
constructor(objectAPI) {
|
||||
this.dirtyObjects = new Set();
|
||||
this.objectAPI = objectAPI;
|
||||
}
|
||||
|
||||
describe("The transaction capability decorator", function () {
|
||||
var mockQ,
|
||||
mockTransactionService,
|
||||
mockCapabilityService,
|
||||
provider;
|
||||
add(object) {
|
||||
this.dirtyObjects.add(object);
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockQ = {};
|
||||
mockTransactionService = {};
|
||||
mockCapabilityService = jasmine.createSpyObj("capabilityService", ["getCapabilities"]);
|
||||
mockCapabilityService.getCapabilities.and.returnValue({
|
||||
persistence: function () {}
|
||||
cancel() {
|
||||
return this._clear();
|
||||
}
|
||||
|
||||
commit() {
|
||||
const promiseArray = [];
|
||||
const save = this.objectAPI.save.bind(this.objectAPI);
|
||||
this.dirtyObjects.forEach(object => {
|
||||
promiseArray.push(this.createDirtyObjectPromise(object, save));
|
||||
});
|
||||
|
||||
return Promise.all(promiseArray);
|
||||
}
|
||||
|
||||
createDirtyObjectPromise(object, action) {
|
||||
return new Promise((resolve, reject) => {
|
||||
action(object)
|
||||
.then(resolve)
|
||||
.catch(reject)
|
||||
.finally(() => {
|
||||
this.dirtyObjects.delete(object);
|
||||
});
|
||||
|
||||
provider = new TransactionCapabilityDecorator(mockQ, mockTransactionService, mockCapabilityService);
|
||||
|
||||
});
|
||||
it("decorates the persistence capability", function () {
|
||||
var capabilities = provider.getCapabilities();
|
||||
expect(capabilities.persistence({}) instanceof TransactionalPersistenceCapability).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
start() {
|
||||
this.dirtyObjects = new Set();
|
||||
}
|
||||
|
||||
_clear() {
|
||||
const promiseArray = [];
|
||||
const refresh = this.objectAPI.refresh.bind(this.objectAPI);
|
||||
this.dirtyObjects.forEach(object => {
|
||||
promiseArray.push(this.createDirtyObjectPromise(object, refresh));
|
||||
});
|
||||
|
||||
return Promise.all(promiseArray);
|
||||
}
|
||||
}
|
@ -165,12 +165,19 @@ define([
|
||||
return identifierEquals(a.identifier, b.identifier);
|
||||
}
|
||||
|
||||
function refresh(oldObject, newObject) {
|
||||
let deleted = _.difference(Object.keys(oldObject), Object.keys(newObject));
|
||||
deleted.forEach((propertyName) => delete oldObject[propertyName]);
|
||||
Object.assign(oldObject, newObject);
|
||||
}
|
||||
|
||||
return {
|
||||
toOldFormat: toOldFormat,
|
||||
toNewFormat: toNewFormat,
|
||||
makeKeyString: makeKeyString,
|
||||
parseKeyString: parseKeyString,
|
||||
equals: objectEquals,
|
||||
identifierEquals: identifierEquals
|
||||
identifierEquals: identifierEquals,
|
||||
refresh: refresh
|
||||
};
|
||||
});
|
||||
|
@ -148,10 +148,14 @@ describe("Notebook plugin:", () => {
|
||||
'observe'
|
||||
]);
|
||||
|
||||
openmct.editor = {};
|
||||
openmct.editor.isEditing = () => false;
|
||||
|
||||
const applicableViews = openmct.objectViews.get(notebookViewObject, [notebookViewObject]);
|
||||
notebookViewProvider = applicableViews.find(viewProvider => viewProvider.key === 'notebook-vue');
|
||||
|
||||
testObjectProvider.get.and.returnValue(Promise.resolve(notebookViewObject));
|
||||
testObjectProvider.create.and.returnValue(Promise.resolve(notebookViewObject));
|
||||
openmct.objects.addProvider('test-namespace', testObjectProvider);
|
||||
testObjectProvider.observe.and.returnValue(() => {});
|
||||
|
||||
|
@ -110,8 +110,7 @@ export default class Snapshot {
|
||||
}
|
||||
|
||||
return () => {
|
||||
const path = window.location.href.split('#');
|
||||
window.location.href = path[0] + url;
|
||||
window.location.href = window.location.origin + url;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ const notebookDomainObject = {
|
||||
namespace: ''
|
||||
},
|
||||
type: 'notebook',
|
||||
name: 'Test Notebook',
|
||||
configuration: {
|
||||
defaultSort: 'oldest',
|
||||
entries: notebookEntries,
|
||||
@ -118,6 +119,12 @@ describe('Notebook Entries:', () => {
|
||||
'create',
|
||||
'update'
|
||||
]));
|
||||
openmct.editor = {
|
||||
isEditing: () => false
|
||||
};
|
||||
openmct.objects.isPersistable = () => true;
|
||||
openmct.objects.save = () => Promise.resolve(true);
|
||||
|
||||
window.localStorage.setItem('notebook-storage', null);
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user