Compare commits

..

2 Commits

Author SHA1 Message Date
Andrew Henry
d026a67ac0 Update on sort 2019-02-26 13:08:41 -08:00
Andrew Henry
78018628ce Remove slice operation 2019-02-26 09:16:37 -08:00
415 changed files with 22897 additions and 13134 deletions

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="DialogLaunchController"> <span class="h-indicator" ng-controller="DialogLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! --> <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="c-indicator c-indicator--clickable icon-box-with-arrow s-status-available"><span class="label c-indicator__label"> <div class="ls-indicator icon-box-with-arrow s-status-available"><span class="label">
<button ng-click="launchProgress(true)">Known</button> <a ng-click="launchProgress(true)">Known</a>
<button ng-click="launchProgress(false)">Unknown</button> <a ng-click="launchProgress(false)">Unknown</a>
<button ng-click="launchError()">Error</button> <a ng-click="launchError()">Error</a>
<button ng-click="launchInfo()">Info</button> <a ng-click="launchInfo()">Info</a>
</span></div> </span></div>
</span> </span>

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="NotificationLaunchController"> <span class="h-indicator" ng-controller="NotificationLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! --> <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="c-indicator c-indicator--clickable icon-bell s-status-available"><span class="label c-indicator__label"> <div class="ls-indicator icon-bell s-status-available"><span class="label">
<button ng-click="newInfo()">Success</button> <a ng-click="newInfo()">Success</a>
<button ng-click="newError()">Error</button> <a ng-click="newError()">Error</a>
<button ng-click="newAlert()">Alert</button> <a ng-click="newAlert()">Alert</a>
<button ng-click="newProgress()">Progress</button> <a ng-click="newProgress()">Progress</a>
</span></div> </span></div>
</span> </span>

View File

@@ -27,9 +27,11 @@
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<title></title> <title></title>
<script src="dist/openmct.js"></script> <script src="dist/openmct.js"></script>
<link rel="icon" type="image/png" href="dist/favicons/favicon-96x96.png" sizes="96x96" type="image/x-icon"> <link rel="stylesheet" href="dist/openmct.css">
<link rel="icon" type="image/png" href="dist/favicons/favicon-32x32.png" sizes="32x32" type="image/x-icon"> <link rel="icon" type="image/png" href="dist/favicons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="dist/favicons/favicon-16x16.png" sizes="16x16" type="image/x-icon"> <link rel="icon" type="image/png" href="dist/favicons/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="dist/favicons/favicon-16x16.png" sizes="16x16">
<link rel="shortcut icon" href="dist/favicons/favicon.ico">
</head> </head>
<body> <body>
</body> </body>
@@ -48,12 +50,10 @@
openmct.install(openmct.plugins.Generator()); openmct.install(openmct.plugins.Generator());
openmct.install(openmct.plugins.ExampleImagery()); openmct.install(openmct.plugins.ExampleImagery());
openmct.install(openmct.plugins.UTCTimeSystem()); openmct.install(openmct.plugins.UTCTimeSystem());
openmct.install(openmct.plugins.ImportExport());
openmct.install(openmct.plugins.AutoflowView({ openmct.install(openmct.plugins.AutoflowView({
type: "telemetry.panel" type: "telemetry.panel"
})); }));
openmct.install(openmct.plugins.DisplayLayout({
showAsView: ['summary-widget', 'example.imagery']
}));
openmct.install(openmct.plugins.Conductor({ openmct.install(openmct.plugins.Conductor({
menuOptions: [ menuOptions: [
{ {
@@ -77,10 +77,10 @@
})); }));
openmct.install(openmct.plugins.SummaryWidget()); openmct.install(openmct.plugins.SummaryWidget());
openmct.install(openmct.plugins.Notebook()); openmct.install(openmct.plugins.Notebook());
openmct.install(openmct.plugins.FolderView());
openmct.install(openmct.plugins.Tabs());
openmct.install(openmct.plugins.FlexibleLayout());
openmct.install(openmct.plugins.LADTable()); openmct.install(openmct.plugins.LADTable());
openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay']));
openmct.install(openmct.plugins.ObjectMigration());
openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked']));
openmct.start(); openmct.start();
</script> </script>
</html> </html>

View File

@@ -23,9 +23,9 @@
/*global module,process*/ /*global module,process*/
const devMode = process.env.NODE_ENV !== 'production'; const devMode = process.env.NODE_ENV !== 'production';
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless'];
module.exports = (config) => { module.exports = (config) => {
const webpackConfig = require('./webpack.config.js'); const webpackConfig = require('./webpack.config.js');
delete webpackConfig.output; delete webpackConfig.output;
@@ -50,17 +50,11 @@ module.exports = (config) => {
'coverage', 'coverage',
'html' 'html'
], ],
browsers: browsers, browsers: ['ChromeHeadless'],
customLaunchers: {
ChromeDebugging: {
base: 'Chrome',
flags: ['--remote-debugging-port=9222'],
debug: true
}
},
colors: true, colors: true,
logLevel: config.LOG_INFO, logLevel: config.LOG_INFO,
autoWatch: true, autoWatch: true,
coverageReporter: { coverageReporter: {
dir: process.env.CIRCLE_ARTIFACTS ? dir: process.env.CIRCLE_ARTIFACTS ?
process.env.CIRCLE_ARTIFACTS + '/coverage' : process.env.CIRCLE_ARTIFACTS + '/coverage' :
@@ -72,18 +66,22 @@ module.exports = (config) => {
} }
} }
}, },
// HTML test reporting. // HTML test reporting.
htmlReporter: { htmlReporter: {
outputDir: "dist/reports/tests", outputDir: "dist/reports/tests",
preserveDescribeNesting: true, preserveDescribeNesting: true,
foldAll: false foldAll: false
}, },
preprocessors: { preprocessors: {
// add webpack as preprocessor // add webpack as preprocessor
'platform/**/*Spec.js': [ 'webpack', 'sourcemap' ], 'platform/**/*Spec.js': [ 'webpack' ],
'src/**/*Spec.js': [ 'webpack', 'sourcemap' ] 'src/**/*Spec.js': [ 'webpack' ]
}, },
webpack: webpackConfig, webpack: webpackConfig,
webpackMiddleware: { webpackMiddleware: {
stats: 'errors-only', stats: 'errors-only',
logLevel: 'warn' logLevel: 'warn'
@@ -91,3 +89,4 @@ module.exports = (config) => {
singleRun: true singleRun: true
}); });
} }

View File

