Compare commits
2 Commits
fix-lint-e
...
table-perf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d026a67ac0 | ||
|
|
78018628ce |
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
18
index.html
18
index.html
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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": [
|
||||||
|
|||||||
215
platform/commonUI/browse/src/BrowseController.js
Normal file
215
platform/commonUI/browse/src/BrowseController.js
Normal 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;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
72
platform/commonUI/browse/src/BrowseObjectController.js
Normal file
72
platform/commonUI/browse/src/BrowseObjectController.js
Normal 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;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
78
platform/commonUI/browse/src/InspectorPaneController.js
Normal file
78
platform/commonUI/browse/src/InspectorPaneController.js
Normal 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;
|
||||||
|
}
|
||||||
|
);
|
||||||
59
platform/commonUI/browse/src/MenuArrowController.js
Normal file
59
platform/commonUI/browse/src/MenuArrowController.js
Normal 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;
|
||||||
|
}
|
||||||
|
);
|
||||||
92
platform/commonUI/browse/src/ObjectHeaderController.js
Normal file
92
platform/commonUI/browse/src/ObjectHeaderController.js
Normal 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;
|
||||||
|
}
|
||||||
|
);
|
||||||
88
platform/commonUI/browse/src/PaneController.js
Normal file
88
platform/commonUI/browse/src/PaneController.js
Normal 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;
|
||||||
|
}
|
||||||
|
);
|
||||||
51
platform/commonUI/browse/src/windowing/WindowTitler.js
Normal file
51
platform/commonUI/browse/src/windowing/WindowTitler.js
Normal 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;
|
||||||
|
}
|
||||||
|
);
|
||||||
266
platform/commonUI/browse/test/BrowseControllerSpec.js
Normal file
266
platform/commonUI/browse/test/BrowseControllerSpec.js
Normal 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'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
93
platform/commonUI/browse/test/BrowseObjectControllerSpec.js
Normal file
93
platform/commonUI/browse/test/BrowseObjectControllerSpec.js
Normal 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]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
103
platform/commonUI/browse/test/InspectorPaneControllerSpec.js
Normal file
103
platform/commonUI/browse/test/InspectorPaneControllerSpec.js
Normal 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);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
79
platform/commonUI/browse/test/MenuArrowControllerSpec.js
Normal file
79
platform/commonUI/browse/test/MenuArrowControllerSpec.js
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
137
platform/commonUI/browse/test/ObjectHeaderControllerSpec.js
Normal file
137
platform/commonUI/browse/test/ObjectHeaderControllerSpec.js
Normal 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);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
106
platform/commonUI/browse/test/PaneControllerSpec.js
Normal file
106
platform/commonUI/browse/test/PaneControllerSpec.js
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
78
platform/commonUI/browse/test/windowing/WindowTitlerSpec.js
Normal file
78
platform/commonUI/browse/test/windowing/WindowTitlerSpec.js
Normal 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");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 () {
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
140
platform/commonUI/edit/src/actions/RemoveAction.js
Normal file
140
platform/commonUI/edit/src/actions/RemoveAction.js
Normal 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;
|
||||||
|
});
|
||||||
72
platform/commonUI/edit/src/actions/RemoveDialog.js
Normal file
72
platform/commonUI/edit/src/actions/RemoveDialog.js
Normal 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;
|
||||||
|
});
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
255
platform/commonUI/edit/test/actions/RemoveActionSpec.js
Normal file
255
platform/commonUI/edit/test/actions/RemoveActionSpec.js
Normal 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();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 () {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
<span class='c-disclosure-triangle c-tree__item__view-control'></span>
|
<span class='ui-symbol view-control flex-elem'>
|
||||||
|
</span>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
60
platform/entanglement/src/actions/GoToOriginalAction.js
Normal file
60
platform/entanglement/src/actions/GoToOriginalAction.js
Normal 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;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
93
platform/entanglement/test/actions/GoToOriginalActionSpec.js
Normal file
93
platform/entanglement/test/actions/GoToOriginalActionSpec.js
Normal 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');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -42,7 +42,7 @@ define(
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
xdescribe("CopyService", function () {
|
describe("CopyService", function () {
|
||||||
var policyService;
|
var policyService;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ define(
|
|||||||
ControlledPromise
|
ControlledPromise
|
||||||
) {
|
) {
|
||||||
|
|
||||||
xdescribe("MoveService", function () {
|
describe("MoveService", function () {
|
||||||
|
|
||||||
var moveService,
|
var moveService,
|
||||||
policyService,
|
policyService,
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 () {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ define([
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
openmct.legacyRegistry.enable('platform/import-export');
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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 () {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 () {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 () {
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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 () {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}());
|
|
||||||
@@ -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];
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ define([
|
|||||||
GenericSearchProvider
|
GenericSearchProvider
|
||||||
) {
|
) {
|
||||||
|
|
||||||
xdescribe('GenericSearchProvider', function () {
|
describe('GenericSearchProvider', function () {
|
||||||
var $q,
|
var $q,
|
||||||
$log,
|
$log,
|
||||||
modelService,
|
modelService,
|
||||||
|
|||||||
58
src/MCT.js
58
src/MCT.js
@@ -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
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user