@@ -19,7 +19,7 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
/*global module*/ /*global module,BUILD_CONSTANTS*/
const matcher = /\/openmct.js$/; const matcher = /\/openmct.js$/;
if (document.currentScript) { if (document.currentScript) {

View File

@@ -1,10 +1,9 @@
{ {
"name": "openmct", "name": "openmct",
"version": "1.0.0-beta", "version": "0.14.0-SNAPSHOT",
"description": "The Open MCT core platform", "description": "The Open MCT core platform",
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"acorn": "6.2.0",
"angular": "1.4.14", "angular": "1.4.14",
"angular-route": "1.4.14", "angular-route": "1.4.14",
"babel-eslint": "8.2.6", "babel-eslint": "8.2.6",
@@ -26,7 +25,7 @@
"eventemitter3": "^1.2.0", "eventemitter3": "^1.2.0",
"exports-loader": "^0.7.0", "exports-loader": "^0.7.0",
"express": "^4.13.1", "express": "^4.13.1",
"fast-sass-loader": "1.4.6", "fast-sass-loader": "^1.4.5",
"file-loader": "^1.1.11", "file-loader": "^1.1.11",
"file-saver": "^1.3.8", "file-saver": "^1.3.8",
"git-rev-sync": "^1.4.0", "git-rev-sync": "^1.4.0",
@@ -43,7 +42,6 @@
"karma-coverage": "^1.1.2", "karma-coverage": "^1.1.2",
"karma-html-reporter": "^0.2.7", "karma-html-reporter": "^0.2.7",
"karma-jasmine": "^1.1.2", "karma-jasmine": "^1.1.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^3.0.0", "karma-webpack": "^3.0.0",
"location-bar": "^3.0.1", "location-bar": "^3.0.1",
"lodash": "^3.10.1", "lodash": "^3.10.1",
@@ -57,7 +55,7 @@
"node-bourbon": "^4.2.3", "node-bourbon": "^4.2.3",
"node-sass": "^4.9.2", "node-sass": "^4.9.2",
"painterro": "^0.2.65", "painterro": "^0.2.65",
"printj": "^1.2.1", "printj": "^1.1.0",
"raw-loader": "^0.5.1", "raw-loader": "^0.5.1",
"request": "^2.69.0", "request": "^2.69.0",
"split": "^1.0.0", "split": "^1.0.0",
@@ -80,7 +78,6 @@
"build:dev": "webpack", "build:dev": "webpack",
"build:watch": "webpack --watch", "build:watch": "webpack --watch",
"test": "karma start --single-run", "test": "karma start --single-run",
"test-debug": "NODE_ENV=debug karma start --no-single-run",
"test:watch": "karma start --no-single-run", "test:watch": "karma start --no-single-run",
"verify": "concurrently 'npm:test' 'npm:lint'", "verify": "concurrently 'npm:test' 'npm:lint'",
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api", "jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",

View File

@@ -21,10 +21,17 @@
*****************************************************************************/ *****************************************************************************/
define([ define([
"./src/BrowseController",
"./src/PaneController",
"./src/InspectorPaneController",
"./src/BrowseObjectController",
"./src/MenuArrowController",
"./src/ObjectHeaderController",
"./src/navigation/NavigationService", "./src/navigation/NavigationService",
"./src/navigation/NavigateAction", "./src/navigation/NavigateAction",
"./src/navigation/OrphanNavigationHandler", "./src/navigation/OrphanNavigationHandler",
"./src/windowing/NewTabAction", "./src/windowing/NewTabAction",
"./src/windowing/WindowTitler",
"./res/templates/browse.html", "./res/templates/browse.html",
"./res/templates/browse-object.html", "./res/templates/browse-object.html",
"./res/templates/browse/object-header.html", "./res/templates/browse/object-header.html",
@@ -35,10 +42,17 @@ define([
"./res/templates/browse/inspector-region.html", "./res/templates/browse/inspector-region.html",
'legacyRegistry' 'legacyRegistry'
], function ( ], function (
BrowseController,
PaneController,
InspectorPaneController,
BrowseObjectController,
MenuArrowController,
ObjectHeaderController,
NavigationService, NavigationService,
NavigateAction, NavigateAction,
OrphanNavigationHandler, OrphanNavigationHandler,
NewTabAction, NewTabAction,
WindowTitler,
browseTemplate, browseTemplate,
browseObjectTemplate, browseObjectTemplate,
objectHeaderTemplate, objectHeaderTemplate,
@@ -61,6 +75,70 @@ define([
"priority": "fallback" "priority": "fallback"
} }
], ],
"controllers": [
{
"key": "BrowseController",
"implementation": BrowseController,
"depends": [
"$scope",
"$route",
"$location",
"objectService",
"navigationService",
"urlService",
"DEFAULT_PATH"
]
},
{
"key": "PaneController",
"implementation": PaneController,
"priority": "preferred",
"depends": [
"$scope",
"agentService",
"$window",
"$location",
"$attrs",
"navigationService"
]
},
{
"key": "BrowseObjectController",
"implementation": BrowseObjectController,
"depends": [
"$scope",
"$location",
"$route"
]
},
{
"key": "MenuArrowController",
"implementation": MenuArrowController,
"depends": [
"$scope"
]
},
{
"key": "InspectorPaneController",
"implementation": InspectorPaneController,
"priority": "preferred",
"depends": [
"$scope",
"agentService",
"$window",
"navigationService",
"$location",
"$attrs"
]
},
{
"key": "ObjectHeaderController",
"implementation": ObjectHeaderController,
"depends": [
"$scope"
]
}
],
"representations": [ "representations": [
{ {
"key": "browse-object", "key": "browse-object",
@@ -148,6 +226,14 @@ define([
} }
], ],
"runs": [ "runs": [
{
"implementation": WindowTitler,
"depends": [
"navigationService",
"$rootScope",
"$document"
]
},
{ {
"implementation": OrphanNavigationHandler, "implementation": OrphanNavigationHandler,
"depends": [ "depends": [

View File

@@ -0,0 +1,215 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/**
* This bundle implements Browse mode.
* @namespace platform/commonUI/browse
*/
define(
['lodash'],
function (_) {
/**
* The BrowseController is used to populate the initial scope in Browse
* mode. It loads the root object from the objectService and makes it
* available in the scope for Angular template's; this is the point at
* which Angular templates first have access to the domain object
* hierarchy.
*
* @memberof platform/commonUI/browse
* @constructor
*/
function BrowseController(
$scope,
$route,
$location,
objectService,
navigationService,
urlService,
defaultPath
) {
window.browseScope = $scope;
var initialPath = ($route.current.params.ids || defaultPath).split("/"),
currentIds;
$scope.treeModel = {
selectedObject: undefined,
onSelection: function (object) {
navigationService.setNavigation(object, true);
},
allowSelection: function (object) {
var domainObjectInView = navigationService.getNavigation(),
isInEditMode = domainObjectInView.getCapability('status').get('editing');
if (isInEditMode) {
var actions = object.getCapability('action'),
previewAction = actions.getActions({key: 'mct-preview-action'})[0];
if (previewAction && previewAction.perform) {
previewAction.perform();
return false;
} else {
return navigationService.shouldNavigate();
}
} else {
return true;
}
}
};
function idsForObject(domainObject) {
return urlService
.urlForLocation("", domainObject)
.replace('/', '');
}
// Find an object in an array of objects.
function findObject(domainObjects, id) {
var i;
for (i = 0; i < domainObjects.length; i += 1) {
if (domainObjects[i].getId() === id) {
return domainObjects[i];
}
}
}
// helper, fetch a single object from the object service.
function getObject(id) {
return objectService.getObjects([id])
.then(function (results) {
return results[id];
});
}
// recursively locate and return an object inside of a container
// via a path. If at any point in the recursion it fails to find
// the next object, it will return the parent.
function findViaComposition(containerObject, path) {
var nextId = path.shift();
if (!nextId) {
return containerObject;
}
return containerObject.useCapability('composition')
.then(function (composees) {
var nextObject = findObject(composees, nextId);
if (!nextObject) {
return containerObject;
}
if (!nextObject.hasCapability('composition')) {
return nextObject;
}
return findViaComposition(nextObject, path);
});
}
function navigateToObject(desiredObject) {
$scope.navigatedObject = desiredObject;
$scope.treeModel.selectedObject = desiredObject;
currentIds = idsForObject(desiredObject);
$route.current.pathParams.ids = currentIds;
$location.path('/browse/' + currentIds);
}
function getLastChildIfRoot(object) {
if (object.getId() !== 'ROOT') {
return object;
}
return object.useCapability('composition')
.then(function (composees) {
return composees[composees.length - 1];
});
}
function navigateToPath(path) {
return getObject('ROOT')
.then(function (root) {
return findViaComposition(root, path);
})
.then(getLastChildIfRoot)
.then(function (object) {
navigationService.setNavigation(object);
});
}
getObject('ROOT')
.then(function (root) {
$scope.domainObject = root;
navigateToPath(initialPath);
});
// Handle navigation events from view service. Only navigates
// if path has changed.
function navigateDirectlyToModel(domainObject) {
var newIds = idsForObject(domainObject);
if (currentIds !== newIds) {
currentIds = newIds;
navigateToObject(domainObject);
}
}
// Listen for changes in navigation state.
navigationService.addListener(navigateDirectlyToModel);
// Listen for route changes which are caused by browser events
// (e.g. bookmarks to pages in OpenMCT) and prevent them. Instead,
// navigate to the path ourselves, which results in it being
// properly set.
$scope.$on('$routeChangeStart', function (event, route, oldRoute) {
if (route.$$route === $route.current.$$route) {
if (route.pathParams.ids &&
route.pathParams.ids !== $route.current.pathParams.ids) {
var otherParams = _.omit(route.params, 'ids');
var oldOtherParams = _.omit(oldRoute.params, 'ids');
var deletedParams = _.omit(oldOtherParams, _.keys(otherParams));
event.preventDefault();
navigateToPath(route.pathParams.ids.split('/'))
.then(function () {
if (!_.isEqual(otherParams, oldOtherParams)) {
_.forEach(otherParams, function (v, k) {
$location.search(k, v);
});
_.forEach(deletedParams, function (k) {
$location.search(k, null);
});
}
});
} else {
navigateToPath([]);
}
}
});
// Clean up when the scope is destroyed
$scope.$on("$destroy", function () {
navigationService.removeListener(navigateDirectlyToModel);
});
}
return BrowseController;
}
);

View File

@@ -0,0 +1,72 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
[],
function () {
/**
* Controller for the `browse-object` representation of a domain
* object (the right-hand side of Browse mode.)
* @memberof platform/commonUI/browse
* @constructor
*/
function BrowseObjectController($scope, $location, $route) {
function setViewForDomainObject(domainObject) {
var locationViewKey = $location.search().view;
function selectViewIfMatching(view) {
if (view.key === locationViewKey) {
$scope.representation = $scope.representation || {};
$scope.representation.selected = view;
}
}
if (locationViewKey) {
((domainObject && domainObject.useCapability('view')) || [])
.forEach(selectViewIfMatching);
}
}
function updateQueryParam(viewKey) {
if (viewKey && $location.search().view !== viewKey) {
$location.search('view', viewKey);
}
}
$scope.$watch('domainObject', setViewForDomainObject);
$scope.$watch('representation.selected.key', updateQueryParam);
$scope.$on('$locationChangeSuccess', function () {
setViewForDomainObject($scope.domainObject);
});
$scope.doAction = function (action) {
return $scope[action] && $scope[action]();
};
}
return BrowseObjectController;
}
);

View File

@@ -0,0 +1,78 @@
/*****************************************************************************
* 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(
["./PaneController"],
function (PaneController) {
/**
* Pane controller that reveals inspector, if hidden, when object
* switches to edit mode.
*
* @param $scope
* @param agentService
* @param $window
* @param navigationService
* @constructor
*/
function InspectorPaneController($scope, agentService, $window, navigationService, $location, $attrs) {
PaneController.call(this, $scope, agentService, $window, $location, $attrs);
var statusListener,
self = this;
function showInspector(statuses) {
if (statuses.indexOf('editing') !== -1 && !self.visible()) {
self.toggle();
}
}
function attachStatusListener(domainObject) {
// Remove existing status listener if existing
if (statusListener) {
statusListener();
}
if (domainObject.hasCapability("status")) {
statusListener = domainObject.getCapability("status").listen(showInspector);
}
return statusListener;
}
var domainObject = navigationService.getNavigation();
if (domainObject) {
attachStatusListener(domainObject);
}
navigationService.addListener(attachStatusListener);
$scope.$on("$destroy", function () {
statusListener();
navigationService.removeListener(attachStatusListener);
});
}
InspectorPaneController.prototype = Object.create(PaneController.prototype);
return InspectorPaneController;
}
);

View File

@@ -0,0 +1,59 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/**
* Module defining MenuArrowController. Created by shale on 06/30/2015.
*/
define(
[],
function () {
/**
* A left-click on the menu arrow should display a
* context menu. This controller launches the context
* menu.
* @memberof platform/commonUI/browse
* @constructor
*/
function MenuArrowController($scope) {
this.$scope = $scope;
}
/**
* Show a context menu for the domain object in this scope.
*
* @param event the browser event which caused this (used to
* position the menu)
*/
MenuArrowController.prototype.showMenu = function (event) {
var actionContext = {
key: 'menu',
domainObject: this.$scope.domainObject,
event: event
};
this.$scope.domainObject.getCapability('action').perform(actionContext);
};
return MenuArrowController;
}
);

View File

@@ -0,0 +1,92 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
[],
function () {
/**
* Controller to provide the ability to inline edit an object name.
*
* @constructor
* @memberof platform/commonUI/browse
*/
function ObjectHeaderController($scope) {
this.$scope = $scope;
this.domainObject = $scope.domainObject;
this.editable = this.allowEdit();
}
/**
* Updates the object name on blur and enter keypress events.
*
* @param event the mouse event
*/
ObjectHeaderController.prototype.updateName = function (event) {
if (!event || !event.currentTarget) {
return;
}
if (event.type === 'blur') {
this.updateModel(event);
} else if (event.which === 13) {
this.updateModel(event);
event.currentTarget.blur();
window.getSelection().removeAllRanges();
}
};
/**
* Updates the model.
*
* @param event the mouse event
* @param private
*/
ObjectHeaderController.prototype.updateModel = function (event) {
var name = event.currentTarget.textContent.replace(/\n/g, ' ');
if (name.length === 0) {
name = "Unnamed " + this.domainObject.getCapability("type").typeDef.name;
event.currentTarget.textContent = name;
}
if (name !== this.domainObject.getModel().name) {
this.domainObject.getCapability('mutation').mutate(function (model) {
model.name = name;
});
}
};
/**
* Checks if the domain object is editable.
*
* @private
* @return true if object is editable
*/
ObjectHeaderController.prototype.allowEdit = function () {
var type = this.domainObject && this.domainObject.getCapability('type');
return !!(type && type.hasFeature('creation'));
};
return ObjectHeaderController;
}
);

View File

@@ -0,0 +1,88 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
[],
function () {
var navigationListenerAdded = false;
/**
* Controller to provide the ability to show/hide the tree in
* Browse mode.
* @constructor
* @memberof platform/commonUI/browse
*/
function PaneController($scope, agentService, $window, $location, $attrs, navigationService) {
var self = this;
this.agentService = agentService;
var hideParameterPresent = $location.search().hasOwnProperty($attrs.hideParameter);
if ($attrs.hideParameter && hideParameterPresent) {
this.state = false;
$location.search($attrs.hideParameter, undefined);
} else {
this.state = true;
}
/**
* Callback to invoke when any selection occurs in the tree.
* This controller can be passed in as the `parameters` object
* to the tree representation.
*
* @property {Function} callback
* @memberof platform/commonUI/browse.PaneController#
*/
this.callback = function () {
// Note that, since this is a callback to pass, this is not
// declared as a method but as a property which happens to
// be a function.
if (agentService.isPhone() && agentService.isPortrait()) {
// On phones, trees should collapse in portrait mode
// when something is navigated-to.
self.state = false;
}
};
if (navigationService && navigationService.addListener && !navigationListenerAdded) {
navigationService.addListener(this.callback);
navigationListenerAdded = true;
}
}
/**
* Toggle the visibility of the pane.
*/
PaneController.prototype.toggle = function () {
this.state = !this.state;
};
/**
* Get the desired visibility state of the pane.
* @returns {boolean} true when visible
*/
PaneController.prototype.visible = function () {
return !!this.state;
};
return PaneController;
}
);

View File

@@ -0,0 +1,51 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
[],
function () {
/**
* Updates the title of the current window to reflect the name
* of the currently navigated-to domain object.
* @memberof platform/commonUI/browse
* @constructor
*/
function WindowTitler(navigationService, $rootScope, $document) {
// Look up name of the navigated domain object...
function getNavigatedObjectName() {
var navigatedObject = navigationService.getNavigation();
return navigatedObject && navigatedObject.getModel().name;
}
// Set the window title...
function setTitle(name) {
$document[0].title = name;
}
// Watch the former, and invoke the latter
$rootScope.$watch(getNavigatedObjectName, setTitle);
}
return WindowTitler;
}
);

View File

@@ -0,0 +1,266 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global console*/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
[
"../src/BrowseController",
"../src/navigation/NavigationService"
],
function (
BrowseController,
NavigationService
) {
describe("The browse controller", function () {
var mockScope,
mockRoute,
mockLocation,
mockObjectService,
mockNavigationService,
mockRootObject,
mockUrlService,
mockDefaultRootObject,
mockOtherDomainObject,
mockNextObject,
testDefaultRoot,
controller;
function waitsForNavigation() {
return new Promise(function (resolve) {
mockNavigationService.setNavigation.and.callFake(function (obj) {
var returnValue;
try {
returnValue = NavigationService.prototype.setNavigation.call(mockNavigationService, obj);
} catch (err) {
console.error(err);
//Not rejecting because 'setNavigation' has been called, which is what's being tested here.
//Rejecting will fail tests.
}
resolve();
return returnValue;
});
});
}
function instantiateController() {
controller = new BrowseController(
mockScope,
mockRoute,
mockLocation,
mockObjectService,
mockNavigationService,
mockUrlService,
testDefaultRoot
);
}
beforeEach(function () {
testDefaultRoot = "some-root-level-domain-object";
mockScope = jasmine.createSpyObj(
"$scope",
["$on", "$watch"]
);
mockRoute = { current: { params: {}, pathParams: {} } };
mockUrlService = jasmine.createSpyObj(
"urlService",
["urlForLocation"]
);
mockUrlService.urlForLocation.and.callFake(function (mode, object) {
if (object === mockDefaultRootObject) {
return [mode, testDefaultRoot].join('/');
}
if (object === mockOtherDomainObject) {
return [mode, 'other'].join('/');
}
if (object === mockNextObject) {
return [mode, testDefaultRoot, 'next'].join('/');
}
throw new Error('Tried to get url for unexpected object');
});
mockLocation = jasmine.createSpyObj(
"$location",
["path"]
);
mockObjectService = jasmine.createSpyObj(
"objectService",
["getObjects"]
);
mockNavigationService = new NavigationService({});
[
"getNavigation",
"setNavigation",
"addListener",
"removeListener"
].forEach(function (method) {
spyOn(mockNavigationService, method)
.and.callThrough();
});
mockRootObject = jasmine.createSpyObj(
"rootObjectContainer",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockDefaultRootObject = jasmine.createSpyObj(
"defaultRootObject",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockOtherDomainObject = jasmine.createSpyObj(
"otherDomainObject",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockNextObject = jasmine.createSpyObj(
"nestedDomainObject",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockObjectService.getObjects.and.returnValue(Promise.resolve({
ROOT: mockRootObject
}));
mockRootObject.useCapability.and.returnValue(Promise.resolve([
mockOtherDomainObject,
mockDefaultRootObject
]));
mockRootObject.hasCapability.and.returnValue(true);
mockDefaultRootObject.useCapability.and.returnValue(Promise.resolve([
mockNextObject
]));
mockDefaultRootObject.hasCapability.and.returnValue(true);
mockOtherDomainObject.hasCapability.and.returnValue(false);
mockNextObject.useCapability.and.returnValue(undefined);
mockNextObject.hasCapability.and.returnValue(false);
mockNextObject.getId.and.returnValue("next");
mockDefaultRootObject.getId.and.returnValue(testDefaultRoot);
instantiateController();
return waitsForNavigation();
});
it("uses composition to set the navigated object, if there is none", function () {
instantiateController();
return waitsForNavigation().then(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
it("navigates to a root-level object, even when default path is not found", function () {
mockDefaultRootObject.getId
.and.returnValue("something-other-than-the-" + testDefaultRoot);
instantiateController();
return waitsForNavigation().then(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
it("does not try to override navigation", function () {
mockNavigationService.getNavigation.and.returnValue(mockDefaultRootObject);
instantiateController();
return waitsForNavigation().then(function () {
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
});
});
it("updates scope when navigated object changes", function () {
// Should have registered a listener - call it
mockNavigationService.addListener.calls.mostRecent().args[0](
mockOtherDomainObject
);
expect(mockScope.navigatedObject).toEqual(mockOtherDomainObject);
});
it("releases its navigation listener when its scope is destroyed", function () {
expect(mockScope.$on).toHaveBeenCalledWith(
"$destroy",
jasmine.any(Function)
);
mockScope.$on.calls.mostRecent().args[1]();
// Should remove the listener it added earlier
expect(mockNavigationService.removeListener).toHaveBeenCalledWith(
mockNavigationService.addListener.calls.mostRecent().args[0]
);
});
it("uses route parameters to choose initially-navigated object", function () {
mockRoute.current.params.ids = testDefaultRoot + "/next";
instantiateController();
return waitsForNavigation().then(function () {
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
});
});
it("handles invalid IDs by going as far as possible", function () {
// Idea here is that if we get a bad path of IDs,
// browse controller should traverse down it until
// it hits an invalid ID.
mockRoute.current.params.ids = testDefaultRoot + "/junk";
instantiateController();
return waitsForNavigation().then(function () {
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
it("handles compositionless objects by going as far as possible", function () {
// Idea here is that if we get a path which passes
// through an object without a composition, browse controller
// should stop at it since remaining IDs cannot be loaded.
mockRoute.current.params.ids = testDefaultRoot + "/next/junk";
instantiateController();
return waitsForNavigation().then(function () {
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
});
});
it("updates the displayed route to reflect current navigation", function () {
// In order to trigger a route update and not a route change,
// the current route must be updated before location.path is
// called.
expect(mockRoute.current.pathParams.ids)
.not
.toBe(testDefaultRoot + '/next');
mockLocation.path.and.callFake(function () {
expect(mockRoute.current.pathParams.ids)
.toBe(testDefaultRoot + '/next');
});
mockNavigationService.addListener.calls.mostRecent().args[0](
mockNextObject
);
expect(mockLocation.path).toHaveBeenCalledWith(
'/browse/' + testDefaultRoot + '/next'
);
});
});
}
);

View File

@@ -0,0 +1,93 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
["../src/BrowseObjectController"],
function (BrowseObjectController) {
describe("The browse object controller", function () {
var mockScope,
mockLocation,
mockRoute,
controller;
// Utility function; look for a $watch on scope and fire it
function fireWatch(expr, value) {
mockScope.$watch.calls.all().forEach(function (call) {
if (call.args[0] === expr) {
call.args[1](value);
}
});
}
beforeEach(function () {
mockScope = jasmine.createSpyObj(
"$scope",
["$on", "$watch"]
);
mockRoute = { current: { params: {} } };
mockLocation = jasmine.createSpyObj(
"$location",
["path", "search"]
);
mockLocation.search.and.returnValue({});
controller = new BrowseObjectController(
mockScope,
mockLocation,
mockRoute
);
});
it("updates query parameters when selected view changes", function () {
fireWatch("representation.selected.key", "xyz");
expect(mockLocation.search).toHaveBeenCalledWith('view', "xyz");
// Allows the path index to be checked
// prior to setting $route.current
mockLocation.path.and.returnValue("/browse/");
});
it("sets the active view from query parameters", function () {
var mockDomainObject = jasmine.createSpyObj(
"domainObject",
['getId', 'getModel', 'getCapability', 'useCapability']
),
testViews = [
{ key: 'abc' },
{ key: 'def', someKey: 'some value' },
{ key: 'xyz' }
];
mockDomainObject.useCapability.and.callFake(function (c) {
return (c === 'view') && testViews;
});
mockLocation.search.and.returnValue({ view: 'def' });
fireWatch('domainObject', mockDomainObject);
expect(mockScope.representation.selected)
.toEqual(testViews[1]);
});
});
}
);

View File

@@ -0,0 +1,103 @@
/*****************************************************************************
* 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(
["../src/InspectorPaneController"],
function (InspectorPaneController) {
describe("The InspectorPaneController", function () {
var mockScope,
mockAgentService,
mockDomainObject,
mockWindow,
mockStatusCapability,
mockNavigationService,
mockNavigationUnlistener,
mockStatusUnlistener,
controller,
mockLocation,
mockAttrs;
beforeEach(function () {
mockScope = jasmine.createSpyObj("$scope", ["$on"]);
mockWindow = jasmine.createSpyObj("$window", ["open"]);
mockAgentService = jasmine.createSpyObj(
"agentService",
["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]
);
mockNavigationUnlistener = jasmine.createSpy("navigationUnlistener");
mockNavigationService = jasmine.createSpyObj(
"navigationService",
["getNavigation", "addListener"]
);
mockNavigationService.addListener.and.returnValue(mockNavigationUnlistener);
mockStatusUnlistener = jasmine.createSpy("statusUnlistener");
mockStatusCapability = jasmine.createSpyObj(
"statusCapability",
["listen"]
);
mockStatusCapability.listen.and.returnValue(mockStatusUnlistener);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
[
'getId',
'getModel',
'getCapability',
'hasCapability'
]
);
mockDomainObject.getId.and.returnValue("domainObject");
mockDomainObject.getModel.and.returnValue({});
mockDomainObject.hasCapability.and.returnValue(true);
mockDomainObject.getCapability.and.returnValue(mockStatusCapability);
mockLocation = jasmine.createSpyObj('location', ['search']);
mockLocation.search.and.returnValue({});
mockAttrs = {};
controller = new InspectorPaneController(mockScope, mockAgentService, mockWindow, mockNavigationService, mockLocation, mockAttrs);
});
it("listens for changes to navigation and attaches a status" +
" listener", function () {
expect(mockNavigationService.addListener).toHaveBeenCalledWith(jasmine.any(Function));
mockNavigationService.addListener.calls.mostRecent().args[0](mockDomainObject);
expect(mockStatusCapability.listen).toHaveBeenCalledWith(jasmine.any(Function));
});
it("if hidden, shows the inspector when domain object switches to" +
" edit mode", function () {
controller.toggle();
// test pre-condition that inspector is hidden
expect(controller.visible()).toBe(false);
mockNavigationService.addListener.calls.mostRecent().args[0](mockDomainObject);
mockStatusCapability.listen.calls.mostRecent().args[0](["editing"]);
expect(controller.visible()).toBe(true);
});
});
}
);

View File

@@ -0,0 +1,79 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/**
* MenuArrowControllerSpec. Created by shale on 07/02/2015.
*/
define(
["../src/MenuArrowController"],
function (MenuArrowController) {
describe("The menu arrow controller ", function () {
var mockScope,
mockDomainObject,
mockEvent,
mockContextMenuAction,
mockActionContext,
controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj(
"$scope",
[""]
);
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getCapability"]
);
mockEvent = jasmine.createSpyObj(
"event",
["preventDefault"]
);
mockContextMenuAction = jasmine.createSpyObj(
"action",
["perform", "getActions"]
);
mockActionContext = jasmine.createSpyObj(
"actionContext",
[""]
);
mockActionContext.domainObject = mockDomainObject;
mockActionContext.event = mockEvent;
mockScope.domainObject = mockDomainObject;
mockDomainObject.getCapability.and.returnValue(mockContextMenuAction);
mockContextMenuAction.perform.and.returnValue(jasmine.any(Function));
controller = new MenuArrowController(mockScope);
});
it("calls the context menu action when clicked", function () {
// Simulate a click on the menu arrow
controller.showMenu(mockEvent);
// Expect the menu action to be performed
expect(mockDomainObject.getCapability).toHaveBeenCalledWith('action');
expect(mockContextMenuAction.perform).toHaveBeenCalled();
});
});
}
);

View File

@@ -0,0 +1,137 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
["../src/ObjectHeaderController"],
function (ObjectHeaderController) {
describe("The object header controller", function () {
var mockScope,
mockDomainObject,
mockCapabilities,
mockMutationCapability,
mockTypeCapability,
mockEvent,
mockCurrentTarget,
model,
controller;
beforeEach(function () {
mockMutationCapability = jasmine.createSpyObj("mutation", ["mutate"]);
mockTypeCapability = jasmine.createSpyObj("type", ["typeDef", "hasFeature"]);
mockTypeCapability.typeDef = { name: ""};
mockTypeCapability.hasFeature.and.callFake(function (feature) {
return feature === 'creation';
});
mockCapabilities = {
mutation: mockMutationCapability,
type: mockTypeCapability
};
model = {
name: "Test name"
};
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "getModel"]);
mockDomainObject.getModel.and.returnValue(model);
mockDomainObject.getCapability.and.callFake(function (key) {
return mockCapabilities[key];
});
mockScope = {
domainObject: mockDomainObject
};
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur", "textContent"]);
mockCurrentTarget.blur.and.returnValue(mockCurrentTarget);
mockEvent = {
which: {},
type: {},
currentTarget: mockCurrentTarget
};
controller = new ObjectHeaderController(mockScope);
});
it("updates the model with new name on blur", function () {
mockEvent.type = "blur";
mockCurrentTarget.textContent = "New name";
controller.updateName(mockEvent);
expect(mockMutationCapability.mutate).toHaveBeenCalled();
});
it("updates the model with a default for blank names", function () {
mockEvent.type = "blur";
mockCurrentTarget.textContent = "";
controller.updateName(mockEvent);
expect(mockCurrentTarget.textContent.length).not.toEqual(0);
expect(mockMutationCapability.mutate).toHaveBeenCalled();
});
it("does not update the model if the same name", function () {
mockEvent.type = "blur";
mockCurrentTarget.textContent = mockDomainObject.getModel().name;
controller.updateName(mockEvent);
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
});
it("updates the model on enter keypress event only", function () {
mockCurrentTarget.textContent = "New name";
controller.updateName(mockEvent);
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
mockEvent.which = 13;
controller.updateName(mockEvent);
expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
mockMutationCapability.mutate.calls.mostRecent().args[0](model);
expect(mockDomainObject.getModel().name).toBe("New name");
});
it("blurs the field on enter key press", function () {
mockCurrentTarget.textContent = "New name";
mockEvent.which = 13;
controller.updateName(mockEvent);
expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
});
it("allows editting name when object is creatable", function () {
expect(controller.allowEdit()).toBe(true);
});
it("disallows editting name when object is non-creatable", function () {
mockTypeCapability.hasFeature.and.returnValue(false);
expect(controller.allowEdit()).toBe(false);
});
});
}
);

View File

@@ -0,0 +1,106 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
["../src/PaneController"],
function (PaneController) {
describe("The PaneController", function () {
var mockScope,
mockAgentService,
mockWindow,
controller,
mockLocation,
mockAttrs;
// We want to reinstantiate for each test case
// because device state can influence constructor-time behavior
function instantiateController() {
return new PaneController(
mockScope,
mockAgentService,
mockWindow,
mockLocation,
mockAttrs
);
}
beforeEach(function () {
mockScope = jasmine.createSpyObj("$scope", ["$on"]);
mockAgentService = jasmine.createSpyObj(
"agentService",
["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]
);
mockWindow = jasmine.createSpyObj("$window", ["open"]);
mockLocation = jasmine.createSpyObj('location', ['search']);
mockLocation.search.and.returnValue({});
mockAttrs = {};
});
it("is initially visible", function () {
expect(instantiateController().visible()).toBeTruthy();
});
it("allows visibility to be toggled", function () {
controller = instantiateController();
controller.toggle();
expect(controller.visible()).toBeFalsy();
controller.toggle();
expect(controller.visible()).toBeTruthy();
});
it("collapses on navigation changes on portrait-oriented phones", function () {
mockAgentService.isMobile.and.returnValue(true);
mockAgentService.isPhone.and.returnValue(true);
mockAgentService.isPortrait.and.returnValue(true);
controller = instantiateController();
expect(controller.visible()).toBeTruthy();
// Simulate a change from the tree by invoking controller's
controller.callback();
// Tree should have collapsed
expect(controller.visible()).toBeFalsy();
});
describe("specifying hideParameter", function () {
beforeEach(function () {
mockAttrs = {hideParameter: 'hideTree'};
});
it("sets pane state to false when in location.search", function () {
mockLocation.search.and.returnValue({'hideTree': true});
expect(instantiateController().visible()).toBe(false);
expect(mockLocation.search).toHaveBeenCalledWith('hideTree', undefined);
});
it("sets state to true when not found in location.search", function () {
mockLocation.search.and.returnValue({});
expect(instantiateController().visible()).toBe(true);
expect(mockLocation.search).not.toHaveBeenCalledWith('hideTree', undefined);
});
});
});
}
);

View File

@@ -0,0 +1,78 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/**
* WindowTitlerSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/windowing/WindowTitler"],
function (WindowTitler) {
describe("The window titler", function () {
var mockNavigationService,
mockRootScope,
mockDocument,
mockDomainObject,
titler; // eslint-disable-line
beforeEach(function () {
mockNavigationService = jasmine.createSpyObj(
'navigationService',
['getNavigation']
);
mockRootScope = jasmine.createSpyObj(
'$rootScope',
['$watch']
);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getModel']
);
mockDocument = [{}];
mockDomainObject.getModel.and.returnValue({ name: 'Test name' });
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
titler = new WindowTitler(
mockNavigationService,
mockRootScope,
mockDocument
);
});
it("listens for changes to the name of the navigated object", function () {
expect(mockRootScope.$watch).toHaveBeenCalledWith(
jasmine.any(Function),
jasmine.any(Function)
);
expect(mockRootScope.$watch.calls.mostRecent().args[0]())
.toEqual('Test name');
});
it("sets the title to the name of the navigated object", function () {
mockRootScope.$watch.calls.mostRecent().args[1]("Some name");
expect(mockDocument[0].title).toEqual("Some name");
});
});
}
);

View File

@@ -28,7 +28,6 @@ define([
"./res/templates/dialog.html", "./res/templates/dialog.html",
"./res/templates/overlay-blocking-message.html", "./res/templates/overlay-blocking-message.html",
"./res/templates/message.html", "./res/templates/message.html",
"./res/templates/notification-message.html",
"./res/templates/overlay-message-list.html", "./res/templates/overlay-message-list.html",
"./res/templates/overlay.html", "./res/templates/overlay.html",
'legacyRegistry' 'legacyRegistry'
@@ -40,7 +39,6 @@ define([
dialogTemplate, dialogTemplate,
overlayBlockingMessageTemplate, overlayBlockingMessageTemplate,
messageTemplate, messageTemplate,
notificationMessageTemplate,
overlayMessageListTemplate, overlayMessageListTemplate,
overlayTemplate, overlayTemplate,
legacyRegistry legacyRegistry
@@ -65,8 +63,7 @@ define([
"depends": [ "depends": [
"$document", "$document",
"$compile", "$compile",
"$rootScope", "$rootScope"
"$timeout"
] ]
} }
], ],
@@ -91,10 +88,6 @@ define([
"key": "message", "key": "message",
"template": messageTemplate "template": messageTemplate
}, },
{
"key": "notification-message",
"template": notificationMessageTemplate
},
{ {
"key": "overlay-message-list", "key": "overlay-message-list",
"template": overlayMessageListTemplate "template": overlayMessageListTemplate

View File

@@ -19,24 +19,24 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<div class="c-overlay__top-bar"> <div class="abs top-bar">
<div class="c-overlay__dialog-title">{{ngModel.title}}</div> <div class="dialog-title">{{ngModel.title}}</div>
<div class="c-overlay__dialog-hint hint">All fields marked <span class="req icon-asterisk"></span> are required.</div> <div class="hint">All fields marked <span class="req icon-asterisk"></span> are required.</div>
</div> </div>
<div class='c-overlay__contents-main'> <div class='abs editor'>
<mct-form ng-model="ngModel.value" <mct-form ng-model="ngModel.value"
structure="ngModel.structure" structure="ngModel.structure"
class="validates" class="validates"
name="createForm"> name="createForm">
</mct-form> </mct-form>
</div> </div>
<div class="c-overlay__button-bar"> <div class="abs bottom-bar">
<a class='c-button c-button--major' <a class='s-button major'
ng-class="{ disabled: !createForm.$valid }" ng-class="{ disabled: !createForm.$valid }"
ng-click="ngModel.confirm()"> ng-click="ngModel.confirm()">
OK OK
</a> </a>
<a class='c-button ' <a class='s-button'
ng-click="ngModel.cancel()"> ng-click="ngModel.cancel()">
Cancel Cancel
</a> </a>

View File

@@ -1,32 +1,25 @@
<div class="c-message" <div class="l-message"
ng-class="'message-severity-' + ngModel.severity"> ng-class="'message-severity-' + ngModel.severity">
<div class="w-message-contents"> <div class="w-message-contents">
<div class="c-message__top-bar"> <div class="top-bar">
<div class="c-message__title">{{ngModel.title}}</div> <div class="title">{{ngModel.message}}</div>
</div>
<div class="c-message__hint" ng-hide="ngModel.hint === undefined">
{{ngModel.hint}}
<span ng-if="ngModel.timestamp !== undefined">[{{ngModel.timestamp}}]</span>
</div> </div>
<div class="message-body"> <div class="message-body">
<div class="message-action">
{{ngModel.actionText}}
</div>
<mct-include key="'progress-bar'" <mct-include key="'progress-bar'"
ng-model="ngModel" ng-model="ngModel"
ng-show="ngModel.progress !== undefined || ngModel.unknownProgress"></mct-include> ng-show="ngModel.progressPerc !== undefined"></mct-include>
</div> </div>
<div class="c-overlay__button-bar"> <div class="bottom-bar">
<button ng-repeat="dialogOption in ngModel.options" <a ng-repeat="dialogOption in ngModel.options"
class="c-button" class="s-button"
ng-click="dialogOption.callback()"> ng-click="dialogOption.callback()">
{{dialogOption.label}} {{dialogOption.label}}
</button> </a>
<button class="c-button c-button--major" <a class="s-button major"
ng-if="ngModel.primaryOption" ng-if="ngModel.primaryOption"
ng-click="ngModel.primaryOption.callback()"> ng-click="ngModel.primaryOption.callback()">
{{ngModel.primaryOption.label}} {{ngModel.primaryOption.label}}
</button> </a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,25 +0,0 @@
<div class="c-message"
ng-class="'message-severity-' + ngModel.severity">
<div class="w-message-contents">
<div class="c-message__top-bar">
<div class="c-message__title">{{ngModel.message}}</div>
</div>
<div class="message-body">
<mct-include key="'progress-bar'"
ng-model="ngModel"
ng-show="ngModel.progressPerc !== undefined"></mct-include>
</div>
</div>
<div class="c-overlay__button-bar">
<button ng-repeat="dialogOption in ngModel.options"
class="c-button"
ng-click="dialogOption.callback()">
{{dialogOption.label}}
</button>
<button class="c-button c-button--major"
ng-if="ngModel.primaryOption"
ng-click="ngModel.primaryOption.callback()">
{{ngModel.primaryOption.label}}
</button>
</div>
</div>

View File

@@ -1,23 +1,22 @@
<mct-container key="overlay"> <mct-container key="overlay">
<div class="t-message-list c-overlay__contents"> <div class="t-message-list">
<div class="c-overlay__top-bar"> <div class="top-bar">
<div class="c-overlay__dialog-title">{{ngModel.dialog.title}}</div> <div class="dialog-title">{{ngModel.dialog.title}}</div>
<div class="c-overlay__dialog-hint">Displaying {{ngModel.dialog.messages.length}} message<span <div class="hint">Displaying {{ngModel.dialog.messages.length}} message<span ng-show="ngModel.dialog.messages.length > 1 ||
ng-show="ngModel.dialog.messages.length > 1 ||
ngModel.dialog.messages.length == 0">s</span> ngModel.dialog.messages.length == 0">s</span>
</div> </div>
</div> </div>
<div class="w-messages c-overlay__messages"> <div class="w-messages">
<mct-include <mct-include
ng-repeat="msg in ngModel.dialog.messages | orderBy: '-'" ng-repeat="msg in ngModel.dialog.messages | orderBy: '-'"
key="'notification-message'" ng-model="msg.model"></mct-include> key="'message'" ng-model="msg.model"></mct-include>
</div> </div>
<div class="c-overlay__bottom-bar"> <div class="bottom-bar">
<button ng-repeat="dialogAction in ngModel.dialog.actions" <a ng-repeat="dialogAction in ngModel.dialog.actions"
class="c-button c-button--major" class="s-button major"
ng-click="dialogAction.action()"> ng-click="dialogAction.action()">
{{dialogAction.label}} {{dialogAction.label}}
</button> </a>
</div> </div>
</div> </div>
</mct-container> </mct-container>

View File

@@ -19,18 +19,18 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<mct-container key="c-overlay__contents"> <mct-container key="overlay">
<div class=c-overlay__top-bar"> <div class="abs top-bar">
<div class="c-overlay__dialog-title">{{ngModel.dialog.title}}</div> <div class="dialog-title">{{ngModel.dialog.title}}</div>
<div class="c-overlay__dialog-hint hint">{{ngModel.dialog.hint}}</div> <div class="hint">{{ngModel.dialog.hint}}</div>
</div> </div>
<div class='c-overlay__contents-main'> <div class='abs editor'>
<mct-include key="ngModel.dialog.template" <mct-include key="ngModel.dialog.template"
parameters="ngModel.dialog.parameters" parameters="ngModel.dialog.parameters"
ng-model="ngModel.dialog.model"> ng-model="ngModel.dialog.model">
</mct-include> </mct-include>
</div> </div>
<div class="c-overlay__button-bar"> <div class="abs bottom-bar">
<a ng-repeat="option in ngModel.dialog.options" <a ng-repeat="option in ngModel.dialog.options"
href='' href=''
class="s-button lg" class="s-button lg"

View File

@@ -19,12 +19,12 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<div class="c-overlay l-overlay-small" ng-class="{'delayEntry100ms' : ngModel.delay}"> <div class="abs overlay l-dialog" ng-class="{'delayEntry100ms' : ngModel.delay}">
<div class="c-overlay__blocker"></div> <div class="abs blocker"></div>
<div class="c-overlay__outer"> <div class="abs outer-holder">
<button ng-click="ngModel.cancel()" <a ng-click="ngModel.cancel()"
ng-if="ngModel.cancel" ng-if="ngModel.cancel"
class="c-click-icon c-overlay__close-button icon-x-in-circle"></button> class="close icon-x-in-circle"></a>
<div class="c-overlay__contents" ng-transclude></div> <div class="abs inner-holder contents" ng-transclude></div>
</div> </div>
</div> </div>

View File

@@ -44,9 +44,8 @@ define(
* @memberof platform/commonUI/dialog * @memberof platform/commonUI/dialog
* @constructor * @constructor
*/ */
function OverlayService($document, $compile, $rootScope, $timeout) { function OverlayService($document, $compile, $rootScope) {
this.$compile = $compile; this.$compile = $compile;
this.$timeout = $timeout;
// Don't include $document and $rootScope directly; // Don't include $document and $rootScope directly;
// avoids https://docs.angularjs.org/error/ng/cpws // avoids https://docs.angularjs.org/error/ng/cpws
@@ -94,14 +93,12 @@ define(
scope.key = key; scope.key = key;
scope.typeClass = typeClass || 't-dialog'; scope.typeClass = typeClass || 't-dialog';
this.$timeout(() => {
// Create the overlay element and add it to the document's body // Create the overlay element and add it to the document's body
element = this.$compile(TEMPLATE)(scope); element = this.$compile(TEMPLATE)(scope);
// Append so that most recent dialog is last in DOM. This means the most recent dialog will be on top when // Append so that most recent dialog is last in DOM. This means the most recent dialog will be on top when
// multiple overlays with the same z-index are active. // multiple overlays with the same z-index are active.
this.findBody().append(element); this.findBody().append(element);
});
return { return {
dismiss: dismiss dismiss: dismiss

View File

@@ -35,20 +35,16 @@ define(
mockTemplate, mockTemplate,
mockElement, mockElement,
mockScope, mockScope,
mockTimeout,
overlayService; overlayService;
beforeEach(function () { beforeEach(function () {
mockDocument = jasmine.createSpyObj("$document", ["find"]); mockDocument = jasmine.createSpyObj("$document", ["find"]);
mockCompile = jasmine.createSpy("$compile"); mockCompile = jasmine.createSpy("$compile");
mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]); mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
mockBody = jasmine.createSpyObj("body", ["append"]); mockBody = jasmine.createSpyObj("body", ["prepend"]);
mockTemplate = jasmine.createSpy("template"); mockTemplate = jasmine.createSpy("template");
mockElement = jasmine.createSpyObj("element", ["remove"]); mockElement = jasmine.createSpyObj("element", ["remove"]);
mockScope = jasmine.createSpyObj("scope", ["$destroy"]); mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
mockTimeout = function (callback) {
callback();
}
mockDocument.find.and.returnValue(mockBody); mockDocument.find.and.returnValue(mockBody);
mockCompile.and.returnValue(mockTemplate); mockCompile.and.returnValue(mockTemplate);
@@ -58,8 +54,7 @@ define(
overlayService = new OverlayService( overlayService = new OverlayService(
mockDocument, mockDocument,
mockCompile, mockCompile,
mockRootScope, mockRootScope
mockTimeout
); );
}); });
@@ -72,7 +67,7 @@ define(
it("adds the templated element to the body", function () { it("adds the templated element to the body", function () {
overlayService.createOverlay("test", {}); overlayService.createOverlay("test", {});
expect(mockBody.append).toHaveBeenCalledWith(mockElement); expect(mockBody.prepend).toHaveBeenCalledWith(mockElement);
}); });
it("places the provided model/key in its template's scope", function () { it("places the provided model/key in its template's scope", function () {

View File

@@ -27,6 +27,7 @@ define([
"./src/actions/EditAndComposeAction", "./src/actions/EditAndComposeAction",
"./src/actions/EditAction", "./src/actions/EditAction",
"./src/actions/PropertiesAction", "./src/actions/PropertiesAction",
"./src/actions/RemoveAction",
"./src/actions/SaveAction", "./src/actions/SaveAction",
"./src/actions/SaveAndStopEditingAction", "./src/actions/SaveAndStopEditingAction",
"./src/actions/SaveAsAction", "./src/actions/SaveAsAction",
@@ -57,6 +58,7 @@ define([
EditAndComposeAction, EditAndComposeAction,
EditAction, EditAction,
PropertiesAction, PropertiesAction,
RemoveAction,
SaveAction, SaveAction,
SaveAndStopEditingAction, SaveAndStopEditingAction,
SaveAsAction, SaveAsAction,
@@ -156,6 +158,18 @@ define([
"dialogService" "dialogService"
] ]
}, },
{
"key": "remove",
"category": "contextual",
"implementation": RemoveAction,
"cssClass": "icon-trash",
"name": "Remove",
"description": "Remove this object from its containing object.",
"depends": [
"openmct",
"navigationService"
]
},
{ {
"key": "save-and-stop-editing", "key": "save-and-stop-editing",
"category": "save", "category": "save",

View File

@@ -49,7 +49,7 @@ define(
name: "Properties", name: "Properties",
rows: this.properties.map(function (property, index) { rows: this.properties.map(function (property, index) {
// Property definition is same as form row definition // Property definition is same as form row definition
var row = JSON.parse(JSON.stringify(property.getDefinition())); var row = Object.create(property.getDefinition());
row.key = index; row.key = index;
return row; return row;
}).filter(function (row) { }).filter(function (row) {

View File

@@ -0,0 +1,140 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/**
* Module defining RemoveAction. Created by vwoeltje on 11/17/14.
*/
define([
'./RemoveDialog'
], function (
RemoveDialog
) {
/**
* Construct an action which will remove the provided object manifestation.
* The object will be removed from its parent's composition; the parent
* is looked up via the "context" capability (so this will be the
* immediate ancestor by which this specific object was reached.)
*
* @param {DialogService} dialogService a service which will show the dialog
* @param {NavigationService} navigationService a service that maintains the current navigation state
* @param {ActionContext} context the context in which this action is performed
* @memberof platform/commonUI/edit
* @constructor
* @implements {Action}
*/
function RemoveAction(openmct, navigationService, context) {
this.domainObject = (context || {}).domainObject;
this.openmct = openmct;
this.navigationService = navigationService;
}
/**
* Perform this action.
*/
RemoveAction.prototype.perform = function () {
var dialog,
domainObject = this.domainObject,
navigationService = this.navigationService;
/*
* Check whether an object ID matches the ID of the object being
* removed (used to filter a parent's composition to handle the
* removal.)
*/
function isNotObject(otherObjectId) {
return otherObjectId !== domainObject.getId();
}
/*
* Mutate a parent object such that it no longer contains the object
* which is being removed.
*/
function doMutate(model) {
model.composition = model.composition.filter(isNotObject);
}
/*
* Checks current object and ascendants of current
* object with object being removed, if the current
* object or any in the current object's path is being removed,
* navigate back to parent of removed object.
*/
function checkObjectNavigation(object, parentObject) {
// Traverse object starts at current location
var traverseObject = (navigationService).getNavigation(),
context;
// Stop when object is not defined (above ROOT)
while (traverseObject) {
// If object currently traversed to is object being removed
// navigate to parent of current object and then exit loop
if (traverseObject.getId() === object.getId()) {
navigationService.setNavigation(parentObject);
return;
}
// Traverses to parent of current object, moving
// up the ascendant path
context = traverseObject.getCapability('context');
traverseObject = context && context.getParent();
}
}
/*
* Remove the object from its parent, as identified by its context
* capability. Based on object's location and selected object's location
* user may be navigated to existing parent object
*/
function removeFromContext() {
var contextCapability = domainObject.getCapability('context'),
parent = contextCapability.getParent();
// If currently within path of removed object(s),
// navigates to existing object up tree
checkObjectNavigation(domainObject, parent);
return parent.useCapability('mutation', doMutate);
}
/*
* Pass in the function to remove the domain object so it can be
* associated with an 'OK' button press
*/
dialog = new RemoveDialog(this.openmct, domainObject, removeFromContext);
dialog.show();
};
// Object needs to have a parent for Remove to be applicable
RemoveAction.appliesTo = function (context) {
var object = (context || {}).domainObject,
contextCapability = object && object.getCapability("context"),
parent = contextCapability && contextCapability.getParent(),
parentType = parent && parent.getCapability('type'),
parentCreatable = parentType && parentType.hasFeature('creation');
// Only creatable types should be modifiable
return parent !== undefined &&
Array.isArray(parent.getModel().composition) &&
parentCreatable;
};
return RemoveAction;
});

View File

@@ -0,0 +1,72 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, 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 () {
/**
* @callback removeCallback
* @param {DomainObject} domainObject the domain object to be removed
*/
/**
* Construct a new Remove dialog.
*
* @param {DialogService} dialogService the service that shows the dialog
* @param {DomainObject} domainObject the domain object to be removed
* @param {removeCallback} removeCallback callback that handles removal of the domain object
* @memberof platform/commonUI/edit
* @constructor
*/
function RemoveDialog(openmct, domainObject, removeCallback) {
this.openmct = openmct;
this.domainObject = domainObject;
this.removeCallback = removeCallback;
}
/**
* Display a dialog to confirm the removal of a domain object.
*/
RemoveDialog.prototype.show = function () {
let dialog = this.openmct.overlays.dialog({
title: 'Remove ' + this.domainObject.getModel().name,
iconClass: 'alert',
message: 'Warning! This action will permanently remove this object. Are you sure you want to continue?',
buttons: [
{
label: 'OK',
callback: () => {
this.removeCallback();
dialog.dismiss();
}
},
{
label: 'Cancel',
callback: () => {
dialog.dismiss();
}
}
]
});
};
return RemoveDialog;
});

View File

@@ -92,7 +92,16 @@ function (
* @memberof platform/commonUI/edit.SaveAction# * @memberof platform/commonUI/edit.SaveAction#
*/ */
SaveAsAction.prototype.perform = function () { SaveAsAction.prototype.perform = function () {
return this.save(); // Discard the current root view (which will be the editing
// UI, which will have been pushed atop the Browse UI.)
function returnToBrowse(object) {
if (object) {
object.getCapability("action").perform("navigate");
}
return object;
}
return this.save().then(returnToBrowse);
}; };
/** /**
@@ -162,6 +171,9 @@ function (
function saveAfterClone(clonedObject) { function saveAfterClone(clonedObject) {
return this.openmct.editor.save().then(() => { return this.openmct.editor.save().then(() => {
// Force mutation for search indexing // Force mutation for search indexing
clonedObject.useCapability('mutation', (model) => {
return model;
});
return clonedObject; return clonedObject;
}) })
} }
@@ -170,14 +182,6 @@ function (
return fetchObject(clonedObject.getId()) return fetchObject(clonedObject.getId())
} }
function indexForSearch(savedObject) {
savedObject.useCapability('mutation', (model) => {
return model;
});
return savedObject;
}
function onSuccess(object) { function onSuccess(object) {
self.notificationService.info("Save Succeeded"); self.notificationService.info("Save Succeeded");
return object; return object;
@@ -188,7 +192,7 @@ function (
if (reason !== "user canceled") { if (reason !== "user canceled") {
self.notificationService.error("Save Failed"); self.notificationService.error("Save Failed");
} }
throw reason; return false;
} }
return getParent(domainObject) return getParent(domainObject)
@@ -199,7 +203,6 @@ function (
.then(undirtyOriginals) .then(undirtyOriginals)
.then(saveAfterClone) .then(saveAfterClone)
.then(finishEditing) .then(finishEditing)
.then(indexForSearch)
.then(hideBlockingDialog) .then(hideBlockingDialog)
.then(onSuccess) .then(onSuccess)
.catch(onFailure); .catch(onFailure);

View File

@@ -64,6 +64,7 @@ define(
* @returns boolean * @returns boolean
*/ */
EditorCapability.prototype.inEditContext = function () { EditorCapability.prototype.inEditContext = function () {
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
return this.openmct.editor.isEditing(); return this.openmct.editor.isEditing();
}; };
@@ -73,6 +74,7 @@ define(
* @returns {*} * @returns {*}
*/ */
EditorCapability.prototype.isEditContextRoot = function () { EditorCapability.prototype.isEditContextRoot = function () {
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
return this.openmct.editor.isEditing(); return this.openmct.editor.isEditing();
}; };

View File

@@ -67,38 +67,20 @@ define(
openmct = this.openmct, openmct = this.openmct,
newObject; newObject;
function onSave() {
// openmct.editor.save();
}
function onCancel() { function onCancel() {
openmct.editor.cancel(); openmct.editor.cancel();
} }
function isFirstViewEditable(domainObject) {
let firstView = openmct.objectViews.get(domainObject)[0];
return firstView && firstView.canEdit && firstView.canEdit(domainObject);
}
function navigateAndEdit(object) {
let objectPath = object.getCapability('context').getPath(),
url = '#/browse/' + objectPath
.slice(1)
.map(function (o) {
return o && openmct.objects.makeKeyString(o.getId());
})
.join('/');
window.location.href = url;
if (isFirstViewEditable(object.useCapability('adapter'))) {
openmct.editor.edit();
}
}
newModel.type = this.type.getKey(); newModel.type = this.type.getKey();
newModel.location = this.parent.getId(); newModel.location = this.parent.getId();
newObject = this.parent.useCapability('instantiation', newModel); newObject = this.parent.useCapability('instantiation', newModel);
openmct.editor.edit(); openmct.editor.edit();
newObject.getCapability("action").perform("save-as").then(navigateAndEdit, onCancel); newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
// TODO: support editing object without saving object first. // TODO: support editing object without saving object first.
// Which means we have to toggle createwizard afterwards. For now, // Which means we have to toggle createwizard afterwards. For now,
// We will disable this. // We will disable this.

View File

@@ -66,7 +66,7 @@ define(
name: "Properties", name: "Properties",
rows: this.properties.map(function (property, index) { rows: this.properties.map(function (property, index) {
// Property definition is same as form row definition // Property definition is same as form row definition
var row = JSON.parse(JSON.stringify(property.getDefinition())); var row = Object.create(property.getDefinition());
// Use index as the key into the formValue; // Use index as the key into the formValue;
// this correlates to the indexing provided by // this correlates to the indexing provided by

View File

@@ -77,19 +77,14 @@ define([], function () {
return promiseFn().then(nextFn); 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);
}
if (!this.isScheduled(id)) {
this.clearTransactionFns[id] = this.clearTransactionFns[id] =
this.transactionService.addToTransaction( this.transactionService.addToTransaction(
chain(onCommit, release), chain(onCommit, release),
chain(onCancel, release) chain(onCancel, release)
); );
}
}; };
/** /**

View File

@@ -0,0 +1,255 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
["../../src/actions/RemoveAction"],
function (RemoveAction) {
describe("The Remove action", function () {
var action,
actionContext,
capabilities,
mockContext,
mockOverlayAPI,
mockDomainObject,
mockMutation,
mockNavigationService,
mockParent,
mockType,
model;
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability", "getModel"]
);
mockMutation = jasmine.createSpyObj("mutation", ["invoke"]);
mockType = jasmine.createSpyObj("type", ["hasFeature"]);
mockType.hasFeature.and.returnValue(true);
capabilities = {
mutation: mockMutation,
type: mockType
};
model = {
composition: ["a", "test", "b"]
};
mockParent = {
getModel: function () {
return model;
},
getCapability: function (k) {
return capabilities[k];
},
useCapability: function (k, v) {
return capabilities[k].invoke(v);
}
};
mockOverlayAPI = jasmine.createSpyObj(
"overlayAPI",
["dialog"]
);
mockNavigationService = jasmine.createSpyObj(
"navigationService",
[
"getNavigation",
"setNavigation",
"addListener",
"removeListener"
]
);
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
mockContext = jasmine.createSpyObj("context", ["getParent"]);
mockContext.getParent.and.returnValue(mockParent);
mockDomainObject.getId.and.returnValue("test");
mockDomainObject.getCapability.and.returnValue(mockContext);
mockDomainObject.getModel.and.returnValue({name: 'test object'});
mockContext.getParent.and.returnValue(mockParent);
mockType.hasFeature.and.returnValue(true);
actionContext = { domainObject: mockDomainObject };
action = new RemoveAction({overlays: mockOverlayAPI}, mockNavigationService, actionContext);
});
it("only applies to objects with parents", function () {
expect(RemoveAction.appliesTo(actionContext)).toBeTruthy();
mockContext.getParent.and.returnValue(undefined);
expect(RemoveAction.appliesTo(actionContext)).toBeFalsy();
// Also verify that creatability was checked
expect(mockType.hasFeature).toHaveBeenCalledWith('creation');
});
it("shows a blocking message dialog", function () {
mockParent = jasmine.createSpyObj(
"parent",
["getModel", "getCapability", "useCapability"]
);
action.perform();
expect(mockOverlayAPI.dialog).toHaveBeenCalled();
// Also check that no mutation happens at this point
expect(mockParent.useCapability).not.toHaveBeenCalledWith("mutation", jasmine.any(Function));
});
describe("after the remove callback is triggered", function () {
var mockChildContext,
mockChildObject,
mockDialogHandle,
mockGrandchildContext,
mockGrandchildObject,
mockRootContext,
mockRootObject;
beforeEach(function () {
mockChildObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
);
mockDialogHandle = jasmine.createSpyObj(
"dialogHandle",
["dismiss"]
);
mockGrandchildObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
);
mockRootObject = jasmine.createSpyObj(
"domainObject",
["getId", "getCapability"]
);
mockChildContext = jasmine.createSpyObj("context", ["getParent"]);
mockGrandchildContext = jasmine.createSpyObj("context", ["getParent"]);
mockRootContext = jasmine.createSpyObj("context", ["getParent"]);
mockOverlayAPI.dialog.and.returnValue(mockDialogHandle);
});
it("mutates the parent when performed", function () {
action.perform();
mockOverlayAPI.dialog.calls.mostRecent().args[0]
.buttons[0].callback();
expect(mockMutation.invoke)
.toHaveBeenCalledWith(jasmine.any(Function));
});
it("changes composition from its mutation function", function () {
var mutator, result;
action.perform();
mockOverlayAPI.dialog.calls.mostRecent().args[0]
.buttons[0].callback();
mutator = mockMutation.invoke.calls.mostRecent().args[0];
result = mutator(model);
// Should not have cancelled the mutation
expect(result).not.toBe(false);
// Simulate mutate's behavior (remove can either return a
// new model or modify this one in-place)
result = result || model;
// Should have removed "test" - that was our
// mock domain object's id.
expect(result.composition).toEqual(["a", "b"]);
});
it("removes parent of object currently navigated to", function () {
// Navigates to child object
mockNavigationService.getNavigation.and.returnValue(mockChildObject);
// Test is id of object being removed
// Child object has different id
mockDomainObject.getId.and.returnValue("test");
mockChildObject.getId.and.returnValue("not test");
// Sets context for the child and domainObject
mockDomainObject.getCapability.and.returnValue(mockContext);
mockChildObject.getCapability.and.returnValue(mockChildContext);
// Parents of child and domainObject are set
mockContext.getParent.and.returnValue(mockParent);
mockChildContext.getParent.and.returnValue(mockDomainObject);
mockType.hasFeature.and.returnValue(true);
action.perform();
mockOverlayAPI.dialog.calls.mostRecent().args[0]
.buttons[0].callback();
// Expects navigation to parent of domainObject (removed object)
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
});
it("checks if removing object not in ascendent path (reaches ROOT)", function () {
// Navigates to grandchild of ROOT
mockNavigationService.getNavigation.and.returnValue(mockGrandchildObject);
// domainObject (grandparent) is set as ROOT, child and grandchild
// are set objects not being removed
mockDomainObject.getId.and.returnValue("test 1");
mockRootObject.getId.and.returnValue("ROOT");
mockChildObject.getId.and.returnValue("not test 2");
mockGrandchildObject.getId.and.returnValue("not test 3");
// Sets context for the grandchild, child, and domainObject
mockRootObject.getCapability.and.returnValue(mockRootContext);
mockChildObject.getCapability.and.returnValue(mockChildContext);
mockGrandchildObject.getCapability.and.returnValue(mockGrandchildContext);
// Parents of grandchild and child are set
mockChildContext.getParent.and.returnValue(mockRootObject);
mockGrandchildContext.getParent.and.returnValue(mockChildObject);
mockType.hasFeature.and.returnValue(true);
action.perform();
mockOverlayAPI.dialog.calls.mostRecent().args[0]
.buttons[0].callback();
// Expects no navigation to occur
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
});
});
});
}
);

View File

@@ -25,7 +25,7 @@ define(
["../../src/actions/SaveAsAction"], ["../../src/actions/SaveAsAction"],
function (SaveAsAction) { function (SaveAsAction) {
xdescribe("The Save As action", function () { describe("The Save As action", function () {
var mockDomainObject, var mockDomainObject,
mockClonedObject, mockClonedObject,
mockEditorCapability, mockEditorCapability,

View File

@@ -24,7 +24,7 @@ define(
["../../src/capabilities/EditorCapability"], ["../../src/capabilities/EditorCapability"],
function (EditorCapability) { function (EditorCapability) {
xdescribe("The editor capability", function () { describe("The editor capability", function () {
var mockDomainObject, var mockDomainObject,
capabilities, capabilities,
mockParentObject, mockParentObject,

View File

@@ -27,7 +27,7 @@ define(
["../../src/creation/CreateAction"], ["../../src/creation/CreateAction"],
function (CreateAction) { function (CreateAction) {
xdescribe("The create action", function () { describe("The create action", function () {
var mockType, var mockType,
mockParent, mockParent,
mockContext, mockContext,

View File

@@ -27,7 +27,7 @@ define(
["../../src/creation/CreateWizard"], ["../../src/creation/CreateWizard"],
function (CreateWizard) { function (CreateWizard) {
xdescribe("The create wizard", function () { describe("The create wizard", function () {
var mockType, var mockType,
mockParent, mockParent,
mockProperties, mockProperties,

View File

@@ -93,33 +93,24 @@ define(
expect(mockOnCancel).toHaveBeenCalled(); expect(mockOnCancel).toHaveBeenCalled();
}); });
describe("Adds callbacks to transaction", function () { it("ignores subsequent calls for the same object", function () {
beforeEach(function () {
spyOn(manager, 'clearTransactionsFor');
manager.clearTransactionsFor.and.callThrough();
});
it("and clears pending calls if same object", function () {
manager.addToTransaction( manager.addToTransaction(
testId, testId,
jasmine.createSpy(), jasmine.createSpy(),
jasmine.createSpy() jasmine.createSpy()
); );
expect(manager.clearTransactionsFor).toHaveBeenCalledWith(testId); expect(mockTransactionService.addToTransaction.calls.count())
.toEqual(1);
}); });
it("and does not clear pending calls if different object", function () { it("accepts subsequent calls for other objects", function () {
manager.addToTransaction( manager.addToTransaction(
'other-id', 'other-id',
jasmine.createSpy(), jasmine.createSpy(),
jasmine.createSpy() jasmine.createSpy()
); );
expect(manager.clearTransactionsFor).not.toHaveBeenCalled(); expect(mockTransactionService.addToTransaction.calls.count())
}); .toEqual(2);
afterEach(function () {
expect(mockTransactionService.addToTransaction.calls.count()).toEqual(2);
});
}); });
it("does not remove callbacks from the transaction", function () { it("does not remove callbacks from the transaction", function () {

View File

@@ -20,7 +20,8 @@
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! --> <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="c-indicator {{ngModel.getCssClass()}}" <div class="ls-indicator {{ngModel.getCssClass()}}"
title="{{ngModel.getDescription()}}"
ng-show="ngModel.getText().length > 0"> ng-show="ngModel.getText().length > 0">
<span class="label c-indicator__label">{{ngModel.getText()}}</span> <span class="label">{{ngModel.getText()}}</span>
</div> </div>

View File

@@ -19,7 +19,7 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<div class="c-object-label"> <div class="t-object-label l-flex-row flex-elem grows">
<div class="c-object-label__type-icon {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div> <div class="t-item-icon flex-elem {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div>
<div class='c-object-label__name'>{{model.name}}</div> <div class='t-title-label flex-elem grows'>{{model.name}}</div>
</div> </div>

View File

@@ -1,13 +1,13 @@
<div ng-controller="BannerController" ng-show="active.notification" <div ng-controller="BannerController" ng-show="active.notification"
class="c-message-banner {{active.notification.model.severity}}" ng-class="{ class="l-message-banner s-message-banner {{active.notification.model.severity}}" ng-class="{
'minimized': active.notification.model.minimized, 'minimized': active.notification.model.minimized,
'new': !active.notification.model.minimized}" 'new': !active.notification.model.minimized}"
ng-click="maximize(active.notification)"> ng-click="maximize(active.notification)">
<span class="c-message-banner__message"> <span class="banner-elem label">
{{active.notification.model.title}} {{active.notification.model.title}}
</span> </span>
<span ng-show="active.notification.model.progress !== undefined || active.notification.model.unknownProgress"> <span ng-show="active.notification.model.progress !== undefined || active.notification.model.unknownProgress">
<mct-include key="'progress-bar'" class="c-message-banner__progress-bar" <mct-include key="'progress-bar'" class="banner-elem"
ng-model="active.notification.model"> ng-model="active.notification.model">
</mct-include> </mct-include>
</span> </span>
@@ -16,5 +16,5 @@
ng-click="action(active.notification.model.primaryOption.callback, $event)"> ng-click="action(active.notification.model.primaryOption.callback, $event)">
{{active.notification.model.primaryOption.label}} {{active.notification.model.primaryOption.label}}
</a> </a>
<button class="c-message-banner__close-button c-click-icon icon-x-in-circle" ng-click="dismiss(active.notification, $event)"></button> <a class="banner-elem close icon-x" ng-click="dismiss(active.notification, $event)"></a>
</div> </div>

View File

@@ -20,11 +20,14 @@
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<span ng-controller="ToggleController as toggle"> <span ng-controller="ToggleController as toggle">
<div class="u-contents" ng-controller="TreeNodeController as treeNode"> <span ng-controller="TreeNodeController as treeNode">
<div class="c-tree__item menus-to-left" <span
ng-class="{selected: treeNode.isSelected()}"> class="tree-item menus-to-left"
<span class='c-disclosure-triangle c-tree__item__view-control' ng-class="{selected: treeNode.isSelected()}"
ng-class="{ 'is-enabled': model.composition !== undefined, 'c-disclosure-triangle--expanded': toggle.isActive() }" >
<span
class='ui-symbol view-control flex-elem'
ng-class="{ 'has-children': model.composition !== undefined, expanded: toggle.isActive() }"
ng-click="toggle.toggle(); treeNode.trackExpansion()" ng-click="toggle.toggle(); treeNode.trackExpansion()"
> >
</span> </span>
@@ -36,15 +39,19 @@
ng-click="treeNode.select()" ng-click="treeNode.select()"
> >
</mct-representation> </mct-representation>
</div> </span>
<div class="u-contents" <span
class="tree-item-subtree"
ng-show="toggle.isActive()" ng-show="toggle.isActive()"
ng-if="model.composition !== undefined"> ng-if="model.composition !== undefined"
>
<mct-representation key="'subtree'" <mct-representation key="'subtree'"
ng-model="ngModel" ng-model="ngModel"
parameters="parameters" parameters="parameters"
mct-object="treeNode.hasBeenExpanded() && domainObject"> mct-object="treeNode.hasBeenExpanded() && domainObject">
</mct-representation> </mct-representation>
</div>
</div> </span>
</span>
</span> </span>

View File

@@ -19,8 +19,8 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<ul class="c-tree"> <ul class="tree">
<li class="c-tree__item-h"> <li>
<mct-representation key="'tree-node'" <mct-representation key="'tree-node'"
mct-object="domainObject" mct-object="domainObject"
ng-model="ngModel" ng-model="ngModel"

View File

@@ -1,2 +1,4 @@
<span class="c-tree__item js-tree__item"></span> <span class="tree-item menus-to-left">
<span class="c-tree__item-subtree"></span> </span>
<span class="tree-item-subtree">
</span>

View File

@@ -1 +1,2 @@
<span class='c-disclosure-triangle c-tree__item__view-control'></span> <span class='ui-symbol view-control flex-elem'>
</span>

View File

@@ -1,4 +1,6 @@
<div class="rep-object-label c-object-label c-tree__item__label"> <span class="rep-object-label">
<div class="c-object-label__type-icon c-tree__item__type-icon t-item-icon"></div> <div class="t-object-label l-flex-row flex-elem grows">
<div class="c-object-label__name c-tree__item__name t-title-label"></div> <div class="t-item-icon flex-elem"></div>
</div> <div class='t-title-label flex-elem grows'></div>
</div>
</span>

View File

@@ -54,7 +54,6 @@ define(
if (isDestroyed) { if (isDestroyed) {
return; return;
} }
var removeSelectable = openmct.selection.selectable( var removeSelectable = openmct.selection.selectable(
element[0], element[0],
scope.$eval(attrs.mctSelectable), scope.$eval(attrs.mctSelectable),

View File

@@ -37,9 +37,9 @@ define([
this.expanded = state; this.expanded = state;
if (state) { if (state) {
this.el.addClass('c-disclosure-triangle--expanded'); this.el.addClass('expanded');
} else { } else {
this.el.removeClass('c-disclosure-triangle--expanded'); this.el.removeClass('expanded');
} }
this.callbacks.forEach(function (callback) { this.callbacks.forEach(function (callback) {

View File

@@ -28,7 +28,7 @@ define([
], function ($, nodeTemplate, ToggleView, TreeLabelView) { ], function ($, nodeTemplate, ToggleView, TreeLabelView) {
function TreeNodeView(gestureService, subtreeFactory, selectFn, openmct) { function TreeNodeView(gestureService, subtreeFactory, selectFn, openmct) {
this.li = $('<li class="c-tree__item-h">'); this.li = $('<li>');
this.openmct = openmct; this.openmct = openmct;
this.statusClasses = []; this.statusClasses = [];
@@ -38,7 +38,7 @@ define([
if (!this.subtreeView) { if (!this.subtreeView) {
this.subtreeView = subtreeFactory(); this.subtreeView = subtreeFactory();
this.subtreeView.model(this.activeObject); this.subtreeView.model(this.activeObject);
this.li.find('.c-tree__item-subtree').eq(0) this.li.find('.tree-item-subtree').eq(0)
.append($(this.subtreeView.elements())); .append($(this.subtreeView.elements()));
} }
$(this.subtreeView.elements()).removeClass('hidden'); $(this.subtreeView.elements()).removeClass('hidden');
@@ -85,9 +85,9 @@ define([
var obj = domainObject.useCapability('adapter'); var obj = domainObject.useCapability('adapter');
var hasComposition = this.openmct.composition.get(obj) !== undefined; var hasComposition = this.openmct.composition.get(obj) !== undefined;
if (hasComposition) { if (hasComposition) {
$(this.toggleView.elements()).addClass('is-enabled'); $(this.toggleView.elements()).removeClass('no-children');
} else { } else {
$(this.toggleView.elements()).removeClass('is-enabled'); $(this.toggleView.elements()).addClass('no-children');
} }
} }
@@ -120,7 +120,7 @@ define([
selectedIdPath = getIdPath(domainObject); selectedIdPath = getIdPath(domainObject);
if (this.onSelectionPath) { if (this.onSelectionPath) {
this.li.find('.js-tree__item').eq(0).removeClass('is-selected'); this.li.find('.tree-item').eq(0).removeClass('selected');
if (this.subtreeView) { if (this.subtreeView) {
this.subtreeView.value(undefined); this.subtreeView.value(undefined);
} }
@@ -136,7 +136,7 @@ define([
if (this.onSelectionPath) { if (this.onSelectionPath) {
if (activeIdPath.length === selectedIdPath.length) { if (activeIdPath.length === selectedIdPath.length) {
this.li.find('.js-tree__item').eq(0).addClass('is-selected'); this.li.find('.tree-item').eq(0).addClass('selected');
} else { } else {
// Expand to reveal the selection // Expand to reveal the selection
this.toggleView.value(true); this.toggleView.value(true);

View File

@@ -27,7 +27,7 @@ define([
], function ($, TreeNodeView, spinnerTemplate) { ], function ($, TreeNodeView, spinnerTemplate) {
function TreeView(gestureService, openmct, selectFn) { function TreeView(gestureService, openmct, selectFn) {
this.ul = $('<ul class="c-tree"></ul>'); this.ul = $('<ul class="tree"></ul>');
this.nodeViews = []; this.nodeViews = [];
this.callbacks = []; this.callbacks = [];
this.selectFn = selectFn || this.value.bind(this); this.selectFn = selectFn || this.value.bind(this);

View File

@@ -26,7 +26,7 @@ define([
'zepto' 'zepto'
], function (TreeView, $) { ], function (TreeView, $) {
xdescribe("TreeView", function () { describe("TreeView", function () {
var mockGestureService, var mockGestureService,
mockGestureHandle, mockGestureHandle,
mockDomainObject, mockDomainObject,

View File

@@ -1,8 +1,8 @@
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! --> <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div ng-show="notifications.length > 0" class="c-indicator c-indicator--clickable s-status-{{highest.severity}} icon-bell" <div ng-show="notifications.length > 0" class="ls-indicator s-status-{{highest.severity}} icon-bell"
ng-controller="NotificationIndicatorController"> ng-controller="NotificationIndicatorController">
<span class="label c-indicator__label"> <span class="label">
<button ng-click="showNotificationsList()"> <a ng-click="showNotificationsList()">
{{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></button> {{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></a>
</span><span class="c-indicator__count">{{notifications.length}}</span> </span><span class="count">{{notifications.length}}</span>
</div> </div>

View File

@@ -24,7 +24,7 @@ define(
['../src/NotificationIndicatorController'], ['../src/NotificationIndicatorController'],
function (NotificationIndicatorController) { function (NotificationIndicatorController) {
xdescribe("The notification indicator controller ", function () { describe("The notification indicator controller ", function () {
var mockNotificationService, var mockNotificationService,
mockScope, mockScope,
mockDialogService, mockDialogService,

View File

@@ -23,7 +23,7 @@
define( define(
["../src/ComposeActionPolicy"], ["../src/ComposeActionPolicy"],
function (ComposeActionPolicy) { function (ComposeActionPolicy) {
xdescribe("The compose action policy", function () { describe("The compose action policy", function () {
var mockInjector, var mockInjector,
mockPolicyService, mockPolicyService,
mockTypes, mockTypes,

View File

@@ -43,10 +43,23 @@ define([], function () {
var mutationTopic = topic('mutation'); var mutationTopic = topic('mutation');
mutationTopic.listen(function (domainObject) { mutationTopic.listen(function (domainObject) {
var persistence = domainObject.getCapability('persistence'); var persistence = domainObject.getCapability('persistence');
var wasActive = transactionService.isActive();
cacheService.put(domainObject.getId(), domainObject.getModel()); cacheService.put(domainObject.getId(), domainObject.getModel());
if (hasChanged(domainObject)) { if (hasChanged(domainObject)) {
persistence.persist();
if (!wasActive) {
transactionService.startTransaction();
}
transactionService.addToTransaction(
persistence.persist.bind(persistence),
persistence.refresh.bind(persistence)
);
if (!wasActive) {
transactionService.commit();
}
} }
}); });
} }

View File

@@ -24,27 +24,22 @@ define(
["../../src/runs/TransactingMutationListener"], ["../../src/runs/TransactingMutationListener"],
function (TransactingMutationListener) { function (TransactingMutationListener) {
describe("TransactingMutationListener", function () { xdescribe("TransactingMutationListener", function () {
var mockTopic, var mockTopic,
mockMutationTopic, mockMutationTopic,
mockCacheService,
mockTransactionService, mockTransactionService,
mockDomainObject, mockDomainObject,
mockModel,
mockPersistence; mockPersistence;
beforeEach(function () { beforeEach(function () {
mockTopic = jasmine.createSpy('topic'); mockTopic = jasmine.createSpy('topic');
mockMutationTopic = mockMutationTopic =
jasmine.createSpyObj('mutation', ['listen']); jasmine.createSpyObj('mutation', ['listen']);
mockCacheService =
jasmine.createSpyObj('cacheService', [
'put'
]);
mockTransactionService = mockTransactionService =
jasmine.createSpyObj('transactionService', [ jasmine.createSpyObj('transactionService', [
'isActive', 'isActive',
'startTransaction', 'startTransaction',
'addToTransaction',
'commit' 'commit'
]); ]);
mockDomainObject = jasmine.createSpyObj( mockDomainObject = jasmine.createSpyObj(
@@ -57,24 +52,18 @@ define(
); );
mockTopic.and.callFake(function (t) { mockTopic.and.callFake(function (t) {
expect(t).toBe('mutation'); return (t === 'mutation') && mockMutationTopic;
return mockMutationTopic;
}); });
mockDomainObject.getId.and.returnValue('mockId');
mockDomainObject.getCapability.and.callFake(function (c) { mockDomainObject.getCapability.and.callFake(function (c) {
expect(c).toBe('persistence'); return (c === 'persistence') && mockPersistence;
return mockPersistence;
}); });
mockModel = {};
mockDomainObject.getModel.and.returnValue(mockModel);
mockPersistence.persisted.and.returnValue(true); mockPersistence.persisted.and.returnValue(true);
return new TransactingMutationListener( return new TransactingMutationListener(
mockTopic, mockTopic,
mockTransactionService, mockTransactionService
mockCacheService
); );
}); });
@@ -83,27 +72,48 @@ define(
.toHaveBeenCalledWith(jasmine.any(Function)); .toHaveBeenCalledWith(jasmine.any(Function));
}); });
it("calls persist if the model has changed", function () { [false, true].forEach(function (isActive) {
mockModel.persisted = Date.now(); var verb = isActive ? "is" : "isn't";
//Mark the model dirty by setting the mutated date later than the last persisted date. function onlyWhenInactive(expectation) {
mockModel.modified = mockModel.persisted + 1; return isActive ? expectation.not : expectation;
}
mockMutationTopic.listen.calls.mostRecent() describe("when a transaction " + verb + " active", function () {
.args[0](mockDomainObject); var innerVerb = isActive ? "does" : "doesn't";
expect(mockPersistence.persist).toHaveBeenCalled(); beforeEach(function () {
mockTransactionService.isActive.and.returnValue(isActive);
}); });
it("does not call persist if the model has not changed", function () { describe("and mutation occurs", function () {
mockModel.persisted = Date.now(); beforeEach(function () {
mockModel.modified = mockModel.persisted;
mockMutationTopic.listen.calls.mostRecent() mockMutationTopic.listen.calls.mostRecent()
.args[0](mockDomainObject); .args[0](mockDomainObject);
});
expect(mockPersistence.persist).not.toHaveBeenCalled();
it(innerVerb + " start a new transaction", function () {
onlyWhenInactive(
expect(mockTransactionService.startTransaction)
).toHaveBeenCalled();
});
it("adds to the active transaction", function () {
expect(mockTransactionService.addToTransaction)
.toHaveBeenCalledWith(
jasmine.any(Function),
jasmine.any(Function)
);
});
it(innerVerb + " immediately commit", function () {
onlyWhenInactive(
expect(mockTransactionService.commit)
).toHaveBeenCalled();
});
});
});
}); });
}); });
} }

View File

@@ -24,6 +24,7 @@ define([
"./src/actions/MoveAction", "./src/actions/MoveAction",
"./src/actions/CopyAction", "./src/actions/CopyAction",
"./src/actions/LinkAction", "./src/actions/LinkAction",
"./src/actions/GoToOriginalAction",
"./src/actions/SetPrimaryLocationAction", "./src/actions/SetPrimaryLocationAction",
"./src/services/LocatingCreationDecorator", "./src/services/LocatingCreationDecorator",
"./src/services/LocatingObjectDecorator", "./src/services/LocatingObjectDecorator",
@@ -40,6 +41,7 @@ define([
MoveAction, MoveAction,
CopyAction, CopyAction,
LinkAction, LinkAction,
GoToOriginalAction,
SetPrimaryLocationAction, SetPrimaryLocationAction,
LocatingCreationDecorator, LocatingCreationDecorator,
LocatingObjectDecorator, LocatingObjectDecorator,
@@ -102,6 +104,14 @@ define([
"linkService" "linkService"
] ]
}, },
{
"key": "follow",
"name": "Go To Original",
"description": "Go to the original, un-linked instance of this object.",
"cssClass": "",
"category": "contextual",
"implementation": GoToOriginalAction
},
{ {
"key": "locate", "key": "locate",
"name": "Set Primary Location", "name": "Set Primary Location",

View File

@@ -0,0 +1,60 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
function () {
/**
* Implements the "Go To Original" action, which follows a link back
* to an original instance of an object.
*
* @implements {Action}
* @constructor
* @private
* @memberof platform/entanglement
* @param {ActionContext} context the context in which the action
* will be performed
*/
function GoToOriginalAction(context) {
this.domainObject = context.domainObject;
}
GoToOriginalAction.prototype.perform = function () {
return this.domainObject.getCapability("location").getOriginal()
.then(function (originalObject) {
var actionCapability =
originalObject.getCapability("action");
return actionCapability &&
actionCapability.perform("navigate");
});
};
GoToOriginalAction.appliesTo = function (context) {
var domainObject = context.domainObject;
return domainObject && domainObject.hasCapability("location") &&
domainObject.getCapability("location").isLink();
};
return GoToOriginalAction;
}
);

View File

@@ -0,0 +1,93 @@
/*****************************************************************************
* 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.
*****************************************************************************/
define(
[
'../../src/actions/GoToOriginalAction',
'../DomainObjectFactory',
'../ControlledPromise'
],
function (GoToOriginalAction, domainObjectFactory, ControlledPromise) {
describe("The 'go to original' action", function () {
var testContext,
originalDomainObject,
mockLocationCapability,
mockOriginalActionCapability,
originalPromise,
action;
beforeEach(function () {
mockLocationCapability = jasmine.createSpyObj(
'location',
['isLink', 'isOriginal', 'getOriginal']
);
mockOriginalActionCapability = jasmine.createSpyObj(
'action',
['perform', 'getActions']
);
originalPromise = new ControlledPromise();
mockLocationCapability.getOriginal.and.returnValue(originalPromise);
mockLocationCapability.isLink.and.returnValue(true);
mockLocationCapability.isOriginal.and.callFake(function () {
return !mockLocationCapability.isLink();
});
testContext = {
domainObject: domainObjectFactory({
capabilities: {
location: mockLocationCapability
}
})
};
originalDomainObject = domainObjectFactory({
capabilities: {
action: mockOriginalActionCapability
}
});
action = new GoToOriginalAction(testContext);
});
it("is applicable to links", function () {
expect(GoToOriginalAction.appliesTo(testContext))
.toBeTruthy();
});
it("is not applicable to originals", function () {
mockLocationCapability.isLink.and.returnValue(false);
expect(GoToOriginalAction.appliesTo(testContext))
.toBeFalsy();
});
it("navigates to original objects when performed", function () {
expect(mockOriginalActionCapability.perform)
.not.toHaveBeenCalled();
action.perform();
originalPromise.resolve(originalDomainObject);
expect(mockOriginalActionCapability.perform)
.toHaveBeenCalledWith('navigate');
});
});
}
);

View File

@@ -42,7 +42,7 @@ define(
return promise; return promise;
} }
xdescribe("CopyService", function () { describe("CopyService", function () {
var policyService; var policyService;
beforeEach(function () { beforeEach(function () {

View File

@@ -29,7 +29,7 @@ define(
], ],
function (LinkService, domainObjectFactory, ControlledPromise) { function (LinkService, domainObjectFactory, ControlledPromise) {
xdescribe("LinkService", function () { describe("LinkService", function () {
var linkService, var linkService,
mockPolicyService; mockPolicyService;

View File

@@ -34,7 +34,7 @@ define(
ControlledPromise ControlledPromise
) { ) {
xdescribe("MoveService", function () { describe("MoveService", function () {
var moveService, var moveService,
policyService, policyService,

View File

@@ -24,10 +24,10 @@
<button ng-click="timer.clickStopButton()" <button ng-click="timer.clickStopButton()"
ng-hide="timer.timerState == 'stopped'" ng-hide="timer.timerState == 'stopped'"
title="Reset" title="Reset"
class="c-timer__ctrl-reset c-icon-button c-icon-button--major icon-reset"></button> class="c-timer__ctrl-reset c-click-icon c-click-icon--major icon-reset"></button>
<button ng-click="timer.clickButton()" <button ng-click="timer.clickButton()"
title="{{timer.buttonText()}}" title="{{timer.buttonText()}}"
class="c-timer__ctrl-pause-play c-icon-button c-icon-button--major {{timer.buttonCssClass()}}"></button> class="c-timer__ctrl-pause-play c-click-icon c-click-icon--major {{timer.buttonCssClass()}}"></button>
</div> </div>
<div class="c-timer__direction {{timer.signClass()}}" <div class="c-timer__direction {{timer.signClass()}}"
ng-hide="!timer.signClass()"></div> ng-hide="!timer.signClass()"></div>

View File

@@ -49,7 +49,7 @@ define(
}; };
ClockIndicator.prototype.getCssClass = function () { ClockIndicator.prototype.getCssClass = function () {
return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable"; return "t-indicator-clock icon-clock no-collapse float-right";
}; };
ClockIndicator.prototype.getText = function () { ClockIndicator.prototype.getText = function () {

View File

@@ -31,7 +31,7 @@ define([
MCT, MCT,
$ $
) { ) {
xdescribe("The timer-following indicator", function () { describe("The timer-following indicator", function () {
var timerService; var timerService;
var openmct; var openmct;

View File

@@ -45,6 +45,7 @@ define([
"key": "url", "key": "url",
"name": "URL", "name": "URL",
"control": "textfield", "control": "textfield",
"pattern": "^(ftp|https?)\\:\\/\\/",
"required": true, "required": true,
"cssClass": "l-input-lg" "cssClass": "l-input-lg"
}, },

View File

@@ -1,18 +1,22 @@
<div class="t-imagery c-imagery" ng-controller="ImageryController as imagery"> <div class="t-imagery" ng-controller="ImageryController as imagery">
<mct-split-pane class='abs' anchor="bottom" alias="imagery"> <mct-split-pane class='abs' anchor="bottom" alias="imagery">
<div class="split-pane-component has-local-controls l-image-main-wrapper l-flex-col"> <div class="split-pane-component has-local-controls l-image-main-wrapper l-flex-col"
<div class="h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover l-flex-row c-imagery__lc"> ng-mouseenter="showLocalControls = true;"
<span class="holder flex-elem grows c-imagery__lc__sliders"> ng-mouseleave="showLocalControls = false;">
<div class="h-local-controls h-local-controls-overlay-content h-local-controls-trans s-local-controls local-controls-hidden l-flex-row">
<span class="holder flex-elem grows">
<input class="icon-brightness" type="range" <input class="icon-brightness" type="range"
min="0" min="0"
max="500" max="500"
ng-model="filters.brightness" /> ng-model="filters.brightness">
</input>
<input class="icon-contrast" type="range" <input class="icon-contrast" type="range"
min="0" min="0"
max="500" max="500"
ng-model="filters.contrast" /> ng-model="filters.contrast">
</input>
</span> </span>
<span class="holder flex-elem t-reset-btn-holder c-imagery__lc__reset-btn"> <span class="holder flex-elem t-reset-btn-holder">
<a class="s-icon-button icon-reset t-btn-reset" <a class="s-icon-button icon-reset t-btn-reset"
ng-click="filters = { brightness: 100, contrast: 100 }"></a> ng-click="filters = { brightness: 100, contrast: 100 }"></a>
</span> </span>
@@ -29,14 +33,14 @@
<div class="l-image-main-controlbar flex-elem l-flex-row"> <div class="l-image-main-controlbar flex-elem l-flex-row">
<div class="l-datetime-w flex-elem grows"> <div class="l-datetime-w flex-elem grows">
<a class="c-button show-thumbs sm hidden icon-thumbs-strip" <a class="s-button show-thumbs sm hidden icon-thumbs-strip"
ng-click="showThumbsBubble = (showThumbsBubble) ? false:true"></a> ng-click="showThumbsBubble = (showThumbsBubble) ? false:true"></a>
<span class="l-time">{{imagery.getTime()}}</span> <span class="l-time">{{imagery.getTime()}}</span>
</div> </div>
<div class="h-local-controls flex-elem"> <div class="h-local-controls flex-elem">
<a class="c-button icon-pause pause-play" <a class="s-button pause-play"
ng-click="imagery.paused(!imagery.paused())" ng-click="imagery.paused(!imagery.paused())"
ng-class="{ 'is-paused': imagery.paused() }"></a> ng-class="{ paused: imagery.paused() }"></a>
<a href="" <a href=""
class="s-button l-mag s-mag vsm icon-reset" class="s-button l-mag s-mag vsm icon-reset"
ng-click="clipped = false" ng-click="clipped = false"

View File

@@ -30,7 +30,7 @@ define(
var MOCK_ELEMENT_TEMPLATE = var MOCK_ELEMENT_TEMPLATE =
'<div class="l-image-thumbs-wrapper"></div>'; '<div class="l-image-thumbs-wrapper"></div>';
xdescribe("The Imagery controller", function () { describe("The Imagery controller", function () {
var $scope, var $scope,
openmct, openmct,
oldDomainObject, oldDomainObject,

View File

@@ -47,6 +47,7 @@ define([
"key": "url", "key": "url",
"name": "URL", "name": "URL",
"control": "textfield", "control": "textfield",
"pattern": "^(ftp|https?)\\:\\/\\/",
"required": true, "required": true,
"cssClass": "l-input-lg" "cssClass": "l-input-lg"
} }

View File

@@ -19,13 +19,13 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<form name="mctForm" novalidate class="form c-form" autocomplete="off"> <form name="mctForm" novalidate class="form l-flex-col">
<span ng-repeat="section in structure.sections" <span ng-repeat="section in structure.sections"
class="l-form-section c-form__section {{ section.cssClass }}"> class="l-form-section l-flex-col flex-elem {{ section.cssClass }}">
<h2 class="c-form__header" ng-if="section.name"> <h2 class="section-header flex-elem" ng-if="section.name">
{{section.name}} {{section.name}}
</h2> </h2>
<ng-form class="form-row c-form__row validates {{ section.cssClass }}" <ng-form class="form-row validates l-flex-row flex-elem {{ section.cssClass }}"
ng-class="{ ng-class="{
first:$index < 1, first:$index < 1,
req: row.required, req: row.required,
@@ -37,11 +37,11 @@
}" }"
name="mctFormInner" name="mctFormInner"
ng-repeat="row in section.rows"> ng-repeat="row in section.rows">
<div class='c-form__row__label label flex-elem' title="{{row.description}}"> <div class='label flex-elem' title="{{row.description}}">
{{row.name}} {{row.name}}
</div> </div>
<div class='c-form__row__controls controls flex-elem'> <div class='controls flex-elem'>
<div class="c-form__controls-wrapper wrapper" ng-if="row.control"> <div class="wrapper" ng-if="row.control">
<mct-control key="row.control" <mct-control key="row.control"
ng-model="ngModel" ng-model="ngModel"
ng-required="row.required" ng-required="row.required"

View File

@@ -29,13 +29,12 @@ define(
function SnapshotPreviewController($scope, openmct) { function SnapshotPreviewController($scope, openmct) {
$scope.previewImage = function (imageUrl) { $scope.previewImage = function (imageUrl) {
let imageDiv = document.createElement('div'); let image = document.createElement('img');
imageDiv.classList = 'image-main s-image-main'; image.src = imageUrl;
imageDiv.style.backgroundImage = `url(${imageUrl})`;
let previewImageOverlay = openmct.overlays.overlay( let previewImageOverlay = openmct.overlays.overlay(
{ {
element: imageDiv, element: image,
size: 'large', size: 'large',
buttons: [ buttons: [
{ {

View File

@@ -24,7 +24,7 @@ define(
["../src/MCTFileInput"], ["../src/MCTFileInput"],
function (MCTFileInput) { function (MCTFileInput) {
xdescribe("The mct-file-input directive", function () { describe("The mct-file-input directive", function () {
var mockScope, var mockScope,
mockFileInputService, mockFileInputService,

View File

@@ -55,13 +55,13 @@ define([
FrameworkLayer.prototype.initializeApplication = function ( FrameworkLayer.prototype.initializeApplication = function (
angular, angular,
openmct, legacyRegistry,
logLevel logLevel
) { ) {
var $http = this.$http, var $http = this.$http,
$log = this.$log, $log = this.$log,
app = angular.module(Constants.MODULE_NAME, ["ngRoute"]), app = angular.module(Constants.MODULE_NAME, ["ngRoute"]),
loader = new BundleLoader($http, $log, openmct.legacyRegistry), loader = new BundleLoader($http, $log, legacyRegistry),
resolver = new BundleResolver( resolver = new BundleResolver(
new ExtensionResolver( new ExtensionResolver(
new ImplementationLoader({}), new ImplementationLoader({}),
@@ -77,7 +77,7 @@ define([
), ),
bootstrapper = new ApplicationBootstrapper( bootstrapper = new ApplicationBootstrapper(
angular, angular,
openmct.element, window.document,
$log $log
), ),
initializer = new FrameworkInitializer( initializer = new FrameworkInitializer(

View File

@@ -41,7 +41,7 @@ define(
function Main() { function Main() {
} }
Main.prototype.run = function (openmct) { Main.prototype.run = function (legacyRegistry) {
// Get a reference to Angular's injector, so we can get $http and $log // Get a reference to Angular's injector, so we can get $http and $log
// services, which are useful to the framework layer. // services, which are useful to the framework layer.
var injector = angular.injector(['ng']); var injector = angular.injector(['ng']);
@@ -53,7 +53,7 @@ define(
} }
return injector.instantiate(['$http', '$log', FrameworkLayer]) return injector.instantiate(['$http', '$log', FrameworkLayer])
.initializeApplication(angular, openmct, logLevel()); .initializeApplication(angular, legacyRegistry, logLevel());
}; };
return Main; return Main;

View File

@@ -72,6 +72,7 @@ define([
] ]
} }
}); });
openmct.legacyRegistry.enable('platform/import-export');
}; };
}; };
}); });

View File

@@ -19,7 +19,8 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
define(['zepto', '../../../../src/api/objects/object-utils.js'], function ($, objectUtils) {
define(['zepto'], function ($) {
/** /**
* The ImportAsJSONAction is available from context menus and allows a user * The ImportAsJSONAction is available from context menus and allows a user
@@ -60,39 +61,15 @@ define(['zepto', '../../../../src/api/objects/object-utils.js'], function ($, ob
ImportAsJSONAction.prototype.importObjectTree = function (objTree) { ImportAsJSONAction.prototype.importObjectTree = function (objTree) {
var parent = this.context.domainObject; var parent = this.context.domainObject;
var namespace = parent.useCapability('adapter').identifier.namespace; var tree = this.generateNewIdentifiers(objTree);
var tree = this.generateNewIdentifiers(objTree, namespace);
var rootId = tree.rootId; var rootId = tree.rootId;
var rootObj = this.instantiate(tree.openmct[rootId], rootId);
var rootModel = tree.openmct[rootId]; // Instantiate all objects in tree with their newly genereated ids,
delete rootModel.persisted;
var rootObj = this.instantiate(rootModel, rootId);
var newStyleParent = parent.useCapability('adapter');
var newStyleRootObj = rootObj.useCapability('adapter');
if (this.openmct.composition.checkPolicy(newStyleParent, newStyleRootObj)) {
// Instantiate all objects in tree with their newly generated ids,
// adding each to its rightful parent's composition // adding each to its rightful parent's composition
rootObj.getCapability("location").setPrimaryLocation(parent.getId()); rootObj.getCapability("location").setPrimaryLocation(parent.getId());
this.deepInstantiate(rootObj, tree.openmct, []); this.deepInstantiate(rootObj, tree.openmct, []);
parent.getCapability("composition").add(rootObj); parent.getCapability("composition").add(rootObj);
} else {
var dialog = this.openmct.overlays.dialog({
iconClass: 'alert',
message: "We're sorry, but you cannot import that object type into this object.",
buttons: [
{
label: "Ok",
emphasis: true,
callback: function () {
dialog.dismiss();
}
}
]
});
}
}; };
ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) { ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) {
@@ -103,35 +80,25 @@ define(['zepto', '../../../../src/api/objects/object-utils.js'], function ($, ob
var newObj; var newObj;
seen.push(parent.getId()); seen.push(parent.getId());
parentModel.composition.forEach(function (childId, index) {
parentModel.composition.forEach(function (childId) { if (!tree[childId] || seen.includes(childId)) {
let keystring = this.openmct.objects.makeKeyString(childId);
if (!tree[keystring] || seen.includes(keystring)) {
return; return;
} }
let newModel = tree[keystring];
delete newModel.persisted;
newObj = this.instantiate(newModel, keystring); newObj = this.instantiate(tree[childId], childId);
parent.getCapability("composition").add(newObj);
newObj.getCapability("location") newObj.getCapability("location")
.setPrimaryLocation(tree[keystring].location); .setPrimaryLocation(tree[childId].location);
this.deepInstantiate(newObj, tree, seen); this.deepInstantiate(newObj, tree, seen);
}, this); }, this);
} }
}; };
ImportAsJSONAction.prototype.generateNewIdentifiers = function (tree, namespace) { ImportAsJSONAction.prototype.generateNewIdentifiers = function (tree) {
// For each domain object in the file, generate new ID, replace in tree // For each domain object in the file, generate new ID, replace in tree
Object.keys(tree.openmct).forEach(function (domainObjectId) { Object.keys(tree.openmct).forEach(function (domainObjectId) {
let newId = { var newId = this.identifierService.generate();
namespace: namespace, tree = this.rewriteId(domainObjectId, newId, tree);
key: this.identifierService.generate()
};
let oldId = objectUtils.parseKeyString(domainObjectId);
tree = this.rewriteId(oldId, newId, tree);
}, this); }, this);
return tree; return tree;
}; };
@@ -142,21 +109,9 @@ define(['zepto', '../../../../src/api/objects/object-utils.js'], function ($, ob
* *
* @private * @private
*/ */
ImportAsJSONAction.prototype.rewriteId = function (oldId, newId, tree) { ImportAsJSONAction.prototype.rewriteId = function (oldID, newID, tree) {
let newIdKeyString = this.openmct.objects.makeKeyString(newId); tree = JSON.stringify(tree).replace(new RegExp(oldID, 'g'), newID);
let oldIdKeyString = this.openmct.objects.makeKeyString(oldId); return JSON.parse(tree);
tree = JSON.stringify(tree).replace(new RegExp(oldIdKeyString, 'g'), newIdKeyString);
return JSON.parse(tree, (key, value) => {
if (Object.prototype.hasOwnProperty.call(value, 'key') &&
Object.prototype.hasOwnProperty.call(value, 'namespace') &&
value.key === oldId.key &&
value.namespace === oldId.namespace) {
return newId
} else {
return value;
}
});
}; };
ImportAsJSONAction.prototype.getFormModel = function () { ImportAsJSONAction.prototype.getFormModel = function () {

View File

@@ -29,7 +29,7 @@ define(
], ],
function (ExportAsJSONAction, domainObjectFactory, MCT, AdapterCapability) { function (ExportAsJSONAction, domainObjectFactory, MCT, AdapterCapability) {
xdescribe("The export JSON action", function () { describe("The export JSON action", function () {
var context, var context,
action, action,

View File

@@ -27,7 +27,7 @@ define(
], ],
function (ImportAsJSONAction, domainObjectFactory) { function (ImportAsJSONAction, domainObjectFactory) {
xdescribe("The import JSON action", function () { describe("The import JSON action", function () {
var context = {}; var context = {};
var action, var action,

View File

@@ -100,7 +100,7 @@ define(
} }
CouchIndicator.prototype.getCssClass = function () { CouchIndicator.prototype.getCssClass = function () {
return "c-indicator--clickable icon-suitcase " + this.state.statusClass; return "icon-database " + this.state.statusClass;
}; };
CouchIndicator.prototype.getGlyphClass = function () { CouchIndicator.prototype.getGlyphClass = function () {

View File

@@ -24,7 +24,7 @@ define(
["../src/CouchIndicator"], ["../src/CouchIndicator"],
function (CouchIndicator) { function (CouchIndicator) {
xdescribe("The CouchDB status indicator", function () { describe("The CouchDB status indicator", function () {
var mockHttp, var mockHttp,
mockInterval, mockInterval,
testPath, testPath,

View File

@@ -84,7 +84,7 @@ define(
} }
ElasticIndicator.prototype.getCssClass = function () { ElasticIndicator.prototype.getCssClass = function () {
return "c-indicator--clickable icon-suitcase"; return "icon-database";
}; };
ElasticIndicator.prototype.getGlyphClass = function () { ElasticIndicator.prototype.getGlyphClass = function () {
return this.state.glyphClass; return this.state.glyphClass;

View File

@@ -24,7 +24,7 @@ define(
["../src/ElasticIndicator"], ["../src/ElasticIndicator"],
function (ElasticIndicator) { function (ElasticIndicator) {
xdescribe("The ElasticSearch status indicator", function () { describe("The ElasticSearch status indicator", function () {
var mockHttp, var mockHttp,
mockInterval, mockInterval,
testPath, testPath,
@@ -59,7 +59,7 @@ define(
}); });
it("has a database icon", function () { it("has a database icon", function () {
expect(indicator.getCssClass()).toEqual("icon-suitcase"); expect(indicator.getCssClass()).toEqual("icon-database");
}); });
it("consults the database at the configured path", function () { it("consults the database at the configured path", function () {

View File

@@ -41,7 +41,7 @@ define(
} }
LocalStorageIndicator.prototype.getCssClass = function () { LocalStorageIndicator.prototype.getCssClass = function () {
return "c-indicator--clickable icon-suitcase s-status-caution"; return "icon-database s-status-caution";
}; };
LocalStorageIndicator.prototype.getGlyphClass = function () { LocalStorageIndicator.prototype.getGlyphClass = function () {
return 'caution'; return 'caution';

View File

@@ -24,7 +24,7 @@ define(
["../src/LocalStorageIndicator"], ["../src/LocalStorageIndicator"],
function (LocalStorageIndicator) { function (LocalStorageIndicator) {
xdescribe("The local storage status indicator", function () { describe("The local storage status indicator", function () {
var indicator; var indicator;
beforeEach(function () { beforeEach(function () {
@@ -38,7 +38,7 @@ define(
}); });
it("has a database icon", function () { it("has a database icon", function () {
expect(indicator.getCssClass()).toEqual("icon-suitcase s-status-caution"); expect(indicator.getCssClass()).toEqual("icon-database s-status-caution");
}); });
it("has a 'caution' class to draw attention", function () { it("has a 'caution' class to draw attention", function () {

View File

@@ -37,17 +37,75 @@ define(
} }
/** /**
* Discard failures * Handle persistence failures by providing the user with a
* dialog summarizing these failures, and giving the option
* to overwrite/cancel as appropriate.
* @param {Array} failures persistence failures, as prepared * @param {Array} failures persistence failures, as prepared
* by PersistenceQueueHandler * by PersistenceQueueHandler
* @memberof platform/persistence/queue.PersistenceFailureHandler# * @memberof platform/persistence/queue.PersistenceFailureHandler#
*/ */
PersistenceFailureHandler.prototype.handle = function handleFailures(failures) { PersistenceFailureHandler.prototype.handle = function handleFailures(failures) {
// Prepare dialog for display
var dialogModel = new PersistenceFailureDialog(failures), var dialogModel = new PersistenceFailureDialog(failures),
revisionErrors = dialogModel.model.revised, revisionErrors = dialogModel.model.revised,
$q = this.$q; $q = this.$q;
// Refresh revision information for the domain object associated
// with this persistence failure
function refresh(failure) {
// Refresh the domain object to the latest from persistence
return failure.persistence.refresh();
}
// Issue a new persist call for the domain object associated with
// this failure.
function persist(failure) {
// Note that we reissue the persist request here, but don't
// return it, to avoid a circular wait. We trust that the
// PersistenceQueue will behave correctly on the next round
// of flushing.
failure.requeue();
}
// Retry persistence (overwrite) for this set of failed attempts
function retry(failuresToRetry) {
var models = {};
// Cache a copy of the model
function cacheModel(failure) {
// Clone...
models[failure.id] = JSON.parse(JSON.stringify(
failure.domainObject.getModel()
));
}
// Mutate a domain object to restore its model
function remutate(failure) {
var model = models[failure.id];
return failure.domainObject.useCapability(
"mutation",
function () {
return model;
},
model.modified
);
}
// Cache the object models we might want to save
failuresToRetry.forEach(cacheModel);
// Strategy here:
// * Cache all of the models we might want to save (above)
// * Refresh all domain objects (so they are latest versions)
// * Re-insert the cached domain object models
// * Invoke persistence again
return $q.all(failuresToRetry.map(refresh)).then(function () {
return $q.all(failuresToRetry.map(remutate));
}).then(function () {
return $q.all(failuresToRetry.map(persist));
});
}
// Discard changes for a failed refresh // Discard changes for a failed refresh
function discard(failure) { function discard(failure) {
var persistence = var persistence =
@@ -60,7 +118,19 @@ define(
return $q.all(failuresToDiscard.map(discard)); return $q.all(failuresToDiscard.map(discard));
} }
// Handle user input (did they choose to overwrite?)
function handleChoice(key) {
// If so, try again
if (key === PersistenceFailureConstants.OVERWRITE_KEY) {
return retry(revisionErrors);
} else {
return discardAll(revisionErrors); return discardAll(revisionErrors);
}
}
// Prompt for user input, the overwrite if they said so.
return this.dialogService.getUserChoice(dialogModel)
.then(handleChoice, handleChoice);
}; };
return PersistenceFailureHandler; return PersistenceFailureHandler;

View File

@@ -32,6 +32,14 @@ define(
mockPromise, mockPromise,
handler; handler;
function asPromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return asPromise(callback(value));
}
};
}
function makeMockFailure(id, index) { function makeMockFailure(id, index) {
var mockFailure = jasmine.createSpyObj( var mockFailure = jasmine.createSpyObj(
'failure-' + id, 'failure-' + id,
@@ -66,14 +74,43 @@ define(
handler = new PersistenceFailureHandler(mockQ, mockDialogService); handler = new PersistenceFailureHandler(mockQ, mockDialogService);
}); });
it("discards on handle", function () { it("shows a dialog to handle failures", function () {
handler.handle(mockFailures); handler.handle(mockFailures);
expect(mockDialogService.getUserChoice).toHaveBeenCalled();
});
it("overwrites on request", function () {
mockQ.all.and.returnValue(asPromise([]));
handler.handle(mockFailures);
// User chooses overwrite
mockPromise.then.calls.mostRecent().args[0](Constants.OVERWRITE_KEY);
// Should refresh, remutate, and requeue all objects
mockFailures.forEach(function (mockFailure, i) {
expect(mockFailure.persistence.refresh).toHaveBeenCalled();
expect(mockFailure.requeue).toHaveBeenCalled();
expect(mockFailure.domainObject.useCapability).toHaveBeenCalledWith(
'mutation',
jasmine.any(Function),
i // timestamp
);
expect(mockFailure.domainObject.useCapability.calls.mostRecent().args[1]())
.toEqual({ id: mockFailure.id, modified: i });
});
});
it("discards on request", function () {
mockQ.all.and.returnValue(asPromise([]));
handler.handle(mockFailures);
// User chooses overwrite
mockPromise.then.calls.mostRecent().args[0](false);
// Should refresh, but not remutate, and requeue all objects
mockFailures.forEach(function (mockFailure) { mockFailures.forEach(function (mockFailure) {
expect(mockFailure.persistence.refresh).toHaveBeenCalled(); expect(mockFailure.persistence.refresh).toHaveBeenCalled();
expect(mockFailure.requeue).not.toHaveBeenCalled(); expect(mockFailure.requeue).not.toHaveBeenCalled();
expect(mockFailure.domainObject.useCapability).not.toHaveBeenCalled(); expect(mockFailure.domainObject.useCapability).not.toHaveBeenCalled();
}); });
}); });
}); });
} }
); );

View File

@@ -29,7 +29,6 @@ define([
"./res/templates/search.html", "./res/templates/search.html",
"./res/templates/search-menu.html", "./res/templates/search-menu.html",
"raw-loader!./src/services/GenericSearchWorker.js", "raw-loader!./src/services/GenericSearchWorker.js",
"raw-loader!./src/services/BareBonesSearchWorker.js",
'legacyRegistry' 'legacyRegistry'
], function ( ], function (
SearchController, SearchController,
@@ -40,7 +39,6 @@ define([
searchTemplate, searchTemplate,
searchMenuTemplate, searchMenuTemplate,
searchWorkerText, searchWorkerText,
BareBonesSearchWorkerText,
legacyRegistry legacyRegistry
) { ) {
@@ -55,11 +53,6 @@ define([
"ROOT" "ROOT"
], ],
"priority": "fallback" "priority": "fallback"
},
{
"key": "USE_LEGACY_INDEXER",
"value": false,
"priority": 2
} }
], ],
"controllers": [ "controllers": [
@@ -108,7 +101,6 @@ define([
"workerService", "workerService",
"topic", "topic",
"GENERIC_SEARCH_ROOTS", "GENERIC_SEARCH_ROOTS",
"USE_LEGACY_INDEXER",
"openmct" "openmct"
] ]
}, },
@@ -123,10 +115,6 @@ define([
} }
], ],
"workers": [ "workers": [
{
"key": "bareBonesSearchWorker",
"scriptText": BareBonesSearchWorkerText
},
{ {
"key": "genericSearchWorker", "key": "genericSearchWorker",
"scriptText": searchWorkerText "scriptText": searchWorkerText

View File

@@ -45,7 +45,7 @@
</mct-include> </mct-include>
</div> </div>
<a class="c-button c-search__btn-cancel" <a class="s-button c-search__btn-cancel"
ng-show="!(ngModel.input === '' || ngModel.input === undefined)" ng-show="!(ngModel.input === '' || ngModel.input === undefined)"
ng-click="ngModel.input = ''; ngModel.checkAll = true; menuController.checkAll(); controller.search()"> ng-click="ngModel.input = ''; ngModel.checkAll = true; menuController.checkAll(); controller.search()">
Cancel</a> Cancel</a>

View File

@@ -1,80 +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.
*****************************************************************************/
/*global self*/
/**
* Module defining BareBonesSearchWorker. Created by deeptailor on 10/03/2019.
*/
(function () {
// An array of objects composed of domain object IDs and names
// {id: domainObject's ID, name: domainObject's name}
var indexedItems = [];
function indexItem(id, model) {
indexedItems.push({
id: id,
name: model.name.toLowerCase()
});
}
/**
* Gets search results from the indexedItems based on provided search
* input. Returns matching results from indexedItems
*
* @param data An object which contains:
* * input: The original string which we are searching with
* * maxResults: The maximum number of search results desired
* * queryId: an id identifying this query, will be returned.
*/
function search(data) {
// This results dictionary will have domain object ID keys which
// point to the value the domain object's score.
var results,
input = data.input.trim().toLowerCase(),
message = {
request: 'search',
results: {},
total: 0,
queryId: data.queryId
};
results = indexedItems.filter((indexedItem) => {
return indexedItem.name.includes(input);
});
message.total = results.length;
message.results = results
.slice(0, data.maxResults);
return message;
}
self.onmessage = function (event) {
if (event.data.request === 'index') {
indexItem(event.data.id, event.data.model);
} else if (event.data.request === 'search') {
self.postMessage(search(event.data));
}
};
}());

View File

@@ -44,7 +44,7 @@ define([
* @param {TopicService} topic the topic service. * @param {TopicService} topic the topic service.
* @param {Array} ROOTS An array of object Ids to begin indexing. * @param {Array} ROOTS An array of object Ids to begin indexing.
*/ */
function GenericSearchProvider($q, $log, modelService, workerService, topic, ROOTS, USE_LEGACY_INDEXER, openmct) { function GenericSearchProvider($q, $log, modelService, workerService, topic, ROOTS, openmct) {
var provider = this; var provider = this;
this.$q = $q; this.$q = $q;
this.$log = $log; this.$log = $log;
@@ -58,8 +58,6 @@ define([
this.pendingQueries = {}; this.pendingQueries = {};
this.USE_LEGACY_INDEXER = USE_LEGACY_INDEXER;
this.worker = this.startWorker(workerService); this.worker = this.startWorker(workerService);
this.indexOnMutation(topic); this.indexOnMutation(topic);
@@ -103,14 +101,8 @@ define([
* @returns worker the created search worker. * @returns worker the created search worker.
*/ */
GenericSearchProvider.prototype.startWorker = function (workerService) { GenericSearchProvider.prototype.startWorker = function (workerService) {
var provider = this, var worker = workerService.run('genericSearchWorker'),
worker; provider = this;
if (this.USE_LEGACY_INDEXER) {
worker = workerService.run('genericSearchWorker');
} else {
worker = workerService.run('bareBonesSearchWorker');
}
worker.addEventListener('message', function (messageEvent) { worker.addEventListener('message', function (messageEvent) {
provider.onWorkerMessage(messageEvent); provider.onWorkerMessage(messageEvent);
@@ -250,11 +242,7 @@ define([
return; return;
} }
var pendingQuery, var pendingQuery = this.pendingQueries[event.data.queryId],
modelResults;
if (this.USE_LEGACY_INDEXER) {
pendingQuery = this.pendingQueries[event.data.queryId];
modelResults = { modelResults = {
total: event.data.total total: event.data.total
}; };
@@ -266,18 +254,6 @@ define([
score: hit.matchCount score: hit.matchCount
}; };
}); });
} else {
pendingQuery = this.pendingQueries[event.data.queryId];
modelResults = {
total: event.data.total
};
modelResults.hits = event.data.results.map(function (hit) {
return {
id: hit.id
};
});
}
pendingQuery.resolve(modelResults); pendingQuery.resolve(modelResults);
delete this.pendingQueries[event.data.queryId]; delete this.pendingQueries[event.data.queryId];

View File

@@ -29,7 +29,7 @@ define([
GenericSearchProvider GenericSearchProvider
) { ) {
xdescribe('GenericSearchProvider', function () { describe('GenericSearchProvider', function () {
var $q, var $q,
$log, $log,
modelService, modelService,

View File

@@ -38,15 +38,12 @@ define([
'./ui/router/ApplicationRouter', './ui/router/ApplicationRouter',
'./ui/router/Browse', './ui/router/Browse',
'../platform/framework/src/Main', '../platform/framework/src/Main',
'./styles/core.scss', './styles-new/core.scss',
'./styles/notebook.scss', './styles-new/notebook.scss',
'./ui/layout/Layout.vue', './ui/layout/Layout.vue',
'../platform/core/src/objects/DomainObjectImpl', '../platform/core/src/objects/DomainObjectImpl',
'../platform/core/src/capabilities/ContextualDomainObject', '../platform/core/src/capabilities/ContextualDomainObject',
'./ui/preview/plugin', './ui/preview/plugin',
'./api/Branding',
'./plugins/licenses/plugin',
'./plugins/remove/plugin',
'vue' 'vue'
], function ( ], function (
EventEmitter, EventEmitter,
@@ -72,9 +69,6 @@ define([
DomainObjectImpl, DomainObjectImpl,
ContextualDomainObject, ContextualDomainObject,
PreviewPlugin, PreviewPlugin,
BrandingAPI,
LicensesPlugin,
RemoveActionPlugin,
Vue Vue
) { ) {
/** /**
@@ -95,16 +89,6 @@ define([
*/ */
function MCT() { function MCT() {
EventEmitter.call(this); EventEmitter.call(this);
/* eslint-disable no-undef */
this.buildInfo = {
version: __OPENMCT_VERSION__,
buildDate: __OPENMCT_BUILD_DATE__,
revision: __OPENMCT_REVISION__,
branch: __OPENMCT_BUILD_BRANCH__
};
/* eslint-enable no-undef */
this.legacyBundle = { extensions: { this.legacyBundle = { extensions: {
services: [ services: [
{ {
@@ -244,25 +228,16 @@ define([
this.contextMenu = new api.ContextMenuRegistry(); this.contextMenu = new api.ContextMenuRegistry();
this.router = new ApplicationRouter();
this.branding = BrandingAPI.default;
this.legacyRegistry = defaultRegistry; this.legacyRegistry = defaultRegistry;
// Plugin's that are installed by default
this.install(this.plugins.Plot()); this.install(this.plugins.Plot());
this.install(this.plugins.TelemetryTable()); this.install(this.plugins.TelemetryTable());
this.install(this.plugins.DisplayLayout());
this.install(PreviewPlugin.default()); this.install(PreviewPlugin.default());
this.install(LegacyIndicatorsPlugin());
this.install(LicensesPlugin.default()); if (typeof BUILD_CONSTANTS !== 'undefined') {
this.install(RemoveActionPlugin.default()); this.install(buildInfoPlugin(BUILD_CONSTANTS));
this.install(this.plugins.ImportExport()); }
this.install(this.plugins.FolderView());
this.install(this.plugins.Tabs());
this.install(this.plugins.FlexibleLayout());
this.install(this.plugins.GoToOriginalAction());
} }
MCT.prototype = Object.create(EventEmitter.prototype); MCT.prototype = Object.create(EventEmitter.prototype);
@@ -333,18 +308,10 @@ define([
* MCT; if undefined, MCT will be run in the body of the document * MCT; if undefined, MCT will be run in the body of the document
*/ */
MCT.prototype.start = function (domElement) { MCT.prototype.start = function (domElement) {
if (!this.plugins.DisplayLayout._installed) {
this.install(this.plugins.DisplayLayout({
showAsView: ['summary-widget']
}));
}
if (!domElement) { if (!domElement) {
domElement = document.body; domElement = document.body;
} }
this.element = domElement;
this.legacyExtension('runs', { this.legacyExtension('runs', {
depends: ['navigationService'], depends: ['navigationService'],
implementation: function (navigationService) { implementation: function (navigationService) {
@@ -364,8 +331,12 @@ define([
legacyRegistry.register('adapter', this.legacyBundle); legacyRegistry.register('adapter', this.legacyBundle);
legacyRegistry.enable('adapter'); legacyRegistry.enable('adapter');
this.install(LegacyIndicatorsPlugin());
this.router = new ApplicationRouter();
this.router.route(/^\/$/, () => { this.router.route(/^\/$/, () => {
this.router.setPath('/browse/'); this.router.setPath('/browse/mine');
}); });
/** /**
@@ -374,8 +345,7 @@ define([
* @event start * @event start
* @memberof module:openmct.MCT~ * @memberof module:openmct.MCT~
*/ */
const startPromise = new Main() var startPromise = new Main().run(this.legacyRegistry)
startPromise.run(this)
.then(function (angular) { .then(function (angular) {
this.$angular = angular; this.$angular = angular;
// OpenMCT Object provider doesn't operate properly unless // OpenMCT Object provider doesn't operate properly unless

View File

@@ -25,7 +25,7 @@ define([
'./plugins/plugins', './plugins/plugins',
'legacyRegistry' 'legacyRegistry'
], function (MCT, plugins, legacyRegistry) { ], function (MCT, plugins, legacyRegistry) {
xdescribe("MCT", function () { describe("MCT", function () {
var openmct; var openmct;
var mockPlugin; var mockPlugin;
var mockPlugin2; var mockPlugin2;

Some files were not shown because too many files have changed in this diff Show More