Compare commits
	
		
			104 Commits
		
	
	
		
			table-perf
			...
			vista-4.2.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					c054914a9c | ||
| 
						 | 
					69b6f8afa9 | ||
| 
						 | 
					45164a2f68 | ||
| 
						 | 
					b189a887e6 | ||
| 
						 | 
					71abfbc336 | ||
| 
						 | 
					ee690545fb | ||
| 
						 | 
					fcf3c76aa1 | ||
| 
						 | 
					5dbd77d10c | ||
| 
						 | 
					43515ca84e | ||
| 
						 | 
					54fe881e71 | ||
| 
						 | 
					7c32700b69 | ||
| 
						 | 
					e98d0cc7c5 | ||
| 
						 | 
					2200503e48 | ||
| 
						 | 
					8f0081acc8 | ||
| 
						 | 
					003c3e9fbe | ||
| 
						 | 
					02ef58ced1 | ||
| 
						 | 
					e89881c266 | ||
| 
						 | 
					fa66289d5c | ||
| 
						 | 
					4f3a3befe0 | ||
| 
						 | 
					a0864a8702 | ||
| 
						 | 
					a34ad4e58c | ||
| 
						 | 
					7e50010463 | ||
| 
						 | 
					974be0ae2c | ||
| 
						 | 
					3dc6dac12d | ||
| 
						 | 
					aafe524454 | ||
| 
						 | 
					e84ade1752 | ||
| 
						 | 
					3b094e43e3 | ||
| 
						 | 
					e6a7b4ed6c | ||
| 
						 | 
					97230bb21f | ||
| 
						 | 
					768d99d928 | ||
| 
						 | 
					c760190a29 | ||
| 
						 | 
					7fe4a77c43 | ||
| 
						 | 
					8578d78c51 | ||
| 
						 | 
					362e565a09 | ||
| 
						 | 
					9517c1f2cd | ||
| 
						 | 
					262d35804d | ||
| 
						 | 
					e0587bf0e7 | ||
| 
						 | 
					f1494fd285 | ||
| 
						 | 
					884aec8ea0 | ||
| 
						 | 
					216f447578 | ||
| 
						 | 
					c38d810658 | ||
| 
						 | 
					f5c48b7bf6 | ||
| 
						 | 
					d0e08f1d9a | ||
| 
						 | 
					72ea7b80fd | ||
| 
						 | 
					35d0c02bc5 | ||
| 
						 | 
					abd7506b45 | ||
| 
						 | 
					526b4aa07e | ||
| 
						 | 
					b5e23963d4 | ||
| 
						 | 
					2c11eb90d4 | ||
| 
						 | 
					90e9c79e19 | ||
| 
						 | 
					1b83631e43 | ||
| 
						 | 
					547d4e82db | ||
| 
						 | 
					3377ad5e0d | ||
| 
						 | 
					1c0df60f05 | ||
| 
						 | 
					138067dca9 | ||
| 
						 | 
					844280eaa5 | ||
| 
						 | 
					d2e2d55caf | ||
| 
						 | 
					f01d4071a1 | ||
| 
						 | 
					06524ce967 | ||
| 
						 | 
					1ec529f360 | ||
| 
						 | 
					cf6458c69d | ||
| 
						 | 
					3316500774 | ||
| 
						 | 
					0f780587c0 | ||
| 
						 | 
					ea69508e22 | ||
| 
						 | 
					4274d8cc0b | ||
| 
						 | 
					1a2048332f | ||
| 
						 | 
					38a875395f | ||
| 
						 | 
					f601ab03e7 | ||
| 
						 | 
					ee1d92d4a9 | ||
| 
						 | 
					548286bacd | ||
| 
						 | 
					9c9006d415 | ||
| 
						 | 
					3219a64d09 | ||
| 
						 | 
					570aa2c02a | ||
| 
						 | 
					c577d2e231 | ||
| 
						 | 
					6bf4b3aba8 | ||
| 
						 | 
					b659f205f7 | ||
| 
						 | 
					40d54df567 | ||
| 
						 | 
					b7fa5c7ba8 | ||
| 
						 | 
					3b0605d17b | ||
| 
						 | 
					d93e7bfd1a | ||
| 
						 | 
					104cd0ed29 | ||
| 
						 | 
					7fb3d86d06 | ||
| 
						 | 
					dbb42e9bb6 | ||
| 
						 | 
					d1baa1f98b | ||
| 
						 | 
					5ab68c0586 | ||
| 
						 | 
					3cf78f509d | ||
| 
						 | 
					c6053e234a | ||
| 
						 | 
					964c326535 | ||
| 
						 | 
					baf410a364 | ||
| 
						 | 
					517a40a32b | ||
| 
						 | 
					8b275b206b | ||
| 
						 | 
					a40a31aa4c | ||
| 
						 | 
					6c0c1df010 | ||
| 
						 | 
					c552afff17 | ||
| 
						 | 
					0837129ad5 | ||
| 
						 | 
					6f3e2a8fbb | ||
| 
						 | 
					4189a05758 | ||
| 
						 | 
					97ccaa58c7 | ||
| 
						 | 
					08ef932926 | ||
| 
						 | 
					1d2ed0398c | ||
| 
						 | 
					5a00e0c549 | ||
| 
						 | 
					ebcf47733f | ||
| 
						 | 
					381d7e7615 | ||
| 
						 | 
					8246b47668 | 
@@ -99,10 +99,10 @@ define([
 | 
			
		||||
 | 
			
		||||
    GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
 | 
			
		||||
        return _.extend(
 | 
			
		||||
                {},
 | 
			
		||||
                domainObject.telemetry,
 | 
			
		||||
                METADATA_BY_TYPE[domainObject.type]
 | 
			
		||||
            );
 | 
			
		||||
            {},
 | 
			
		||||
            domainObject.telemetry,
 | 
			
		||||
            METADATA_BY_TYPE[domainObject.type]
 | 
			
		||||
        );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return GeneratorMetadataProvider;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<span class="h-indicator" ng-controller="DialogLaunchController">
 | 
			
		||||
    <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
    <div class="ls-indicator icon-box-with-arrow s-status-available"><span class="label">
 | 
			
		||||
        <a ng-click="launchProgress(true)">Known</a>
 | 
			
		||||
        <a ng-click="launchProgress(false)">Unknown</a>
 | 
			
		||||
        <a ng-click="launchError()">Error</a>
 | 
			
		||||
        <a ng-click="launchInfo()">Info</a>
 | 
			
		||||
    <div class="c-indicator c-indicator--clickable icon-box-with-arrow s-status-available"><span class="label c-indicator__label">
 | 
			
		||||
        <button ng-click="launchProgress(true)">Known</button>
 | 
			
		||||
        <button ng-click="launchProgress(false)">Unknown</button>
 | 
			
		||||
        <button ng-click="launchError()">Error</button>
 | 
			
		||||
        <button ng-click="launchInfo()">Info</button>
 | 
			
		||||
    </span></div>
 | 
			
		||||
</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<span class="h-indicator" ng-controller="NotificationLaunchController">
 | 
			
		||||
    <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
    <div class="ls-indicator icon-bell s-status-available"><span class="label">
 | 
			
		||||
        <a ng-click="newInfo()">Success</a>
 | 
			
		||||
        <a ng-click="newError()">Error</a>
 | 
			
		||||
        <a ng-click="newAlert()">Alert</a>
 | 
			
		||||
        <a ng-click="newProgress()">Progress</a>
 | 
			
		||||
    <div class="c-indicator c-indicator--clickable icon-bell s-status-available"><span class="label c-indicator__label">
 | 
			
		||||
        <button ng-click="newInfo()">Success</button>
 | 
			
		||||
        <button ng-click="newError()">Error</button>
 | 
			
		||||
        <button ng-click="newAlert()">Alert</button>
 | 
			
		||||
        <button ng-click="newProgress()">Progress</button>
 | 
			
		||||
    </span></div>
 | 
			
		||||
</span>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								index.html
									
									
									
									
									
								
							
							
						
						@@ -27,11 +27,9 @@
 | 
			
		||||
        <meta name="apple-mobile-web-app-capable" content="yes">
 | 
			
		||||
        <title></title>
 | 
			
		||||
        <script src="dist/openmct.js"></script>
 | 
			
		||||
        <link rel="stylesheet" href="dist/styles/openmct.css">
 | 
			
		||||
        <link rel="icon" type="image/png" href="dist/favicons/favicon-32x32.png" sizes="32x32">
 | 
			
		||||
        <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">
 | 
			
		||||
        <link rel="icon" type="image/png" href="dist/favicons/favicon-96x96.png" sizes="96x96" type="image/x-icon">
 | 
			
		||||
        <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-16x16.png" sizes="16x16" type="image/x-icon">
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
    </body>
 | 
			
		||||
@@ -50,7 +48,6 @@
 | 
			
		||||
        openmct.install(openmct.plugins.Generator());
 | 
			
		||||
        openmct.install(openmct.plugins.ExampleImagery());
 | 
			
		||||
        openmct.install(openmct.plugins.UTCTimeSystem());
 | 
			
		||||
        openmct.install(openmct.plugins.ImportExport());
 | 
			
		||||
        openmct.install(openmct.plugins.AutoflowView({
 | 
			
		||||
            type: "telemetry.panel"
 | 
			
		||||
        }));
 | 
			
		||||
@@ -80,12 +77,10 @@
 | 
			
		||||
        }));
 | 
			
		||||
        openmct.install(openmct.plugins.SummaryWidget());
 | 
			
		||||
        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.Filters(['table', 'telemetry.plot.overlay']));
 | 
			
		||||
        openmct.install(openmct.plugins.ObjectMigration());
 | 
			
		||||
        openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked']));
 | 
			
		||||
        openmct.start();
 | 
			
		||||
    </script>
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "openmct",
 | 
			
		||||
  "version": "0.14.0-SNAPSHOT",
 | 
			
		||||
  "version": "1.0.0-beta",
 | 
			
		||||
  "description": "The Open MCT core platform",
 | 
			
		||||
  "dependencies": {},
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "acorn": "6.2.0",
 | 
			
		||||
    "angular": "1.4.14",
 | 
			
		||||
    "angular-route": "1.4.14",
 | 
			
		||||
    "babel-eslint": "8.2.6",
 | 
			
		||||
@@ -55,7 +56,7 @@
 | 
			
		||||
    "node-bourbon": "^4.2.3",
 | 
			
		||||
    "node-sass": "^4.9.2",
 | 
			
		||||
    "painterro": "^0.2.65",
 | 
			
		||||
    "printj": "^1.1.0",
 | 
			
		||||
    "printj": "^1.2.1",
 | 
			
		||||
    "raw-loader": "^0.5.1",
 | 
			
		||||
    "request": "^2.69.0",
 | 
			
		||||
    "split": "^1.0.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,8 @@ define([
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$document",
 | 
			
		||||
                        "$compile",
 | 
			
		||||
                        "$rootScope"
 | 
			
		||||
                        "$rootScope",
 | 
			
		||||
                        "$timeout"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
 
 | 
			
		||||
@@ -9,17 +9,17 @@
 | 
			
		||||
                         ng-model="ngModel"
 | 
			
		||||
                         ng-show="ngModel.progressPerc !== undefined"></mct-include>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="c-overlay__button-bar">
 | 
			
		||||
            <button ng-repeat="dialogOption in ngModel.options"
 | 
			
		||||
    </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"
 | 
			
		||||
            {{dialogOption.label}}
 | 
			
		||||
        </button>
 | 
			
		||||
        <button class="c-button c-button--major"
 | 
			
		||||
                ng-if="ngModel.primaryOption"
 | 
			
		||||
                ng-click="ngModel.primaryOption.callback()">
 | 
			
		||||
                    {{ngModel.primaryOption.label}}
 | 
			
		||||
            </button>
 | 
			
		||||
        </div>
 | 
			
		||||
            {{ngModel.primaryOption.label}}
 | 
			
		||||
        </button>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -44,8 +44,9 @@ define(
 | 
			
		||||
         * @memberof platform/commonUI/dialog
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function OverlayService($document, $compile, $rootScope) {
 | 
			
		||||
        function OverlayService($document, $compile, $rootScope, $timeout) {
 | 
			
		||||
            this.$compile = $compile;
 | 
			
		||||
            this.$timeout = $timeout;
 | 
			
		||||
 | 
			
		||||
            // Don't include $document and $rootScope directly;
 | 
			
		||||
            // avoids https://docs.angularjs.org/error/ng/cpws
 | 
			
		||||
@@ -93,12 +94,14 @@ define(
 | 
			
		||||
            scope.key = key;
 | 
			
		||||
            scope.typeClass = typeClass || 't-dialog';
 | 
			
		||||
 | 
			
		||||
            // Create the overlay element and add it to the document's body
 | 
			
		||||
            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
 | 
			
		||||
            // multiple overlays with the same z-index are active.
 | 
			
		||||
            this.findBody().append(element);
 | 
			
		||||
            this.$timeout(() => {
 | 
			
		||||
                // Create the overlay element and add it to the document's body
 | 
			
		||||
                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
 | 
			
		||||
                // multiple overlays with the same z-index are active.
 | 
			
		||||
                this.findBody().append(element);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                dismiss: dismiss
 | 
			
		||||
 
 | 
			
		||||
@@ -35,16 +35,20 @@ define(
 | 
			
		||||
                mockTemplate,
 | 
			
		||||
                mockElement,
 | 
			
		||||
                mockScope,
 | 
			
		||||
                mockTimeout,
 | 
			
		||||
                overlayService;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockDocument = jasmine.createSpyObj("$document", ["find"]);
 | 
			
		||||
                mockCompile = jasmine.createSpy("$compile");
 | 
			
		||||
                mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
 | 
			
		||||
                mockBody = jasmine.createSpyObj("body", ["prepend"]);
 | 
			
		||||
                mockBody = jasmine.createSpyObj("body", ["append"]);
 | 
			
		||||
                mockTemplate = jasmine.createSpy("template");
 | 
			
		||||
                mockElement = jasmine.createSpyObj("element", ["remove"]);
 | 
			
		||||
                mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
 | 
			
		||||
                mockTimeout = function (callback) {
 | 
			
		||||
                    callback();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                mockDocument.find.and.returnValue(mockBody);
 | 
			
		||||
                mockCompile.and.returnValue(mockTemplate);
 | 
			
		||||
@@ -54,7 +58,8 @@ define(
 | 
			
		||||
                overlayService = new OverlayService(
 | 
			
		||||
                    mockDocument,
 | 
			
		||||
                    mockCompile,
 | 
			
		||||
                    mockRootScope
 | 
			
		||||
                    mockRootScope,
 | 
			
		||||
                    mockTimeout
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +72,7 @@ define(
 | 
			
		||||
 | 
			
		||||
            it("adds the templated element to the body", function () {
 | 
			
		||||
                overlayService.createOverlay("test", {});
 | 
			
		||||
                expect(mockBody.prepend).toHaveBeenCalledWith(mockElement);
 | 
			
		||||
                expect(mockBody.append).toHaveBeenCalledWith(mockElement);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("places the provided model/key in its template's scope", function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ define(
 | 
			
		||||
                    name: "Properties",
 | 
			
		||||
                    rows: this.properties.map(function (property, index) {
 | 
			
		||||
                        // Property definition is same as form row definition
 | 
			
		||||
                        var row = Object.create(property.getDefinition());
 | 
			
		||||
                        var row = JSON.parse(JSON.stringify(property.getDefinition()));
 | 
			
		||||
                        row.key = index;
 | 
			
		||||
                        return row;
 | 
			
		||||
                    }).filter(function (row) {
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,6 @@ define(
 | 
			
		||||
         * @returns boolean
 | 
			
		||||
         */
 | 
			
		||||
        EditorCapability.prototype.inEditContext = function () {
 | 
			
		||||
            console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
 | 
			
		||||
            return this.openmct.editor.isEditing();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -74,7 +73,6 @@ define(
 | 
			
		||||
         * @returns {*}
 | 
			
		||||
         */
 | 
			
		||||
        EditorCapability.prototype.isEditContextRoot = function () {
 | 
			
		||||
            console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
 | 
			
		||||
            return this.openmct.editor.isEditing();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ define(
 | 
			
		||||
                name: "Properties",
 | 
			
		||||
                rows: this.properties.map(function (property, index) {
 | 
			
		||||
                    // Property definition is same as form row definition
 | 
			
		||||
                    var row = Object.create(property.getDefinition());
 | 
			
		||||
                    var row = JSON.parse(JSON.stringify(property.getDefinition()));
 | 
			
		||||
 | 
			
		||||
                    // Use index as the key into the formValue;
 | 
			
		||||
                    // this correlates to the indexing provided by
 | 
			
		||||
 
 | 
			
		||||
@@ -77,14 +77,19 @@ define([], function () {
 | 
			
		||||
                return promiseFn().then(nextFn);
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.isScheduled(id)) {
 | 
			
		||||
            this.clearTransactionFns[id] =
 | 
			
		||||
                this.transactionService.addToTransaction(
 | 
			
		||||
                    chain(onCommit, release),
 | 
			
		||||
                    chain(onCancel, release)
 | 
			
		||||
                );
 | 
			
		||||
        /**
 | 
			
		||||
         * Clear any existing persistence calls for object with given ID. This ensures only the most recent persistence
 | 
			
		||||
         * call is executed. This should prevent stale objects being persisted and overwriting fresh ones.
 | 
			
		||||
         */
 | 
			
		||||
        if (this.isScheduled(id)) {
 | 
			
		||||
            this.clearTransactionsFor(id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.clearTransactionFns[id] =
 | 
			
		||||
            this.transactionService.addToTransaction(
 | 
			
		||||
                chain(onCommit, release),
 | 
			
		||||
                chain(onCancel, release)
 | 
			
		||||
            );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -93,24 +93,33 @@ define(
 | 
			
		||||
                    expect(mockOnCancel).toHaveBeenCalled();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("ignores subsequent calls for the same object", function () {
 | 
			
		||||
                    manager.addToTransaction(
 | 
			
		||||
                        testId,
 | 
			
		||||
                        jasmine.createSpy(),
 | 
			
		||||
                        jasmine.createSpy()
 | 
			
		||||
                    );
 | 
			
		||||
                    expect(mockTransactionService.addToTransaction.calls.count())
 | 
			
		||||
                        .toEqual(1);
 | 
			
		||||
                });
 | 
			
		||||
                describe("Adds callbacks to transaction", function () {
 | 
			
		||||
                    beforeEach(function () {
 | 
			
		||||
                        spyOn(manager, 'clearTransactionsFor');
 | 
			
		||||
                        manager.clearTransactionsFor.and.callThrough();
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                it("accepts subsequent calls for other objects", function () {
 | 
			
		||||
                    manager.addToTransaction(
 | 
			
		||||
                        'other-id',
 | 
			
		||||
                        jasmine.createSpy(),
 | 
			
		||||
                        jasmine.createSpy()
 | 
			
		||||
                    );
 | 
			
		||||
                    expect(mockTransactionService.addToTransaction.calls.count())
 | 
			
		||||
                        .toEqual(2);
 | 
			
		||||
                    it("and clears pending calls if same object", function () {
 | 
			
		||||
                        manager.addToTransaction(
 | 
			
		||||
                            testId,
 | 
			
		||||
                            jasmine.createSpy(),
 | 
			
		||||
                            jasmine.createSpy()
 | 
			
		||||
                        );
 | 
			
		||||
                        expect(manager.clearTransactionsFor).toHaveBeenCalledWith(testId);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it("and does not clear pending calls if different object", function () {
 | 
			
		||||
                        manager.addToTransaction(
 | 
			
		||||
                            'other-id',
 | 
			
		||||
                            jasmine.createSpy(),
 | 
			
		||||
                            jasmine.createSpy()
 | 
			
		||||
                        );
 | 
			
		||||
                        expect(manager.clearTransactionsFor).not.toHaveBeenCalled();
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    afterEach(function () {
 | 
			
		||||
                        expect(mockTransactionService.addToTransaction.calls.count()).toEqual(2);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("does not remove callbacks from the transaction", function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,7 @@
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
<div class="ls-indicator {{ngModel.getCssClass()}}"
 | 
			
		||||
	 title="{{ngModel.getDescription()}}"
 | 
			
		||||
<div class="c-indicator {{ngModel.getCssClass()}}"
 | 
			
		||||
	 ng-show="ngModel.getText().length > 0">
 | 
			
		||||
	<span class="label">{{ngModel.getText()}}</span>
 | 
			
		||||
	<span class="label c-indicator__label">{{ngModel.getText()}}</span>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,7 @@ define(
 | 
			
		||||
                    if (isDestroyed) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var removeSelectable = openmct.selection.selectable(
 | 
			
		||||
                        element[0],
 | 
			
		||||
                        scope.$eval(attrs.mctSelectable),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
<div ng-show="notifications.length > 0" class="ls-indicator s-status-{{highest.severity}} icon-bell"
 | 
			
		||||
<div ng-show="notifications.length > 0" class="c-indicator c-indicator--clickable s-status-{{highest.severity}} icon-bell"
 | 
			
		||||
      ng-controller="NotificationIndicatorController">
 | 
			
		||||
    <span class="label">
 | 
			
		||||
        <a ng-click="showNotificationsList()">
 | 
			
		||||
           {{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></a>
 | 
			
		||||
    </span><span class="count">{{notifications.length}}</span>
 | 
			
		||||
    <span class="label c-indicator__label">
 | 
			
		||||
        <button ng-click="showNotificationsList()">
 | 
			
		||||
           {{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></button>
 | 
			
		||||
    </span><span class="c-indicator__count">{{notifications.length}}</span>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -43,23 +43,10 @@ define([], function () {
 | 
			
		||||
        var mutationTopic = topic('mutation');
 | 
			
		||||
        mutationTopic.listen(function (domainObject) {
 | 
			
		||||
            var persistence = domainObject.getCapability('persistence');
 | 
			
		||||
            var wasActive = transactionService.isActive();
 | 
			
		||||
            cacheService.put(domainObject.getId(), domainObject.getModel());
 | 
			
		||||
 | 
			
		||||
            if (hasChanged(domainObject)) {
 | 
			
		||||
 | 
			
		||||
                if (!wasActive) {
 | 
			
		||||
                    transactionService.startTransaction();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                transactionService.addToTransaction(
 | 
			
		||||
                    persistence.persist.bind(persistence),
 | 
			
		||||
                    persistence.refresh.bind(persistence)
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                if (!wasActive) {
 | 
			
		||||
                    transactionService.commit();
 | 
			
		||||
                }
 | 
			
		||||
                persistence.persist();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,22 +24,27 @@ define(
 | 
			
		||||
    ["../../src/runs/TransactingMutationListener"],
 | 
			
		||||
    function (TransactingMutationListener) {
 | 
			
		||||
 | 
			
		||||
        xdescribe("TransactingMutationListener", function () {
 | 
			
		||||
        describe("TransactingMutationListener", function () {
 | 
			
		||||
            var mockTopic,
 | 
			
		||||
                mockMutationTopic,
 | 
			
		||||
                mockCacheService,
 | 
			
		||||
                mockTransactionService,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockModel,
 | 
			
		||||
                mockPersistence;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockTopic = jasmine.createSpy('topic');
 | 
			
		||||
                mockMutationTopic =
 | 
			
		||||
                    jasmine.createSpyObj('mutation', ['listen']);
 | 
			
		||||
                mockCacheService =
 | 
			
		||||
                    jasmine.createSpyObj('cacheService', [
 | 
			
		||||
                        'put'
 | 
			
		||||
                    ]);
 | 
			
		||||
                mockTransactionService =
 | 
			
		||||
                    jasmine.createSpyObj('transactionService', [
 | 
			
		||||
                        'isActive',
 | 
			
		||||
                        'startTransaction',
 | 
			
		||||
                        'addToTransaction',
 | 
			
		||||
                        'commit'
 | 
			
		||||
                    ]);
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
@@ -52,18 +57,24 @@ define(
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockTopic.and.callFake(function (t) {
 | 
			
		||||
                    return (t === 'mutation') && mockMutationTopic;
 | 
			
		||||
                    expect(t).toBe('mutation');
 | 
			
		||||
                    return mockMutationTopic;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                mockDomainObject.getId.and.returnValue('mockId');
 | 
			
		||||
                mockDomainObject.getCapability.and.callFake(function (c) {
 | 
			
		||||
                    return (c === 'persistence') && mockPersistence;
 | 
			
		||||
                    expect(c).toBe('persistence');
 | 
			
		||||
                    return mockPersistence;
 | 
			
		||||
                });
 | 
			
		||||
                mockModel = {};
 | 
			
		||||
                mockDomainObject.getModel.and.returnValue(mockModel);
 | 
			
		||||
 | 
			
		||||
                mockPersistence.persisted.and.returnValue(true);
 | 
			
		||||
 | 
			
		||||
                return new TransactingMutationListener(
 | 
			
		||||
                    mockTopic,
 | 
			
		||||
                    mockTransactionService
 | 
			
		||||
                    mockTransactionService,
 | 
			
		||||
                    mockCacheService
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -72,48 +83,27 @@ define(
 | 
			
		||||
                    .toHaveBeenCalledWith(jasmine.any(Function));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            [false, true].forEach(function (isActive) {
 | 
			
		||||
                var verb = isActive ? "is" : "isn't";
 | 
			
		||||
            it("calls persist if the model has changed", function () {
 | 
			
		||||
                mockModel.persisted = Date.now();
 | 
			
		||||
 | 
			
		||||
                function onlyWhenInactive(expectation) {
 | 
			
		||||
                    return isActive ? expectation.not : expectation;
 | 
			
		||||
                }
 | 
			
		||||
                //Mark the model dirty by setting the mutated date later than the last persisted date.
 | 
			
		||||
                mockModel.modified = mockModel.persisted + 1;
 | 
			
		||||
 | 
			
		||||
                describe("when a transaction " + verb + " active", function () {
 | 
			
		||||
                    var innerVerb = isActive ? "does" : "doesn't";
 | 
			
		||||
                mockMutationTopic.listen.calls.mostRecent()
 | 
			
		||||
                    .args[0](mockDomainObject);
 | 
			
		||||
 | 
			
		||||
                    beforeEach(function () {
 | 
			
		||||
                        mockTransactionService.isActive.and.returnValue(isActive);
 | 
			
		||||
                    });
 | 
			
		||||
                expect(mockPersistence.persist).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                    describe("and mutation occurs", function () {
 | 
			
		||||
                        beforeEach(function () {
 | 
			
		||||
                            mockMutationTopic.listen.calls.mostRecent()
 | 
			
		||||
                                .args[0](mockDomainObject);
 | 
			
		||||
                        });
 | 
			
		||||
            it("does not call persist if the model has not changed", function () {
 | 
			
		||||
                mockModel.persisted = Date.now();
 | 
			
		||||
 | 
			
		||||
                mockModel.modified = mockModel.persisted;
 | 
			
		||||
 | 
			
		||||
                        it(innerVerb + " start a new transaction", function () {
 | 
			
		||||
                            onlyWhenInactive(
 | 
			
		||||
                                expect(mockTransactionService.startTransaction)
 | 
			
		||||
                            ).toHaveBeenCalled();
 | 
			
		||||
                        });
 | 
			
		||||
                mockMutationTopic.listen.calls.mostRecent()
 | 
			
		||||
                    .args[0](mockDomainObject);
 | 
			
		||||
 | 
			
		||||
                        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();
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                expect(mockPersistence.persist).not.toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,6 @@ define([
 | 
			
		||||
    "./src/actions/MoveAction",
 | 
			
		||||
    "./src/actions/CopyAction",
 | 
			
		||||
    "./src/actions/LinkAction",
 | 
			
		||||
    "./src/actions/GoToOriginalAction",
 | 
			
		||||
    "./src/actions/SetPrimaryLocationAction",
 | 
			
		||||
    "./src/services/LocatingCreationDecorator",
 | 
			
		||||
    "./src/services/LocatingObjectDecorator",
 | 
			
		||||
@@ -41,7 +40,6 @@ define([
 | 
			
		||||
    MoveAction,
 | 
			
		||||
    CopyAction,
 | 
			
		||||
    LinkAction,
 | 
			
		||||
    GoToOriginalAction,
 | 
			
		||||
    SetPrimaryLocationAction,
 | 
			
		||||
    LocatingCreationDecorator,
 | 
			
		||||
    LocatingObjectDecorator,
 | 
			
		||||
@@ -104,14 +102,6 @@ define([
 | 
			
		||||
                        "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",
 | 
			
		||||
                    "name": "Set Primary Location",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,60 +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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -1,93 +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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -49,7 +49,7 @@ define(
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ClockIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return "t-indicator-clock icon-clock no-collapse float-right";
 | 
			
		||||
            return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable";
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ClockIndicator.prototype.getText = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,7 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(['zepto'], function ($) {
 | 
			
		||||
define(['zepto', '../../../../src/api/objects/object-utils.js'], function ($, objectUtils) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The ImportAsJSONAction is available from context menus and allows a user
 | 
			
		||||
@@ -61,15 +60,39 @@ define(['zepto'], function ($) {
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.importObjectTree = function (objTree) {
 | 
			
		||||
        var parent = this.context.domainObject;
 | 
			
		||||
        var tree = this.generateNewIdentifiers(objTree);
 | 
			
		||||
        var rootId = tree.rootId;
 | 
			
		||||
        var rootObj = this.instantiate(tree.openmct[rootId], rootId);
 | 
			
		||||
        var namespace = parent.useCapability('adapter').identifier.namespace;
 | 
			
		||||
 | 
			
		||||
        // Instantiate all objects in tree with their newly genereated ids,
 | 
			
		||||
        // adding each to its rightful parent's composition
 | 
			
		||||
        rootObj.getCapability("location").setPrimaryLocation(parent.getId());
 | 
			
		||||
        this.deepInstantiate(rootObj, tree.openmct, []);
 | 
			
		||||
        parent.getCapability("composition").add(rootObj);
 | 
			
		||||
        var tree = this.generateNewIdentifiers(objTree, namespace);
 | 
			
		||||
        var rootId = tree.rootId;
 | 
			
		||||
 | 
			
		||||
        var rootModel = tree.openmct[rootId];
 | 
			
		||||
        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
 | 
			
		||||
            rootObj.getCapability("location").setPrimaryLocation(parent.getId());
 | 
			
		||||
            this.deepInstantiate(rootObj, tree.openmct, []);
 | 
			
		||||
            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) {
 | 
			
		||||
@@ -80,25 +103,35 @@ define(['zepto'], function ($) {
 | 
			
		||||
            var newObj;
 | 
			
		||||
 | 
			
		||||
            seen.push(parent.getId());
 | 
			
		||||
            parentModel.composition.forEach(function (childId, index) {
 | 
			
		||||
                if (!tree[childId] || seen.includes(childId)) {
 | 
			
		||||
 | 
			
		||||
            parentModel.composition.forEach(function (childId) {
 | 
			
		||||
                let keystring = this.openmct.objects.makeKeyString(childId);
 | 
			
		||||
 | 
			
		||||
                if (!tree[keystring] || seen.includes(keystring)) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                let newModel = tree[keystring];
 | 
			
		||||
                delete newModel.persisted;
 | 
			
		||||
 | 
			
		||||
                newObj = this.instantiate(tree[childId], childId);
 | 
			
		||||
                parent.getCapability("composition").add(newObj);
 | 
			
		||||
                newObj = this.instantiate(newModel, keystring);
 | 
			
		||||
                newObj.getCapability("location")
 | 
			
		||||
                    .setPrimaryLocation(tree[childId].location);
 | 
			
		||||
                    .setPrimaryLocation(tree[keystring].location);
 | 
			
		||||
                this.deepInstantiate(newObj, tree, seen);
 | 
			
		||||
            }, this);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.generateNewIdentifiers = function (tree) {
 | 
			
		||||
    ImportAsJSONAction.prototype.generateNewIdentifiers = function (tree, namespace) {
 | 
			
		||||
        // For each domain object in the file, generate new ID, replace in tree
 | 
			
		||||
        Object.keys(tree.openmct).forEach(function (domainObjectId) {
 | 
			
		||||
            var newId = this.identifierService.generate();
 | 
			
		||||
            tree = this.rewriteId(domainObjectId, newId, tree);
 | 
			
		||||
            let newId = {
 | 
			
		||||
                namespace: namespace,
 | 
			
		||||
                key: this.identifierService.generate()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let oldId = objectUtils.parseKeyString(domainObjectId);
 | 
			
		||||
 | 
			
		||||
            tree = this.rewriteId(oldId, newId, tree);
 | 
			
		||||
        }, this);
 | 
			
		||||
        return tree;
 | 
			
		||||
    };
 | 
			
		||||
@@ -109,9 +142,21 @@ define(['zepto'], function ($) {
 | 
			
		||||
     *
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    ImportAsJSONAction.prototype.rewriteId = function (oldID, newID, tree) {
 | 
			
		||||
        tree = JSON.stringify(tree).replace(new RegExp(oldID, 'g'), newID);
 | 
			
		||||
        return JSON.parse(tree);
 | 
			
		||||
    ImportAsJSONAction.prototype.rewriteId = function (oldId, newId, tree) {
 | 
			
		||||
        let newIdKeyString = this.openmct.objects.makeKeyString(newId);
 | 
			
		||||
        let oldIdKeyString = this.openmct.objects.makeKeyString(oldId);
 | 
			
		||||
        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 () {
 | 
			
		||||
 
 | 
			
		||||
@@ -100,7 +100,7 @@ define(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CouchIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return "icon-database " + this.state.statusClass;
 | 
			
		||||
            return "c-indicator--clickable icon-suitcase " + this.state.statusClass;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        CouchIndicator.prototype.getGlyphClass = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -84,7 +84,7 @@ define(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ElasticIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return "icon-database";
 | 
			
		||||
            return "c-indicator--clickable icon-suitcase";
 | 
			
		||||
        };
 | 
			
		||||
        ElasticIndicator.prototype.getGlyphClass = function () {
 | 
			
		||||
            return this.state.glyphClass;
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ define(
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("has a database icon", function () {
 | 
			
		||||
                expect(indicator.getCssClass()).toEqual("icon-database");
 | 
			
		||||
                expect(indicator.getCssClass()).toEqual("icon-suitcase");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("consults the database at the configured path", function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ define(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        LocalStorageIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return "icon-database s-status-caution";
 | 
			
		||||
            return "c-indicator--clickable icon-suitcase s-status-caution";
 | 
			
		||||
        };
 | 
			
		||||
        LocalStorageIndicator.prototype.getGlyphClass = function () {
 | 
			
		||||
            return 'caution';
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ define(
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("has a database icon", function () {
 | 
			
		||||
                expect(indicator.getCssClass()).toEqual("icon-database s-status-caution");
 | 
			
		||||
                expect(indicator.getCssClass()).toEqual("icon-suitcase s-status-caution");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("has a 'caution' class to draw attention", function () {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								src/MCT.js
									
									
									
									
									
								
							
							
						
						@@ -38,8 +38,8 @@ define([
 | 
			
		||||
    './ui/router/ApplicationRouter',
 | 
			
		||||
    './ui/router/Browse',
 | 
			
		||||
    '../platform/framework/src/Main',
 | 
			
		||||
    './styles-new/core.scss',
 | 
			
		||||
    './styles-new/notebook.scss',
 | 
			
		||||
    './styles/core.scss',
 | 
			
		||||
    './styles/notebook.scss',
 | 
			
		||||
    './ui/layout/Layout.vue',
 | 
			
		||||
    '../platform/core/src/objects/DomainObjectImpl',
 | 
			
		||||
    '../platform/core/src/capabilities/ContextualDomainObject',
 | 
			
		||||
@@ -246,12 +246,20 @@ define([
 | 
			
		||||
        this.branding = BrandingAPI.default;
 | 
			
		||||
 | 
			
		||||
        this.legacyRegistry = defaultRegistry;
 | 
			
		||||
 | 
			
		||||
        // Plugin's that are installed by default
 | 
			
		||||
 | 
			
		||||
        this.install(this.plugins.Plot());
 | 
			
		||||
        this.install(this.plugins.TelemetryTable());
 | 
			
		||||
        this.install(PreviewPlugin.default());
 | 
			
		||||
        this.install(LegacyIndicatorsPlugin());
 | 
			
		||||
        this.install(LicensesPlugin.default());
 | 
			
		||||
        this.install(RemoveActionPlugin.default());
 | 
			
		||||
        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());
 | 
			
		||||
 | 
			
		||||
        if (typeof BUILD_CONSTANTS !== 'undefined') {
 | 
			
		||||
            this.install(buildInfoPlugin(BUILD_CONSTANTS));
 | 
			
		||||
@@ -356,7 +364,7 @@ define([
 | 
			
		||||
        legacyRegistry.enable('adapter');
 | 
			
		||||
 | 
			
		||||
        this.router.route(/^\/$/, () => {
 | 
			
		||||
            this.router.setPath('/browse/mine');
 | 
			
		||||
            this.router.setPath('/browse/');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ const OUTSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "properties", "move", "li
 | 
			
		||||
export default class LegacyContextMenuAction {
 | 
			
		||||
    constructor(openmct, LegacyAction) {
 | 
			
		||||
        this.openmct = openmct;
 | 
			
		||||
        this.key = LegacyAction.definition.key;
 | 
			
		||||
        this.name = LegacyAction.definition.name;
 | 
			
		||||
        this.description = LegacyAction.definition.description;
 | 
			
		||||
        this.cssClass = LegacyAction.definition.cssClass;
 | 
			
		||||
@@ -33,20 +34,25 @@ export default class LegacyContextMenuAction {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    invoke(objectPath) {
 | 
			
		||||
        let context = {
 | 
			
		||||
            category: 'contextual',
 | 
			
		||||
            domainObject: this.openmct.legacyObject(objectPath)
 | 
			
		||||
        }
 | 
			
		||||
        let legacyAction = new this.LegacyAction(context);
 | 
			
		||||
        this.openmct.objects.getRoot().then((root) => {
 | 
			
		||||
            let pathWithRoot = objectPath.slice();
 | 
			
		||||
            pathWithRoot.push(root);
 | 
			
		||||
 | 
			
		||||
        if (!legacyAction.getMetadata) {
 | 
			
		||||
            let metadata = Object.create(this.LegacyAction.definition);
 | 
			
		||||
            metadata.context = context;
 | 
			
		||||
            legacyAction.getMetadata = function () {
 | 
			
		||||
                return metadata;
 | 
			
		||||
            }.bind(legacyAction);
 | 
			
		||||
        }
 | 
			
		||||
        legacyAction.perform();
 | 
			
		||||
            let context = {
 | 
			
		||||
                category: 'contextual',
 | 
			
		||||
                domainObject: this.openmct.legacyObject(pathWithRoot)
 | 
			
		||||
            }
 | 
			
		||||
            let legacyAction = new this.LegacyAction(context);
 | 
			
		||||
 | 
			
		||||
            if (!legacyAction.getMetadata) {
 | 
			
		||||
                let metadata = Object.create(this.LegacyAction.definition);
 | 
			
		||||
                metadata.context = context;
 | 
			
		||||
                legacyAction.getMetadata = function () {
 | 
			
		||||
                    return metadata;
 | 
			
		||||
                }.bind(legacyAction);
 | 
			
		||||
            }
 | 
			
		||||
            legacyAction.perform();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    appliesTo(objectPath) {
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ define([
 | 
			
		||||
    './runs/RegisterLegacyTypes',
 | 
			
		||||
    './services/LegacyObjectAPIInterceptor',
 | 
			
		||||
    './views/installLegacyViews',
 | 
			
		||||
    './policies/legacyCompositionPolicyAdapter',
 | 
			
		||||
    './policies/LegacyCompositionPolicyAdapter',
 | 
			
		||||
    './actions/LegacyActionAdapter'
 | 
			
		||||
], function (
 | 
			
		||||
    legacyRegistry,
 | 
			
		||||
 
 | 
			
		||||
@@ -57,8 +57,10 @@ define([
 | 
			
		||||
        }.bind(this);
 | 
			
		||||
 | 
			
		||||
        handleLegacyMutation = function (legacyObject) {
 | 
			
		||||
            var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId());
 | 
			
		||||
            this.eventEmitter.emit(newStyleObject.identifier.key + ":*", newStyleObject);
 | 
			
		||||
            var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId()),
 | 
			
		||||
                keystring = utils.makeKeyString(newStyleObject.identifier);
 | 
			
		||||
 | 
			
		||||
            this.eventEmitter.emit(keystring + ":*", newStyleObject);
 | 
			
		||||
            this.eventEmitter.emit('mutation', newStyleObject);
 | 
			
		||||
        }.bind(this);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,15 +45,30 @@ define([
 | 
			
		||||
            view: function (domainObject) {
 | 
			
		||||
                let $rootScope = openmct.$injector.get('$rootScope');
 | 
			
		||||
                let templateLinker = openmct.$injector.get('templateLinker');
 | 
			
		||||
                let scope = $rootScope.$new();
 | 
			
		||||
                let scope = $rootScope.$new(true);
 | 
			
		||||
                let legacyObject = convertToLegacyObject(domainObject);
 | 
			
		||||
                let isDestroyed = false;
 | 
			
		||||
                let unlistenToStatus;
 | 
			
		||||
                let element;
 | 
			
		||||
                scope.domainObject = legacyObject;
 | 
			
		||||
                scope.model = legacyObject.getModel();
 | 
			
		||||
 | 
			
		||||
                let child;
 | 
			
		||||
                let parent;
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    show: function (container) {
 | 
			
		||||
                        parent = container;
 | 
			
		||||
                        child = document.createElement('div');
 | 
			
		||||
                        parent.appendChild(child);
 | 
			
		||||
                        let statusCapability = legacyObject.getCapability('status');
 | 
			
		||||
                        unlistenToStatus = statusCapability.listen((newStatus) => {
 | 
			
		||||
                            child.classList.remove('s-status-timeconductor-unsynced');
 | 
			
		||||
 | 
			
		||||
                            if (newStatus.includes('timeconductor-unsynced')) {
 | 
			
		||||
                                child.classList.add('s-status-timeconductor-unsynced');
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        // TODO: implement "gestures" support ?
 | 
			
		||||
                        let uses = legacyView.uses || [];
 | 
			
		||||
                        let promises = [];
 | 
			
		||||
@@ -74,12 +89,13 @@ define([
 | 
			
		||||
                            uses.forEach(function (key, i) {
 | 
			
		||||
                                scope[key] = results[i];
 | 
			
		||||
                            });
 | 
			
		||||
                            element = openmct.$angular.element(child);
 | 
			
		||||
                            templateLinker.link(
 | 
			
		||||
                                scope,
 | 
			
		||||
                                openmct.$angular.element(container),
 | 
			
		||||
                                element,
 | 
			
		||||
                                legacyView
 | 
			
		||||
                            );
 | 
			
		||||
                            container.classList.add('u-contents');
 | 
			
		||||
                            child.classList.add('u-contents');
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (promises.length) {
 | 
			
		||||
@@ -92,8 +108,16 @@ define([
 | 
			
		||||
                            link();
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    onClearData() {
 | 
			
		||||
                        scope.$broadcast('clearData');
 | 
			
		||||
                    },
 | 
			
		||||
                    destroy: function () {
 | 
			
		||||
                        element.off();
 | 
			
		||||
                        element.remove();
 | 
			
		||||
                        scope.$destroy();
 | 
			
		||||
                        element = null;
 | 
			
		||||
                        scope = null;
 | 
			
		||||
                        unlistenToStatus();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
@@ -105,7 +129,7 @@ define([
 | 
			
		||||
                return priority;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return LegacyViewProvider;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,25 +25,34 @@ define([
 | 
			
		||||
            cssClass: representation.cssClass,
 | 
			
		||||
            description: representation.description,
 | 
			
		||||
            canView: function (selection) {
 | 
			
		||||
                if (!selection[0] || !selection[0].context.item) {
 | 
			
		||||
                if (selection.length !== 1 || selection[0].length === 0) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                let domainObject = selection[0].context.item;
 | 
			
		||||
                return domainObject.type === typeDefinition.key;
 | 
			
		||||
 | 
			
		||||
                let selectionContext = selection[0][0].context;
 | 
			
		||||
 | 
			
		||||
                if (!selectionContext.item) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return selectionContext.item.type === typeDefinition.key;
 | 
			
		||||
            },
 | 
			
		||||
            view: function (selection) {
 | 
			
		||||
                let domainObject = selection[0].context.item;
 | 
			
		||||
                let domainObject = selection[0][0].context.item;
 | 
			
		||||
                let $rootScope = openmct.$injector.get('$rootScope');
 | 
			
		||||
                let templateLinker = openmct.$injector.get('templateLinker');
 | 
			
		||||
                let scope = $rootScope.$new();
 | 
			
		||||
                let scope = $rootScope.$new(true);
 | 
			
		||||
                let legacyObject = convertToLegacyObject(domainObject);
 | 
			
		||||
                let isDestroyed = false;
 | 
			
		||||
                let element;
 | 
			
		||||
                scope.domainObject = legacyObject;
 | 
			
		||||
                scope.model = legacyObject.getModel();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    show: function (container) {
 | 
			
		||||
                        let child = document.createElement('div');
 | 
			
		||||
                        container.appendChild(child);
 | 
			
		||||
                        // TODO: implement "gestures" support ?
 | 
			
		||||
                        let uses = representation.uses || [];
 | 
			
		||||
                        let promises = [];
 | 
			
		||||
@@ -64,9 +73,10 @@ define([
 | 
			
		||||
                            uses.forEach(function (key, i) {
 | 
			
		||||
                                scope[key] = results[i];
 | 
			
		||||
                            });
 | 
			
		||||
                            element = openmct.$angular.element(child)
 | 
			
		||||
                            templateLinker.link(
 | 
			
		||||
                                scope,
 | 
			
		||||
                                openmct.$angular.element(container),
 | 
			
		||||
                                element,
 | 
			
		||||
                                representation
 | 
			
		||||
                            );
 | 
			
		||||
                            container.style.height = '100%';
 | 
			
		||||
@@ -83,12 +93,16 @@ define([
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    destroy: function () {
 | 
			
		||||
                        element.off();
 | 
			
		||||
                        element.remove();
 | 
			
		||||
                        scope.$destroy();
 | 
			
		||||
                        element = null;
 | 
			
		||||
                        scope = null;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return TypeInspectorViewProvider;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ let brandingOptions = {};
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set branding options for the application. These will override certain visual elements 
 | 
			
		||||
 * Set branding options for the application. These will override certain visual elements
 | 
			
		||||
 * of the application and allow for customization of the application.
 | 
			
		||||
 * @param {BrandingOptions} options
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -28,11 +28,6 @@ export default class Editor extends EventEmitter {
 | 
			
		||||
        super();
 | 
			
		||||
        this.editing = false;
 | 
			
		||||
        this.openmct = openmct;
 | 
			
		||||
        document.addEventListener('drop', (event) => {
 | 
			
		||||
            if (!this.isEditing()) {
 | 
			
		||||
                this.edit();
 | 
			
		||||
            }
 | 
			
		||||
        }, {capture: true});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -79,9 +74,11 @@ export default class Editor extends EventEmitter {
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    cancel() {
 | 
			
		||||
        this.getTransactionService().cancel();
 | 
			
		||||
        let cancelPromise = this.getTransactionService().cancel();
 | 
			
		||||
        this.editing = false;
 | 
			
		||||
        this.emit('isEditing', false);
 | 
			
		||||
 | 
			
		||||
        return cancelPromise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -22,8 +22,20 @@ define([
 | 
			
		||||
            publicAPI = {};
 | 
			
		||||
            publicAPI.objects = jasmine.createSpyObj('ObjectAPI', [
 | 
			
		||||
                'get',
 | 
			
		||||
                'mutate'
 | 
			
		||||
                'mutate',
 | 
			
		||||
                'observe',
 | 
			
		||||
                'areIdsEqual'
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            publicAPI.objects.areIdsEqual.and.callFake(function (id1, id2) {
 | 
			
		||||
                return id1.namespace === id2.namespace && id1.key === id2.key;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            publicAPI.composition = jasmine.createSpyObj('CompositionAPI', [
 | 
			
		||||
                'checkPolicy'
 | 
			
		||||
            ]);
 | 
			
		||||
            publicAPI.composition.checkPolicy.and.returnValue(true);
 | 
			
		||||
 | 
			
		||||
            publicAPI.objects.eventEmitter = jasmine.createSpyObj('eventemitter', [
 | 
			
		||||
                'on'
 | 
			
		||||
            ]);
 | 
			
		||||
@@ -91,7 +103,7 @@ define([
 | 
			
		||||
                beforeEach(function () {
 | 
			
		||||
                    listener = jasmine.createSpy('reorderListener');
 | 
			
		||||
                    composition.on('reorder', listener);
 | 
			
		||||
                    
 | 
			
		||||
 | 
			
		||||
                    return composition.load();
 | 
			
		||||
                });
 | 
			
		||||
                it('', function () {
 | 
			
		||||
@@ -119,49 +131,16 @@ define([
 | 
			
		||||
                    expect(newComposition[2].key).toEqual('a');
 | 
			
		||||
                })
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // TODO: Implement add/removal in new default provider.
 | 
			
		||||
            xit('synchronizes changes between instances', function () {
 | 
			
		||||
                var otherComposition = compositionAPI.get(domainObject);
 | 
			
		||||
                var addListener = jasmine.createSpy('addListener');
 | 
			
		||||
                var removeListener = jasmine.createSpy('removeListener');
 | 
			
		||||
                var otherAddListener = jasmine.createSpy('otherAddListener');
 | 
			
		||||
                var otherRemoveListener = jasmine.createSpy('otherRemoveListener');
 | 
			
		||||
            it('supports adding an object to composition', function () {
 | 
			
		||||
                let addListener = jasmine.createSpy('addListener');
 | 
			
		||||
                let mockChildObject = {
 | 
			
		||||
                    identifier: {key: 'mock-key', namespace: ''}
 | 
			
		||||
                };
 | 
			
		||||
                composition.on('add', addListener);
 | 
			
		||||
                composition.on('remove', removeListener);
 | 
			
		||||
                otherComposition.on('add', otherAddListener);
 | 
			
		||||
                otherComposition.on('remove', otherRemoveListener);
 | 
			
		||||
                composition.add(mockChildObject);
 | 
			
		||||
 | 
			
		||||
                return Promise.all([composition.load(), otherComposition.load()])
 | 
			
		||||
                    .then(function () {
 | 
			
		||||
                        expect(addListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherAddListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(removeListener).not.toHaveBeenCalled();
 | 
			
		||||
                        expect(otherRemoveListener).not.toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                        var object = addListener.calls.mostRecent().args[0];
 | 
			
		||||
                        composition.remove(object);
 | 
			
		||||
                        expect(removeListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherRemoveListener).toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                        addListener.reset();
 | 
			
		||||
                        otherAddListener.reset();
 | 
			
		||||
                        composition.add(object);
 | 
			
		||||
                        expect(addListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherAddListener).toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                        removeListener.reset();
 | 
			
		||||
                        otherRemoveListener.reset();
 | 
			
		||||
                        otherComposition.remove(object);
 | 
			
		||||
                        expect(removeListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherRemoveListener).toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                        addListener.reset();
 | 
			
		||||
                        otherAddListener.reset();
 | 
			
		||||
                        otherComposition.add(object);
 | 
			
		||||
                        expect(addListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherAddListener).toHaveBeenCalled();
 | 
			
		||||
                    });
 | 
			
		||||
                expect(domainObject.composition.length).toBe(4);
 | 
			
		||||
                expect(domainObject.composition[3]).toEqual(mockChildObject.identifier);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -184,7 +163,9 @@ define([
 | 
			
		||||
                                key: 'thing'
 | 
			
		||||
                            }
 | 
			
		||||
                        ]);
 | 
			
		||||
                    }
 | 
			
		||||
                    },
 | 
			
		||||
                    add: jasmine.createSpy('add'),
 | 
			
		||||
                    remove: jasmine.createSpy('remove')
 | 
			
		||||
                };
 | 
			
		||||
                domainObject = {
 | 
			
		||||
                    identifier: {
 | 
			
		||||
@@ -214,6 +195,25 @@ define([
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
            describe('Calling add or remove', function () {
 | 
			
		||||
                let mockChildObject;
 | 
			
		||||
 | 
			
		||||
                beforeEach(function () {
 | 
			
		||||
                    mockChildObject = {
 | 
			
		||||
                        identifier: {key: 'mock-key', namespace: ''}
 | 
			
		||||
                    };
 | 
			
		||||
                    composition.add(mockChildObject);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it('calls add on the provider', function () {
 | 
			
		||||
                    expect(customProvider.add).toHaveBeenCalledWith(domainObject, mockChildObject.identifier);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it('calls remove on the provider', function () {
 | 
			
		||||
                    composition.remove(mockChildObject);
 | 
			
		||||
                    expect(customProvider.remove).toHaveBeenCalledWith(domainObject, mockChildObject.identifier);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe('dynamic custom composition', function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,6 @@ define([
 | 
			
		||||
], function (
 | 
			
		||||
    _
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A CompositionCollection represents the list of domain objects contained
 | 
			
		||||
     * by another domain object. It provides methods for loading this
 | 
			
		||||
@@ -63,7 +62,6 @@ define([
 | 
			
		||||
        this.onProviderRemove = this.onProviderRemove.bind(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Listen for changes to this composition.  Supports 'add', 'remove', and
 | 
			
		||||
     * 'load' events.
 | 
			
		||||
@@ -76,7 +74,9 @@ define([
 | 
			
		||||
        if (!this.listeners[event]) {
 | 
			
		||||
            throw new Error('Event not supported by composition: ' + event);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.mutationListener) {
 | 
			
		||||
            this._synchronize();
 | 
			
		||||
        }
 | 
			
		||||
        if (this.provider.on && this.provider.off) {
 | 
			
		||||
            if (event === 'add') {
 | 
			
		||||
                this.provider.on(
 | 
			
		||||
@@ -132,6 +132,8 @@ define([
 | 
			
		||||
 | 
			
		||||
        this.listeners[event].splice(index, 1);
 | 
			
		||||
        if (this.listeners[event].length === 0) {
 | 
			
		||||
            this._destroy();
 | 
			
		||||
 | 
			
		||||
            // Remove provider listener if this is the last callback to
 | 
			
		||||
            // be removed.
 | 
			
		||||
            if (this.provider.off && this.provider.on) {
 | 
			
		||||
@@ -175,6 +177,9 @@ define([
 | 
			
		||||
     */
 | 
			
		||||
    CompositionCollection.prototype.add = function (child, skipMutate) {
 | 
			
		||||
        if (!skipMutate) {
 | 
			
		||||
            if (!this.publicAPI.composition.checkPolicy(this.domainObject, child)) {
 | 
			
		||||
                throw `Object of type ${child.type} cannot be added to object of type ${this.domainObject.type}`;
 | 
			
		||||
            }
 | 
			
		||||
            this.provider.add(this.domainObject, child.identifier);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.emit('add', child);
 | 
			
		||||
@@ -266,6 +271,19 @@ define([
 | 
			
		||||
        this.remove(child, true);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CompositionCollection.prototype._synchronize = function () {
 | 
			
		||||
        this.mutationListener = this.publicAPI.objects.observe(this.domainObject, '*', (newDomainObject) => {
 | 
			
		||||
            this.domainObject = JSON.parse(JSON.stringify(newDomainObject));
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CompositionCollection.prototype._destroy = function () {
 | 
			
		||||
        if (this.mutationListener) {
 | 
			
		||||
            this.mutationListener();
 | 
			
		||||
            delete this.mutationListener;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Emit events.
 | 
			
		||||
     * @private
 | 
			
		||||
 
 | 
			
		||||
@@ -48,24 +48,11 @@ define([
 | 
			
		||||
        this.listeningTo = {};
 | 
			
		||||
        this.onMutation = this.onMutation.bind(this);
 | 
			
		||||
 | 
			
		||||
        this.cannotContainDuplicates = this.cannotContainDuplicates.bind(this);
 | 
			
		||||
        this.cannotContainItself = this.cannotContainItself.bind(this);
 | 
			
		||||
 | 
			
		||||
        compositionAPI.addPolicy(this.cannotContainDuplicates);
 | 
			
		||||
        compositionAPI.addPolicy(this.cannotContainItself);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    DefaultCompositionProvider.prototype.cannotContainDuplicates = function (parent, child) {
 | 
			
		||||
        return this.appliesTo(parent) &&
 | 
			
		||||
            parent.composition.findIndex((composeeId) => {
 | 
			
		||||
                return composeeId.namespace === child.identifier.namespace &&
 | 
			
		||||
                    composeeId.key === child.identifier.key;
 | 
			
		||||
            }) === -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
@@ -199,9 +186,18 @@ define([
 | 
			
		||||
     * @memberof module:openmct.CompositionProvider#
 | 
			
		||||
     * @method add
 | 
			
		||||
     */
 | 
			
		||||
    DefaultCompositionProvider.prototype.add = function (domainObject, child) {
 | 
			
		||||
        throw new Error('Default Provider does not implement adding.');
 | 
			
		||||
        // TODO: this needs to be synchronized via mutation
 | 
			
		||||
    DefaultCompositionProvider.prototype.add = function (parent, childId) {
 | 
			
		||||
        if (!this.includes(parent, childId)) {
 | 
			
		||||
            parent.composition.push(childId);
 | 
			
		||||
            this.publicAPI.objects.mutate(parent, 'composition', parent.composition);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    DefaultCompositionProvider.prototype.includes = function (parent, childId) {
 | 
			
		||||
        return parent.composition.findIndex(composee =>
 | 
			
		||||
            this.publicAPI.objects.areIdsEqual(composee, childId)) !== -1;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,9 @@ class ContextMenuAPI {
 | 
			
		||||
     *           a single sentence or short paragraph) of this kind of view
 | 
			
		||||
     * @property {string} cssClass the CSS class to apply to labels for this
 | 
			
		||||
     *           view (to add icons, for instance)
 | 
			
		||||
     * @property {string} key unique key to identify the context menu action
 | 
			
		||||
     *           (used in custom context menu eg table rows, to identify which actions to include)
 | 
			
		||||
     * @property {boolean} hideInDefaultMenu optional flag to hide action from showing in the default context menu (tree item)
 | 
			
		||||
     */
 | 
			
		||||
    /**
 | 
			
		||||
     * @method appliesTo
 | 
			
		||||
@@ -72,12 +75,21 @@ class ContextMenuAPI {
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _showContextMenuForObjectPath(objectPath, x, y) {
 | 
			
		||||
    _showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded) {
 | 
			
		||||
 | 
			
		||||
        let applicableActions = this._allActions.filter((action) => {
 | 
			
		||||
            if (action.appliesTo === undefined) {
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            if (actionsToBeIncluded) {
 | 
			
		||||
                if (action.appliesTo === undefined && actionsToBeIncluded.includes(action.key)) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return action.appliesTo(objectPath, actionsToBeIncluded) && actionsToBeIncluded.includes(action.key);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (action.appliesTo === undefined) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return action.appliesTo(objectPath) && !action.hideInDefaultMenu;
 | 
			
		||||
            }
 | 
			
		||||
            return action.appliesTo(objectPath);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (this._activeContextMenu) {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,11 +28,11 @@ define(['zepto', './res/indicator-template.html'],
 | 
			
		||||
            this.openmct = openmct;
 | 
			
		||||
            this.element = $(indicatorTemplate)[0];
 | 
			
		||||
 | 
			
		||||
            this.textElement = this.element.querySelector('.indicator-text');
 | 
			
		||||
            this.textElement = this.element.querySelector('.js-indicator-text');
 | 
			
		||||
 | 
			
		||||
            //Set defaults
 | 
			
		||||
            this.text('New Indicator');
 | 
			
		||||
            this.description('A simple indicator');
 | 
			
		||||
            this.description('');
 | 
			
		||||
            this.iconClass(DEFAULT_ICON_CLASS);
 | 
			
		||||
            this.statusClass('');
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
<div class="ls-indicator" title="">
 | 
			
		||||
    <span class="label indicator-text"></span>
 | 
			
		||||
<div class="c-indicator c-indicator--clickable c-indicator--simple" title="">
 | 
			
		||||
    <span class="label js-indicator-text c-indicator__label"></span>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ import EventEmitter from 'EventEmitter';
 | 
			
		||||
 *
 | 
			
		||||
 * @typedef {object} NotificationModel
 | 
			
		||||
 * @property {string} message The message to be displayed by the notification
 | 
			
		||||
 * @property {number | 'unknown'} [progress] The progres of some ongoing task. Should be a number between 0 and 100, or 
 | 
			
		||||
 * @property {number | 'unknown'} [progress] The progres of some ongoing task. Should be a number between 0 and 100, or
 | 
			
		||||
 * with the string literal 'unknown'.
 | 
			
		||||
 * @property {string} [progressText] A message conveying progress of some ongoing task.
 | 
			
		||||
 | 
			
		||||
@@ -21,8 +21,10 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './object-utils.js',
 | 
			
		||||
    'lodash'
 | 
			
		||||
], function (
 | 
			
		||||
    utils,
 | 
			
		||||
    _
 | 
			
		||||
) {
 | 
			
		||||
    var ANY_OBJECT_EVENT = "mutation";
 | 
			
		||||
@@ -41,7 +43,9 @@ define([
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function qualifiedEventName(object, eventName) {
 | 
			
		||||
        return [object.identifier.key, eventName].join(':');
 | 
			
		||||
        var keystring = utils.makeKeyString(object.identifier);
 | 
			
		||||
 | 
			
		||||
        return [keystring, eventName].join(':');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MutableObject.prototype.stopListening = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,7 @@
 | 
			
		||||
        &.message-severity-error:before {
 | 
			
		||||
            @include legacyMessage();
 | 
			
		||||
            content: $glyph-icon-alert-triangle;
 | 
			
		||||
            color: $colorWarningLo;
 | 
			
		||||
            color: $colorWarningHi;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Messages in a list
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,7 @@
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex-direction: column;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__top-bar {
 | 
			
		||||
@@ -92,6 +93,7 @@
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex-direction: column;
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            height: 0; // Chrome 73 overflow bug fix
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
            padding-right: $interiorMargin; // fend off scroll bar
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -280,7 +280,11 @@ define([
 | 
			
		||||
        if (!provider) {
 | 
			
		||||
            return Promise.reject('No provider found');
 | 
			
		||||
        }
 | 
			
		||||
        return provider.request.apply(provider, arguments);
 | 
			
		||||
        return provider.request.apply(provider, arguments).catch((rejected) => {
 | 
			
		||||
            this.openmct.notifications.error('Error requesting telemetry data, see console for details');
 | 
			
		||||
            console.error(rejected);
 | 
			
		||||
            return Promise.reject(rejected);
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -329,7 +329,7 @@ define([
 | 
			
		||||
                        hints: {
 | 
			
		||||
                            priority: 2
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        key: "timestamp",
 | 
			
		||||
@@ -365,7 +365,7 @@ define([
 | 
			
		||||
                    {
 | 
			
		||||
                        key: "name",
 | 
			
		||||
                        name: "Name"
 | 
			
		||||
                        
 | 
			
		||||
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        key: "timestamp",
 | 
			
		||||
@@ -392,7 +392,7 @@ define([
 | 
			
		||||
                    {
 | 
			
		||||
                        key: "name",
 | 
			
		||||
                        name: "Name"
 | 
			
		||||
                        
 | 
			
		||||
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        key: "timestamp-utc",
 | 
			
		||||
@@ -434,7 +434,7 @@ define([
 | 
			
		||||
                    {
 | 
			
		||||
                        key: "name",
 | 
			
		||||
                        name: "Name"
 | 
			
		||||
                        
 | 
			
		||||
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        key: "timestamp-utc",
 | 
			
		||||
@@ -486,7 +486,7 @@ define([
 | 
			
		||||
                        hints: {
 | 
			
		||||
                            priority: 1
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        key: "timestamp-utc",
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,6 @@ class CSVExporter {
 | 
			
		||||
        let blob = new Blob([csvText], { type: "text/csv" });
 | 
			
		||||
        saveAs(blob, filename);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default CSVExporter;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,233 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "metadata": {
 | 
			
		||||
    "name": "openmct-symbols-12px",
 | 
			
		||||
    "lastOpened": 0,
 | 
			
		||||
    "created": 1527031065005
 | 
			
		||||
  },
 | 
			
		||||
  "iconSets": [
 | 
			
		||||
    {
 | 
			
		||||
      "selection": [
 | 
			
		||||
        {
 | 
			
		||||
          "order": 9,
 | 
			
		||||
          "id": 6,
 | 
			
		||||
          "name": "icon12-crosshair",
 | 
			
		||||
          "prevSize": 12,
 | 
			
		||||
          "code": 59696,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 11,
 | 
			
		||||
          "id": 8,
 | 
			
		||||
          "name": "icon12-grippy",
 | 
			
		||||
          "prevSize": 12,
 | 
			
		||||
          "code": 59697,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 10,
 | 
			
		||||
          "id": 7,
 | 
			
		||||
          "name": "icon12-list-view",
 | 
			
		||||
          "prevSize": 12,
 | 
			
		||||
          "code": 921666,
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "order": 6,
 | 
			
		||||
          "id": 3,
 | 
			
		||||
          "prevSize": 12,
 | 
			
		||||
          "code": 921865,
 | 
			
		||||
          "name": "icon12-folder",
 | 
			
		||||
          "tempChar": ""
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      "id": 0,
 | 
			
		||||
      "metadata": {
 | 
			
		||||
        "name": "openmct-symbols-12px",
 | 
			
		||||
        "importSize": {
 | 
			
		||||
          "width": 279,
 | 
			
		||||
          "height": 384
 | 
			
		||||
        },
 | 
			
		||||
        "designer": "Charles Hacskaylo"
 | 
			
		||||
      },
 | 
			
		||||
      "height": 1024,
 | 
			
		||||
      "prevSize": 12,
 | 
			
		||||
      "icons": [
 | 
			
		||||
        {
 | 
			
		||||
          "id": 6,
 | 
			
		||||
          "paths": [
 | 
			
		||||
            "M597.333 0h-170.667v256h170.667v-256z",
 | 
			
		||||
            "M1024 426.667h-256v170.667h256v-170.667z",
 | 
			
		||||
            "M597.333 768h-170.667v256h170.667v-256z",
 | 
			
		||||
            "M256 426.667h-256v170.667h256v-170.667z"
 | 
			
		||||
          ],
 | 
			
		||||
          "attrs": [
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {}
 | 
			
		||||
          ],
 | 
			
		||||
          "isMulticolor": false,
 | 
			
		||||
          "isMulticolor2": false,
 | 
			
		||||
          "grid": 0,
 | 
			
		||||
          "tags": [
 | 
			
		||||
            "icon12-crosshair"
 | 
			
		||||
          ],
 | 
			
		||||
          "colorPermutations": {
 | 
			
		||||
            "1161751": [
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {}
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "id": 8,
 | 
			
		||||
          "paths": [
 | 
			
		||||
            "M186.347 232.64c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z",
 | 
			
		||||
            "M186.347 511.867c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z",
 | 
			
		||||
            "M186.347 791.36c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z",
 | 
			
		||||
            "M465.573 93.173c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z",
 | 
			
		||||
            "M465.573 372.4c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z",
 | 
			
		||||
            "M379.028 558.728c51.328 3.652 89.978 48.223 86.325 99.551s-48.223 89.978-99.551 86.325c-51.328-3.652-89.978-48.223-86.325-99.551s48.223-89.978 99.551-86.325z",
 | 
			
		||||
            "M379.017 837.96c51.328 3.652 89.978 48.223 86.325 99.551s-48.223 89.978-99.551 86.325c-51.328-3.652-89.978-48.223-86.325-99.551s48.223-89.978 99.551-86.325z",
 | 
			
		||||
            "M744.773 232.64c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z",
 | 
			
		||||
            "M744.773 511.867c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z",
 | 
			
		||||
            "M744.773 791.36c0 51.458-41.715 93.173-93.173 93.173s-93.173-41.715-93.173-93.173c0-51.458 41.715-93.173 93.173-93.173s93.173 41.715 93.173 93.173z"
 | 
			
		||||
          ],
 | 
			
		||||
          "attrs": [
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {}
 | 
			
		||||
          ],
 | 
			
		||||
          "width": 745,
 | 
			
		||||
          "isMulticolor": false,
 | 
			
		||||
          "isMulticolor2": false,
 | 
			
		||||
          "grid": 0,
 | 
			
		||||
          "tags": [
 | 
			
		||||
            "icon12-grippy"
 | 
			
		||||
          ],
 | 
			
		||||
          "colorPermutations": {
 | 
			
		||||
            "1161751": [
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {}
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "id": 7,
 | 
			
		||||
          "paths": [
 | 
			
		||||
            "M0 0h1024v170.667h-1024v-170.667z",
 | 
			
		||||
            "M0 426.667h1024v170.667h-1024v-170.667z",
 | 
			
		||||
            "M0 853.333h1024v170.667h-1024v-170.667z"
 | 
			
		||||
          ],
 | 
			
		||||
          "attrs": [
 | 
			
		||||
            {},
 | 
			
		||||
            {},
 | 
			
		||||
            {}
 | 
			
		||||
          ],
 | 
			
		||||
          "isMulticolor": false,
 | 
			
		||||
          "isMulticolor2": false,
 | 
			
		||||
          "grid": 0,
 | 
			
		||||
          "tags": [
 | 
			
		||||
            "icon12-list-view"
 | 
			
		||||
          ],
 | 
			
		||||
          "colorPermutations": {
 | 
			
		||||
            "1161751": [
 | 
			
		||||
              {},
 | 
			
		||||
              {},
 | 
			
		||||
              {}
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "id": 3,
 | 
			
		||||
          "paths": [
 | 
			
		||||
            "M938.667 170.667h-341.333l-110.32-110.32c-33.2-33.2-98.667-60.347-145.68-60.347h-256c-47.073 0.136-85.197 38.26-85.333 85.32l-0 341.346c0.136-47.073 38.26-85.197 85.32-85.333l853.346-0c47.073 0.136 85.197 38.26 85.333 85.32l0-170.654c-0.136-47.073-38.26-85.197-85.32-85.333z",
 | 
			
		||||
            "M85.333 426.667h853.333c47.128 0 85.333 38.205 85.333 85.333v426.667c0 47.128-38.205 85.333-85.333 85.333h-853.333c-47.128 0-85.333-38.205-85.333-85.333v-426.667c0-47.128 38.205-85.333 85.333-85.333z"
 | 
			
		||||
          ],
 | 
			
		||||
          "attrs": [],
 | 
			
		||||
          "isMulticolor": false,
 | 
			
		||||
          "grid": 0,
 | 
			
		||||
          "tags": [
 | 
			
		||||
            "icon12-folder"
 | 
			
		||||
          ],
 | 
			
		||||
          "colorPermutations": {
 | 
			
		||||
            "1161751": [
 | 
			
		||||
              {
 | 
			
		||||
                "f": 0
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                "f": 0
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      "invisible": false,
 | 
			
		||||
      "colorThemes": [
 | 
			
		||||
        [
 | 
			
		||||
          [
 | 
			
		||||
            0,
 | 
			
		||||
            0,
 | 
			
		||||
            0,
 | 
			
		||||
            1
 | 
			
		||||
          ],
 | 
			
		||||
          [
 | 
			
		||||
            0,
 | 
			
		||||
            161,
 | 
			
		||||
            75,
 | 
			
		||||
            1
 | 
			
		||||
          ]
 | 
			
		||||
        ]
 | 
			
		||||
      ],
 | 
			
		||||
      "colorThemeIdx": 0
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "preferences": {
 | 
			
		||||
    "showGlyphs": true,
 | 
			
		||||
    "showCodes": true,
 | 
			
		||||
    "showQuickUse": true,
 | 
			
		||||
    "showQuickUse2": true,
 | 
			
		||||
    "showSVGs": true,
 | 
			
		||||
    "fontPref": {
 | 
			
		||||
      "prefix": "icon-",
 | 
			
		||||
      "metadata": {
 | 
			
		||||
        "fontFamily": "openmct-symbols-12px",
 | 
			
		||||
        "majorVersion": 1,
 | 
			
		||||
        "minorVersion": 0
 | 
			
		||||
      },
 | 
			
		||||
      "metrics": {
 | 
			
		||||
        "emSize": 1024,
 | 
			
		||||
        "baseline": 6.25,
 | 
			
		||||
        "whitespace": 50
 | 
			
		||||
      },
 | 
			
		||||
      "embed": false
 | 
			
		||||
    },
 | 
			
		||||
    "imagePref": {
 | 
			
		||||
      "prefix": "icon-",
 | 
			
		||||
      "png": true,
 | 
			
		||||
      "useClassSelector": true,
 | 
			
		||||
      "color": 0,
 | 
			
		||||
      "bgColor": 16777215
 | 
			
		||||
    },
 | 
			
		||||
    "historySize": 100,
 | 
			
		||||
    "gridSize": 16
 | 
			
		||||
  },
 | 
			
		||||
  "uid": -1
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
<?xml version="1.0" standalone="no"?>
 | 
			
		||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
<metadata>Generated by IcoMoon</metadata>
 | 
			
		||||
<defs>
 | 
			
		||||
<font id="openmct-symbols-12px" horiz-adv-x="1024">
 | 
			
		||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
 | 
			
		||||
<missing-glyph horiz-adv-x="1024" />
 | 
			
		||||
<glyph unicode=" " horiz-adv-x="512" d="" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon12-crosshair" d="M597.333 938.667h-170.667v-256h170.667v256zM1024 512h-256v-170.667h256v170.667zM597.333 170.667h-170.667v-256h170.667v256zM256 512h-256v-170.667h256v170.667z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon12-grippy" horiz-adv-x="745" d="M186.347 706.027c0-51.458-41.715-93.173-93.173-93.173s-93.173 41.715-93.173 93.173c0 51.458 41.715 93.173 93.173 93.173s93.173-41.715 93.173-93.173zM186.347 426.8c0-51.458-41.715-93.173-93.173-93.173s-93.173 41.715-93.173 93.173c0 51.458 41.715 93.173 93.173 93.173s93.173-41.715 93.173-93.173zM186.347 147.307c0-51.458-41.715-93.173-93.173-93.173s-93.173 41.715-93.173 93.173c0 51.458 41.715 93.173 93.173 93.173s93.173-41.715 93.173-93.173zM465.573 845.494c0-51.458-41.715-93.173-93.173-93.173s-93.173 41.715-93.173 93.173c0 51.458 41.715 93.173 93.173 93.173s93.173-41.715 93.173-93.173zM465.573 566.267c0-51.458-41.715-93.173-93.173-93.173s-93.173 41.715-93.173 93.173c0 51.458 41.715 93.173 93.173 93.173s93.173-41.715 93.173-93.173zM379.028 379.939c51.328-3.652 89.978-48.223 86.325-99.551s-48.223-89.978-99.551-86.325c-51.328 3.652-89.978 48.223-86.325 99.551s48.223 89.978 99.551 86.325zM379.017 100.707c51.328-3.652 89.978-48.223 86.325-99.551s-48.223-89.978-99.551-86.325c-51.328 3.652-89.978 48.223-86.325 99.551s48.223 89.978 99.551 86.325zM744.773 706.027c0-51.458-41.715-93.173-93.173-93.173s-93.173 41.715-93.173 93.173c0 51.458 41.715 93.173 93.173 93.173s93.173-41.715 93.173-93.173zM744.773 426.8c0-51.458-41.715-93.173-93.173-93.173s-93.173 41.715-93.173 93.173c0 51.458 41.715 93.173 93.173 93.173s93.173-41.715 93.173-93.173zM744.773 147.307c0-51.458-41.715-93.173-93.173-93.173s-93.173 41.715-93.173 93.173c0 51.458 41.715 93.173 93.173 93.173s93.173-41.715 93.173-93.173z" />
 | 
			
		||||
<glyph unicode="󡁂" glyph-name="icon12-list-view" d="M0 938.667h1024v-170.667h-1024v170.667zM0 512h1024v-170.667h-1024v170.667zM0 85.334h1024v-170.667h-1024v170.667z" />
 | 
			
		||||
<glyph unicode="󡄉" glyph-name="icon12-folder" d="M938.667 768h-341.333l-110.32 110.32c-33.2 33.2-98.667 60.347-145.68 60.347h-256c-47.073-0.136-85.197-38.26-85.333-85.32v-341.346c0.136 47.073 38.26 85.197 85.32 85.333h853.346c47.073-0.136 85.197-38.26 85.333-85.32v170.654c-0.136 47.073-38.26 85.197-85.32 85.333zM85.333 512h853.333c47.128 0 85.333-38.205 85.333-85.333v-426.667c0-47.128-38.205-85.333-85.333-85.333h-853.333c-47.128 0-85.333 38.205-85.333 85.333v426.667c0 47.128 38.205 85.333 85.333 85.333z" />
 | 
			
		||||
</font></defs></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 2.9 KiB  | 
@@ -1,123 +0,0 @@
 | 
			
		||||
<?xml version="1.0" standalone="no"?>
 | 
			
		||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
<metadata>Generated by IcoMoon</metadata>
 | 
			
		||||
<defs>
 | 
			
		||||
<font id="openmct-symbols-16px" horiz-adv-x="1024">
 | 
			
		||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
 | 
			
		||||
<missing-glyph horiz-adv-x="1024" />
 | 
			
		||||
<glyph unicode=" " horiz-adv-x="512" d="" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-alert-rect" d="M896 960h-768c-70.6-0.2-127.8-57.4-128-128v-768c0.2-70.6 57.4-127.8 128-128h768c70.6 0.2 127.8 57.4 128 128v768c-0.2 70.6-57.4 127.8-128 128zM576 64h-128v128h128v-128zM597.8 448l-37.8-192h-96l-37.8 192v384h171.8v-384z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-alert-triangle" d="M998.2 111.2l-422.6 739.6c-35 61.2-92 61.2-127 0l-422.8-739.6c-35-61.2-6-111.2 64.4-111.2h843.4c70.6 0 99.6 50 64.6 111.2zM576 64h-128v128h128v-128zM597.8 448l-37.8-192h-96l-37.8 192v256h171.8v-256z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-arrow-down" d="M512 192l512 512h-1024z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-arrow-left" d="M256 448l512-512v1024z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-arrow-right" d="M768 448l-512 512v-1024z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-arrow-double-up" d="M510 450l512-512h-1024zM510 962l512-512h-1024z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-arrow-tall-up" d="M512 960l512-1024h-1024z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-arrow-tall-down" d="M512-64l-512 1024h1024z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-arrow-double-down" d="M510 450l-512 512h1024zM510-62l-512 512h1024z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-arrow-up" d="M512 704l-512-512h1024z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-asterisk" d="M1004.166 619.542l-97.522 168.916-330.534-229.414 33.414 400.956h-195.048l33.414-400.956-330.534 229.414-97.522-168.916 363.944-171.542-363.944-171.542 97.522-168.916 330.534 229.414-33.414-400.956h195.048l-33.414 400.956 330.534-229.414 97.522 168.916-363.944 171.542z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-bell" d="M512-64c106 0 192 86 192 192h-384c0-106 86-192 192-192zM896 512v64c0 212-172 384-384 384s-384-172-384-384v-64c0-70.6-57.4-128-128-128v-128h1024v128c-70.6 0-128 57.4-128 128z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-box" d="M0 960h1024v-1024h-1024v1024z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-box-with-arrow-cursor" d="M894 962h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h400c-2.2 3.8-4 7.6-5.8 11.4l-255.2 576.8c-21.4 48.4-10.8 105 26.6 142.4 24.4 24.4 57.2 37.4 90.4 37.4 17.4 0 35.2-3.6 51.8-11l576.6-255.4c4-1.8 7.8-3.8 11.4-5.8v400.2c0.2 70.4-57.4 128-127.8 128zM958.6 322.6l-576.6 255.4 255.4-576.6 64.6 128.6 192-192 128 128-192 192z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-check" d="M1024 960l-640-640-384 384v-384l384-384 640 640z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-connectivity" d="M704 384c0-70.4-57.6-128-128-128h-128c-70.4 0-128 57.6-128 128v128c0 70.4 57.6 128 128 128h128c70.4 0 128-57.6 128-128v-128zM1024 448l-192 320v-640zM0 448l192 320v-640z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-database-in-brackets" d="M768 608c0-53.019-114.615-96-256-96s-256 42.981-256 96c0 53.019 114.615 96 256 96s256-42.981 256-96zM768 288v256c0-53-114.6-96-256-96s-256 43-256 96v-256c0-53 114.6-96 256-96s256 43 256 96zM832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM192 128.4v639.4c0 0.2 0.2 0.2 0.4 0.4h127.6v191.8h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192h-127.6c-0.2 0-0.4 0.2-0.4 0.4z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-eye-open" d="M512 843.6c-245.8 0-452.2-168-510.8-395.6 58.6-227.4 265-395.6 510.8-395.6s452.2 168 510.8 395.6c-58.6 227.4-265 395.6-510.8 395.6zM829.2 371.6c-22.6-34.4-50.6-64.8-83-90.4-32.8-25.8-69-45.6-108-59.4-40.4-14.2-82.8-21.4-126-21.4s-85.8 7.2-126 21.4c-39 13.8-75.4 33.8-108 59.4-32.4 25.6-60.4 55.8-83 90.4-15.8 24-28.8 49.6-38.6 76.4 10 26.8 23 52.4 38.6 76.4 22.6 34.4 50.6 64.8 83 90.4 32.8 25.8 69 45.6 108 59.4 40.4 14.2 82.8 21.4 126 21.4s85.8-7.2 126-21.4c39-13.8 75.4-33.8 108-59.4 32.4-25.6 60.4-55.8 83-90.4 15.8-24 28.8-49.6 38.6-76.4-9.8-26.8-22.8-52.4-38.6-76.4zM704 448c0-106.039-85.961-192-192-192s-192 85.961-192 192c0 106.039 85.961 192 192 192s192-85.961 192-192z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-gear" d="M1024 384v128l-140.976 35.244c-8.784 32.922-21.818 64.106-38.504 92.918l74.774 124.622-90.51 90.51-124.622-74.774c-28.812 16.686-59.996 29.72-92.918 38.504l-35.244 140.976h-128l-35.244-140.976c-32.922-8.784-64.106-21.818-92.918-38.504l-124.622 74.774-90.51-90.51 74.774-124.622c-16.686-28.812-29.72-59.996-38.504-92.918l-140.976-35.244v-128l140.976-35.244c8.784-32.922 21.818-64.106 38.504-92.918l-74.774-124.622 90.51-90.51 124.622 74.774c28.812-16.686 59.996-29.72 92.918-38.504l35.244-140.976h128l35.244 140.976c32.922 8.784 64.106 21.818 92.918 38.504l124.622-74.774 90.51 90.51-74.774 124.622c16.686 28.812 29.72 59.996 38.504 92.918l140.976 35.244zM704 448c0-106.038-85.962-192-192-192s-192 85.962-192 192 85.962 192 192 192 192-85.962 192-192z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-hourglass" d="M1024 960h-1024c0-282.8 229.2-512 512-512s512 229.2 512 512zM512 576c-102.6 0-199 40-271.6 112.4-41.2 41.2-72 90.2-90.8 143.6h724.6c-18.8-53.4-49.6-102.4-90.8-143.6-72.4-72.4-168.8-112.4-271.4-112.4zM512 448c-282.8 0-512-229.2-512-512h1024c0 282.8-229.2 512-512 512z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-info" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM512 832c70.6 0 128-57.4 128-128s-57.4-128-128-128c-70.6 0-128 57.4-128 128s57.4 128 128 128zM704 128h-384v128h64v256h256v-256h64v-128z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-link" d="M1024 448l-512 512v-307.2l-512-204.8v-256h512v-256z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-lock" d="M832 576h-32v96c0 158.8-129.2 288-288 288s-288-129.2-288-288v-96h-32c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h640c70.4 0 128 57.6 128 128v384c0 70.4-57.6 128-128 128zM416 672c0 53 43 96 96 96s96-43 96-96v-96h-192v96z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-minus" d="M960 320c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64h-896c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h896z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-people" d="M704 640h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM256 640h64c70.4 0 128 57.6 128 128v64c0 70.4-57.6 128-128 128h-64c-70.4 0-128-57.6-128-128v-64c0-70.4 57.6-128 128-128zM832 576h-192c-34.908 0-67.716-9.448-96-25.904 57.278-33.324 96-95.404 96-166.096v-448h384v448c0 105.6-86.4 192-192 192zM384 576h-192c-105.6 0-192-86.4-192-192v-448h576v448c0 105.6-86.4 192-192 192z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-person" d="M768 704c0-105.6-86.4-192-192-192h-128c-105.6 0-192 86.4-192 192v64c0 105.6 86.4 192 192 192h128c105.6 0 192-86.4 192-192v-64zM64-64v192c0 140.8 115.2 256 256 256h384c140.8 0 256-115.2 256-256v-192z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-plus" d="M960 576h-330v320c0 35.2-28.8 64-64 64h-108c-35.2 0-64-28.8-64-64v-320h-330c-35.2 0-64-28.8-64-64v-128c0-35.2 28.8-64 64-64h330v-320c0-35.2 28.8-64 64-64h108c35.2 0 64 28.8 64 64v320h330c35.2 0 64 28.8 64 64v128c0 35.2-28.8 64-64 64z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-trash" d="M832 832h-192.36v64c0 35.2-28.8 64-64 64h-128c-35.2 0-64-28.8-64-64v-64h-191.64c-105.6 0-192-72-192-160s0-160 0-160h64v-384c0-105.6 86.4-192 192-192h512c105.6 0 192 86.4 192 192v384h64c0 0 0 72 0 160s-86.4 160-192 160zM320 128h-128v384h128v-384zM576 128h-128v384h128v-384zM832 128h-128v384h128v-384z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-x" d="M384 448l-365.332-365.332c-24.89-24.89-24.89-65.62 0-90.51l37.49-37.49c24.89-24.89 65.62-24.89 90.51 0 0 0 365.332 365.332 365.332 365.332l365.332-365.332c24.89-24.89 65.62-24.89 90.51 0l37.49 37.49c24.89 24.89 24.89 65.62 0 90.51l-365.332 365.332c0 0 365.332 365.332 365.332 365.332 24.89 24.89 24.89 65.62 0 90.51l-37.49 37.49c-24.89 24.89-65.62 24.89-90.51 0 0 0-365.332-365.332-365.332-365.332l-365.332 365.332c-24.89 24.89-65.62 24.89-90.51 0l-37.49-37.49c-24.89-24.89-24.89-65.62 0-90.51 0 0 365.332-365.332 365.332-365.332z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-brackets" d="M832 960h-192v-192h191.66l0.34-0.34v-639.32l-0.34-0.34h-191.66v-192h192c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM384 128h-191.66l-0.34 0.34v639.32l0.34 0.34h191.66v192h-192c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h192v192z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-crosshair" d="M574 962h-128v-320h128v320zM1022 514h-320v-128h320v128zM574 258h-128v-320h128v320zM318 514h-320v-128h320v128z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-grippy-v2" horiz-adv-x="586" d="M146.4 777.2c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM146.4 557.8c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM146.4 338.2c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM146.4 118.8c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM365.8 886.8c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM365.8 667.4c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM365.8 448c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM365.8 228.6c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM365.8 9.2c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM585.2 777.2c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM585.2 557.8c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM585.2 338.2c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2zM585.2 118.8c0-40.427-32.773-73.2-73.2-73.2s-73.2 32.773-73.2 73.2c0 40.427 32.773 73.2 73.2 73.2s73.2-32.773 73.2-73.2z" />
 | 
			
		||||
<glyph unicode="" glyph-name="icon-arrow-right-equilateral" d="M962 448l-896-512v1024z" />
 | 
			
		||||
<glyph unicode="󡀀" glyph-name="icon-arrows-out" d="M0 448l256-256v512zM512 960l-256-256h512zM512-64l256 256h-512zM768 704v-512l256 256z" />
 | 
			
		||||
<glyph unicode="󡀁" glyph-name="icon-arrows-right-left" d="M1024 448l-448-512v1024zM448 960l-448-512 448-512z" />
 | 
			
		||||
<glyph unicode="󡀂" glyph-name="icon-arrows-up-down" d="M512 960l512-448h-1024zM0 384l512-448 512 448z" />
 | 
			
		||||
<glyph unicode="󡀄" glyph-name="icon-bullet" d="M832 208c0-44-36-80-80-80h-480c-44 0-80 36-80 80v480c0 44 36 80 80 80h480c44 0 80-36 80-80v-480z" />
 | 
			
		||||
<glyph unicode="󡀅" glyph-name="icon-calendar" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM640 512h-256v192h256v-192zM384 448h256v-192h-256v192zM320 256h-256v192h256v-192zM320 704v-192h-256v192h256zM128 0c-17 0-33 6.6-45.2 18.8s-18.8 28.2-18.8 45.2v128h256v-192h-192zM384 0v192h256v-192h-256zM960 64c0-17-6.6-33-18.8-45.2s-28.2-18.8-45.2-18.8h-192v192h256v-128zM960 256h-256v192h256v-192zM960 512h-256v192h256v-192z" />
 | 
			
		||||
<glyph unicode="󡀆" glyph-name="icon-chain-links" d="M958.4 894.4c-43.8 43.8-101 65.6-158.4 65.6s-114.6-21.8-158.4-65.6l-128-128c-74-74-85.4-187-34-273l-12.8-12.8c-35.4 20.8-75 31.4-114.8 31.4-57.4 0-114.6-21.8-158.4-65.6l-128-128c-87.4-87.4-87.4-229.4 0-316.8 43.8-43.8 101-65.6 158.4-65.6s114.6 21.8 158.4 65.6l128 128c74 74 85.4 187 34 273l12.8 12.8c35.2-21 75-31.6 114.6-31.6 57.4 0 114.6 21.8 158.4 65.6l128 128c87.6 87.6 87.6 229.6 0.2 317zM419.8 220.2l-128-128c-18-18.2-42.2-28.2-67.8-28.2s-49.8 10-67.8 28.2c-37.4 37.4-37.4 98.4 0 135.8l128 128c18.2 18.2 42.2 28.2 67.8 28.2 5.6 0 11.2-0.6 16.8-1.4l-55.6-55.6c-10.4-10.4-16.2-24.2-16.2-38.8s5.8-28.6 16.2-38.8c10.4-10.4 24.2-16.2 38.8-16.2s28.6 5.8 38.8 16.2l55.6 55.6c5.4-30.4-3.6-62.2-26.6-85zM867.8 668.2l-128-128c-18-18.2-42.2-28.2-67.8-28.2-5.6 0-11.2 0.6-16.8 1.4l55.6 55.6c10.4 10.4 16.2 24.2 16.2 38.8s-5.8 28.6-16.2 38.8c-10.4 10.4-24.2 16.2-38.8 16.2s-28.6-5.8-38.8-16.2l-55.6-55.6c-5.2 29.8 3.6 61.6 26.6 84.6l128 128c18 18.4 42.2 28.4 67.8 28.4s49.8-10 67.8-28.2c37.6-37.4 37.6-98.2 0-135.6z" />
 | 
			
		||||
<glyph unicode="󡀇" glyph-name="icon-pane-collapse-left" horiz-adv-x="832" d="M0 960h192v-1024h-192v1024zM832 704h-256v256l-320-416 320-416v256h256v320z" />
 | 
			
		||||
<glyph unicode="󡀈" glyph-name="icon-pane-collapse-right" horiz-adv-x="832" d="M640 960h192v-1024h-192v1024zM0 704h256v256l320-416-320-416v256h-256v320z" />
 | 
			
		||||
<glyph unicode="󡀉" glyph-name="icon-download" d="M832 384v-255.66l-0.34-0.34-639.66 0.34v255.66h-192v-256c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v256h-192zM512 320l448 448h-256v192h-384v-192h-256l448-448z" />
 | 
			
		||||
<glyph unicode="󡀐" glyph-name="icon-duplicate" d="M640 704v128c0 70.4-57.6 128-128 128h-384c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h128v139.6c0 134.8 109.6 244.4 244.4 244.4h139.6zM896 576h-384c-70.4 0-128-57.6-128-128v-384c0-70.4 57.6-128 128-128h384c70.4 0 128 57.6 128 128v384c0 70.4-57.6 128-128 128z" />
 | 
			
		||||
<glyph unicode="󡀑" glyph-name="icon-folder-new" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128zM704 160h-128v-128h-128v128h-128v128h128v128h128v-128h128v-128z" />
 | 
			
		||||
<glyph unicode="󡀒" glyph-name="icon-fullscreen-expand" d="M192.344 128c-0.118 0.1-0.244 0.224-0.344 0.344v191.656h-192v-192c0-105.6 86.4-192 192-192h192v192h-191.656zM192 767.656c0.1 0.118 0.224 0.244 0.344 0.344h191.656v192h-192c-105.6 0-192-86.4-192-192v-192h192v191.656zM832 960h-192v-192h191.656c0.118-0.1 0.244-0.226 0.344-0.344v-191.656h192v192c0 105.6-86.4 192-192 192zM832 128.344c-0.1-0.118-0.224-0.244-0.344-0.344h-191.656v-192h192c105.6 0 192 86.4 192 192v192h-192v-191.656z" />
 | 
			
		||||
<glyph unicode="󡀓" glyph-name="icon-fullscreen-collapse" d="M191.656 128c0.118-0.1 0.244-0.224 0.344-0.344v-191.656h192v192c0 105.6-86.4 192-192 192h-192v-192h191.656zM192 768.344c-0.1-0.118-0.224-0.244-0.344-0.344h-191.656v-192h192c105.6 0 192 86.4 192 192v192h-192v-191.656zM832 576h192v192h-191.656c-0.118 0.1-0.244 0.226-0.344 0.344v191.656h-192v-192c0-105.6 86.4-192 192-192zM832 127.656c0.1 0.118 0.224 0.244 0.344 0.344h191.656v192h-192c-105.6 0-192-86.4-192-192v-192h192v191.656z" />
 | 
			
		||||
<glyph unicode="󡀔" glyph-name="icon-layers" d="M1024 576l-512 384-512-384 512-384zM512 64l-426.666 320-85.334-64 512-384 512 384-85.334 64z" />
 | 
			
		||||
<glyph unicode="󡀕" glyph-name="icon-line-horz" d="M64 384c-35.346 0-64 28.654-64 64s28.654 64 64 64h896c35.346 0 64-28.654 64-64s-28.654-64-64-64h-896z" />
 | 
			
		||||
<glyph unicode="󡀖" glyph-name="icon-magnify" d="M1024 64l-256.8 256.8c42.4 66.6 65 144 64.8 223.2 0 229.8-186.2 416-416 416s-416-186.2-416-416 186.2-416 416-416c79-0.2 156.4 22.4 223.2 64.8l256.8-256.8 128 128zM212.4 340.4c-112.4 112.4-112.4 294.8 0 407.2s294.8 112.4 407.2 0 112.4-294.8 0-407.2c-54-54-127.2-84.4-203.6-84.4-76.4-0.2-149.8 30.2-203.6 84.4z" />
 | 
			
		||||
<glyph unicode="󡀗" glyph-name="icon-magnify-in" d="M1024 64l-256.86 256.86c40.681 62.963 64.861 139.898 64.861 222.481 0 0.232 0 0.464-0.001 0.696v-0.036c0 229.76-186.24 416-416 416s-416-186.24-416-416 186.24-416 416-416c0.196 0 0.427-0.001 0.659-0.001 82.583 0 159.518 24.18 224.112 65.846l-1.631-0.985 256.86-256.86zM212.36 340.36c-52.114 52.117-84.346 124.114-84.346 203.64 0 159.058 128.942 288 288 288s288-128.942 288-288c0-159.058-128.942-288-288-288-0.005 0-0.010 0-0.014 0h0.001c-0.242-0.001-0.529-0.001-0.815-0.001-79.271 0-151.010 32.251-202.811 84.348l-0.013 0.014zM224 608h384v-128h-384v128zM352 736h128v-384h-128v384z" />
 | 
			
		||||
<glyph unicode="󡀘" glyph-name="icon-magnify-out" d="M767.2 320.8c42.4 66.6 65 144 64.8 223.2 0 229.8-186.2 416-416 416s-416-186.2-416-416 186.2-416 416-416c79-0.2 156.4 22.4 223.2 64.8l256.8-256.8 128 128-256.8 256.8zM619.6 340.4c-54-54-127.2-84.4-203.6-84.4-76.4-0.2-149.8 30.2-203.6 84.4-112.4 112.4-112.4 294.8 0 407.2s294.8 112.4 407.2 0c112.4-112.4 112.4-294.8 0-407.2zM224 608h384v-128h-384v128z" />
 | 
			
		||||
<glyph unicode="󡀙" glyph-name="icon-menu" d="M0 832h1024v-128h-1024v128zM0 512h1024v-128h-1024v128zM0 192h1024v-128h-1024v128z" />
 | 
			
		||||
<glyph unicode="󡀠" glyph-name="icon-move" d="M293.4 448l218.6 218.6 256-256v421.4c0 70.4-57.6 128-128 128h-512c-70.4 0-128-57.6-128-128v-512c0-70.4 57.6-128 128-128h421.4l-256 256zM1024 512h-128v-320l-384 384-128-128 384-384h-320v-128h576z" />
 | 
			
		||||
<glyph unicode="󡀡" glyph-name="icon-new-window" d="M448 960v-128h320l-384-384 128-128 384 384v-320h128v576zM576 285.726v-157.382c-0.1-0.118-0.226-0.244-0.344-0.344h-383.312c-0.118 0.1-0.244 0.226-0.344 0.344v383.312c0.1 0.118 0.226 0.244 0.344 0.344h157.382l192 192h-349.726c-105.6 0-192-86.4-192-192v-384c0-105.6 86.4-192 192-192h384c105.6 0 192 86.4 192 192v349.726l-192-192z" />
 | 
			
		||||
<glyph unicode="󡀢" glyph-name="icon-paint-bucket" d="M544 736v-224c0-88.4-71.6-160-160-160s-160 71.6-160 160v97.2l-197.4-196.4c-50-50-12.4-215.2 112.4-340s290-162.4 340-112.4l417 423.6-352 352zM896-64c70.6 0 128 57.4 128 128 0 108.6-128 192-128 192s-128-83.4-128-192c0-70.6 57.4-128 128-128zM384 448c-35.4 0-64 28.6-64 64v384c0 35.4 28.6 64 64 64s64-28.6 64-64v-384c0-35.4-28.6-64-64-64z" />
 | 
			
		||||
<glyph unicode="󡀣" glyph-name="icon-pause" d="M126 962h256v-1024h-256v1024zM638 962h256v-1024h-256v1024z" />
 | 
			
		||||
<glyph unicode="󡀤" glyph-name="icon-pencil" d="M922.344 858.32c-38.612 38.596-81.306 69.232-120.304 86.324-68.848 30.25-104.77 9.078-120.194-6.344l-516.228-516.216-3.136-9.152-162.482-476.932 485.998 165.612 6.73 6.806 509.502 509.506c9.882 9.866 21.768 27.77 21.768 56.578 0.002 50.71-38.996 121.148-101.654 183.818zM237.982 104.34l-69.73 69.728 69.25 203.228 18.498 6.704h64v-128h128v-64l-6.846-18.506-203.172-69.154z" />
 | 
			
		||||
<glyph unicode="󡀥" glyph-name="icon-play" d="M1024 448l-1024-512v1024z" />
 | 
			
		||||
<glyph unicode="󡀦" glyph-name="icon-plot-resource" d="M255.884 256c0.040 0.034 0.082 0.074 0.116 0.116v127.884c0 70.58 57.42 128 128 128h255.884c0.040 0.034 0.082 0.074 0.116 0.116v127.884c0 70.58 57.42 128 128 128h143.658c-93.832 117.038-237.98 192-399.658 192-282.77 0-512-229.23-512-512 0-67.904 13.25-132.704 37.256-192h218.628zM768.116 640c-0.040-0.034-0.082-0.074-0.116-0.116v-127.884c0-70.58-57.42-128-128-128h-255.884c-0.040-0.034-0.082-0.074-0.116-0.116v-127.884c0-70.58-57.42-128-128-128h-143.658c93.832-117.038 237.98-192 399.658-192 282.77 0 512 229.23 512 512 0 67.904-13.25 132.704-37.256 192h-218.628z" />
 | 
			
		||||
<glyph unicode="󡀧" glyph-name="icon-pointer-left" horiz-adv-x="512" d="M510-64l-256 512 256 512h-256l-256-512 256-512z" />
 | 
			
		||||
<glyph unicode="󡀨" glyph-name="icon-pointer-right" horiz-adv-x="512" d="M-2 960l256-512-256-512h256l256 512-256 512z" />
 | 
			
		||||
<glyph unicode="󡀩" glyph-name="icon-refresh" d="M960 528v432l-164.8-164.8c-79.8 65.2-178.8 100.8-283.2 100.8-119.6 0-232.2-46.6-316.8-131.2s-131.2-197.2-131.2-316.8 46.6-232.2 131.2-316.8c84.6-84.6 197.2-131.2 316.8-131.2s232.2 46.6 316.8 131.2c69.4 69.4 113.2 157.4 126.6 252.8h-130c-29.8-145.8-159-256-313.6-256-176.4 0-320 143.6-320 320s143.8 320 320.2 320c72 0 138.4-23.8 192-64l-176-176h432z" />
 | 
			
		||||
<glyph unicode="󡀰" glyph-name="icon-save" d="M192.2 384c-0.2 0-0.2 0 0 0l-0.2-448h640v447.8c0 0 0 0-0.2 0.2h-639.6zM978.8 749.2l-165.4 165.4c-25 25-74.2 45.4-109.4 45.4h-576c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128v448c0 35.2 28.8 64 64 64h640c35.2 0 64-28.8 64-64v-448c70.4 0 128 57.6 128 128v576c0 35.2-20.4 84.4-45.2 109.2zM704 704c0-35.2-28.8-64-64-64h-448c-35.2 0-64 28.8-64 64v192h320v-192h128v192h128v-192z" />
 | 
			
		||||
<glyph unicode="󡀱" glyph-name="icon-sine" d="M1022.294 448c-1.746 7.196-3.476 14.452-5.186 21.786-20.036 85.992-53.302 208.976-98 306.538-22.42 48.938-45.298 86.556-69.946 115.006-48.454 55.93-98.176 67.67-131.356 67.67s-82.902-11.74-131.356-67.672c-24.648-28.45-47.528-66.068-69.948-115.006-44.696-97.558-77.962-220.544-98-306.538-21.646-92.898-46.444-175.138-71.71-237.836-16.308-40.46-30.222-66.358-40.6-82.604-10.378 16.246-24.292 42.142-40.6 82.604-23.272 57.75-46.144 132.088-66.524 216.052h-197.362c1.746-7.196 3.476-14.452 5.186-21.786 20.036-85.992 53.302-208.976 98-306.538 22.42-48.938 45.298-86.556 69.946-115.006 48.454-55.932 98.176-67.672 131.356-67.672s82.902 11.74 131.356 67.672c24.648 28.45 47.528 66.068 69.948 115.006 44.696 97.558 77.962 220.544 98 306.538 21.646 92.898 46.444 175.138 71.71 237.836 16.308 40.46 30.222 66.358 40.6 82.604 10.378-16.246 24.292-42.142 40.6-82.604 23.274-57.748 46.146-132.086 66.526-216.050h197.36z" />
 | 
			
		||||
<glyph unicode="󡀲" glyph-name="icon-T" d="M0 960v-256h128v64h256v-704h-192v-128h640v128h-192v704h256v-64h128v256z" />
 | 
			
		||||
<glyph unicode="󡀳" glyph-name="icon-thumbs-strip" d="M448 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 578c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM448 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320zM1024 2c0-35.2-28.8-64-64-64h-320c-35.2 0-64 28.8-64 64v320c0 35.2 28.8 64 64 64h320c35.2 0 64-28.8 64-64v-320z" />
 | 
			
		||||
<glyph unicode="󡀴" glyph-name="icon-two-parts-both" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM128 832h320v-768h-320v768zM896 64h-320v768h320v-768z" />
 | 
			
		||||
<glyph unicode="󡀵" glyph-name="icon-two-parts-one-only" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM896 64h-320v768h320v-768z" />
 | 
			
		||||
<glyph unicode="󡀶" glyph-name="icon-resync" d="M795.2 795.2c-79.8 65.2-178.8 100.8-283.2 100.8-119.6 0-232.2-46.6-316.8-131.2-69.4-69.4-113.2-157.4-126.6-252.8h130c29.6 145.8 158.8 256 313.4 256 72 0 138.4-23.8 192-64l-176-176h432v432l-164.8-164.8zM512 128c-72 0-138.4 23.8-192 64l176 176h-432v-432l164.8 164.8c79.8-65.2 178.8-100.8 283.2-100.8 119.6 0 232.2 46.6 316.8 131.2 69.4 69.4 113.2 157.4 126.6 252.8h-130c-29.6-145.8-158.8-256-313.4-256z" />
 | 
			
		||||
<glyph unicode="󡀷" glyph-name="icon-reset" d="M460.8 499.2l-187.8 187.8c57.2 42.8 128 68.2 204.8 68.2 188.2 0 341.6-153.2 341.6-341.4s-153.2-341.2-341.4-341.2c-165 0-302.8 117.6-334.6 273h-138.4c14.2-101.8 61-195.6 135-269.6 90.2-90.2 210.4-140 338-140s247.6 49.8 338 140 140 210.4 140 338-49.8 247.6-140 338-210.4 140-338 140c-111.4 0-217-38-302-107.6l-176 175.6v-460.8h460.8z" />
 | 
			
		||||
<glyph unicode="󡀸" glyph-name="icon-x-in-circle" d="M512 960c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM832 256l-128-128-192 192-192-192-128 128 192 192-192 192 128 128 192-192 192 192 128-128-192-192 192-192z" />
 | 
			
		||||
<glyph unicode="󡀹" glyph-name="icon-brightness" d="M253.414 641.939l-155.172 116.384c-50.233-66.209-85.127-146.713-97.91-234.39l191.586-30.216c8.145 56.552 29.998 106.879 62.068 149.006zM191.98 402.283l-191.919-27.434c13.115-90.459 48.009-170.963 99.174-238.453l154.18 117.665c-31.476 41.347-53.309 91.675-61.231 146.504zM466.283 768.020l-27.434 191.919c-90.459-13.115-170.963-48.009-238.453-99.174l117.665-154.18c41.347 31.476 91.675 53.309 146.504 61.231zM822.323 861.758c-66.209 50.233-146.713 85.127-234.39 97.91l-30.216-191.586c56.552-8.145 106.879-29.998 149.006-62.068zM832.020 493.717l191.919 27.434c-13.115 90.459-48.009 170.963-99.174 238.453l-154.18-117.665c31.476-41.347 53.309-91.675 61.231-146.504zM201.677 34.242c66.209-50.233 146.713-85.127 234.39-97.91l30.216 191.586c-56.552 8.145-106.879 29.998-149.006 62.068zM770.586 254.061l155.131-116.343c50.233 66.209 85.127 146.713 97.91 234.39l-191.586 30.216c-8.125-56.564-29.966-106.906-62.028-149.049zM557.717 127.98l27.434-191.919c90.459 13.115 170.963 48.009 238.453 99.174l-117.665 154.18c-41.347-31.476-91.675-53.309-146.504-61.231zM770.586 448c0-142.813-115.773-258.586-258.586-258.586s-258.586 115.773-258.586 258.586c0 142.813 115.773 258.586 258.586 258.586s258.586-115.773 258.586-258.586z" />
 | 
			
		||||
<glyph unicode="󡁀" glyph-name="icon-contrast" d="M512 960c-282.78 0-512-229.24-512-512s229.22-512 512-512 512 229.24 512 512-229.22 512-512 512zM783.52 176.48c-69.111-69.481-164.785-112.481-270.502-112.481-0.358 0-0.716 0-1.074 0.001l0.055 768c212.070-0.010 383.982-171.929 383.982-384 0-106.034-42.977-202.031-112.462-271.52z" />
 | 
			
		||||
<glyph unicode="󡁁" glyph-name="icon-expand" d="M960 960c0 0 0 0 0 0h-320v-128h165.4l-210.6-210.8c-25-25-25-65.6 0-90.6 12.4-12.4 28.8-18.8 45.2-18.8s32.8 6.2 45.2 18.8l210.8 210.8v-165.4h128v384h-64zM896 154.6l-210.8 210.6c-25 25-65.6 25-90.6 0s-25-65.6 0-90.6l210.8-210.6h-165.4v-128h384v384h-128v-165.4zM218.6 832h165.4v128h-320c0 0 0 0 0 0h-64v-384h128v165.4l210.8-210.8c12.4-12.4 28.8-18.8 45.2-18.8s32.8 6.2 45.2 18.8c25 25 25 65.6 0 90.6l-210.6 210.8zM338.8 365.2l-210.8-210.6v165.4h-128v-384h384v128h-165.4l210.8 210.8c25 25 25 65.6 0 90.6-25.2 24.8-65.6 24.8-90.6-0.2z" />
 | 
			
		||||
<glyph unicode="󡁂" glyph-name="icon-list-view" d="M0 896h1024v-128h-1024v128zM0 640h1024v-128h-1024v128zM0 384h1024v-128h-1024v128zM0 128h1024v-128h-1024v128z" />
 | 
			
		||||
<glyph unicode="󡁃" glyph-name="icon-grid-snap-to" d="M382 130h448v448h-448v-448zM510 450h192v-192h-192v192zM-2 386h320v-64h-320v64zM894 386h128v-64h-128v64zM574 962h64v-320h-64v320zM574 66h64v-128h-64v128zM574 386h64v-64h-64v64z" />
 | 
			
		||||
<glyph unicode="󡁄" glyph-name="icon-grid-snap-no" d="M768 384h192v-64h-192v64zM256 384h192v-64h-192v64zM0 384h192v-64h-192v64zM640 448h-64v-64h-64v-64h64v-64h64v64h64v64h-64zM576 704h64v-192h-64v192zM576 960h64v-192h-64v192zM576 192h64v-192h-64v192z" />
 | 
			
		||||
<glyph unicode="󡁅" glyph-name="icon-frame-show" d="M0 896v-896h1024v896h-1024zM896 128h-768v640h768v-640zM192 704h384v-128h-384v128z" />
 | 
			
		||||
<glyph unicode="󡁆" glyph-name="icon-frame-hide" d="M128 770h420l104 128h-652v-802.4l128 157.4zM896 130h-420l-104-128h652v802.4l-128-157.4zM832 962l-832-1024h192l832 1024zM392 578l104 128h-304v-128z" />
 | 
			
		||||
<glyph unicode="󡁇" glyph-name="icon-import" d="M832 767.6v-639.4c0-0.2-0.2-0.2-0.4-0.4h-319.6v-192h320c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192h-320v-192h319.6c0.2 0 0.4-0.2 0.4-0.4zM192 256v-192l384 384-384 384v-192h-192v-384z" />
 | 
			
		||||
<glyph unicode="󡁈" glyph-name="icon-export" d="M192 128.34v639.32l0.34 0.34h319.66v192h-320c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h320v192h-319.66zM1024 448l-384 384v-192h-192v-384h192v-192l384 384z" />
 | 
			
		||||
<glyph unicode="󡄀" glyph-name="icon-activity" d="M576 896h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
 | 
			
		||||
<glyph unicode="󡄁" glyph-name="icon-activity-mode" d="M512 960c-214.866 0-398.786-132.372-474.744-320h90.744c56.86 0 107.938-24.724 143.094-64h240.906l-192 192h256l320-320-320-320h-256l192 192h-240.906c-35.156-39.276-86.234-64-143.094-64h-90.744c75.958-187.628 259.878-320 474.744-320 282.77 0 512 229.23 512 512s-229.23 512-512 512z" />
 | 
			
		||||
<glyph unicode="󡄂" glyph-name="icon-autoflow-tabular" d="M192 960c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 960h256v-1024h-256v1024zM832 960h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
 | 
			
		||||
<glyph unicode="󡄃" glyph-name="icon-clock" d="M512 960c-282.76 0-512-229.24-512-512s229.24-512 512-512 512 229.24 512 512-229.24 512-512 512zM782 270c-12.681-21.673-35.844-36-62.354-36-0.023 0-0.047 0-0.070 0-0.016 0-0.040 0-0.064 0-13.234 0-25.63 3.587-36.269 9.843l-221.644 127.977q-1.2 0.7-2.38 1.46l-0.86 0.56-1.86 1.28-1.26 0.9-1.26 0.96-1.7 1.34-0.64 0.54c-0.72 0.6-1.44 1.22-2.14 1.84v0c-5.012 4.562-9.331 9.758-12.863 15.491-0.457 0.769-0.717 1.249-0.997 1.709s-0.58 0.98-0.86 1.48c-3.092 5.53-5.561 11.936-7.071 18.704l-0.089 0.596c-0.2 0.92-0.38 1.84-0.54 2.76 0 0.28-0.1 0.56-0.16 0.84-0.12 0.7-0.22 1.42-0.3 2.14s-0.14 1.040-0.2 1.58-0.1 1.020-0.14 1.54-0.12 1.5-0.18 2.24c0 0.34 0 0.68 0 1.040q0 1.4 0 2.78c0 0.1 0 0.22 0 0.32v364.080c0 39.765 32.235 72 72 72s72-32.235 72-72v-322.44l185.7-107.22c21.605-12.697 35.879-35.823 35.879-62.284 0-13.278-3.594-25.716-9.862-36.395z" />
 | 
			
		||||
<glyph unicode="󡄄" glyph-name="icon-database" d="M1024 768c0-106.039-229.23-192-512-192s-512 85.961-512 192c0 106.039 229.23 192 512 192s512-85.961 512-192zM512 448c-282.77 0-512 85.962-512 192v-512c0-106.038 229.23-192 512-192s512 85.962 512 192v512c0-106.038-229.23-192-512-192z" />
 | 
			
		||||
<glyph unicode="󡄅" glyph-name="icon-database-query" d="M683.52 140.714c-50.782-28.456-109.284-44.714-171.52-44.714-194.094 0-352 157.906-352 352s157.906 352 352 352 352-157.906 352-352c0-62.236-16.258-120.738-44.714-171.52l191.692-191.692c8.516 13.89 13.022 28.354 13.022 43.212v640c0 106.038-229.23 192-512 192s-512-85.962-512-192v-640c0-106.038 229.23-192 512-192 126.11 0 241.548 17.108 330.776 45.46l-159.256 159.254zM352 448c0-88.224 71.776-160 160-160s160 71.776 160 160-71.776 160-160 160-160-71.776-160-160z" />
 | 
			
		||||
<glyph unicode="󡄆" glyph-name="icon-dataset" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128zM320 64h-128v320h128v-320zM576 64h-128v320h128v-320zM832 64h-128v320h128v-320z" />
 | 
			
		||||
<glyph unicode="󡄇" glyph-name="icon-datatable" d="M1024 768c0-106.039-229.23-192-512-192s-512 85.961-512 192c0 106.039 229.23 192 512 192s512-85.961 512-192zM512 448c-282.8 0-512 86-512 192v-512c0-106 229.2-192 512-192s512 86 512 192v512c0-106-229.2-192-512-192zM896 385v-256c-36.6-15.6-79.8-28.8-128-39.4v256c48.2 10.6 91.4 23.8 128 39.4zM256 345.6v-256c-48.2 10.4-91.4 23.8-128 39.4v256c36.6-15.6 79.8-28.8 128-39.4zM384 70v256c41-4 83.8-6 128-6s87 2.2 128 6v-256c-41-4-83.8-6-128-6s-87 2.2-128 6z" />
 | 
			
		||||
<glyph unicode="󡄈" glyph-name="icon-dictionary" d="M832 320c105.6 0 192 86.4 192 192v256c0 105.6-86.4 192-192 192v-320l-128 64-128-64v320h-384c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v192c0-105.6-86.4-192-192-192h-640v192h640z" />
 | 
			
		||||
<glyph unicode="󡄉" glyph-name="icon-folder" d="M896 768h-320c-16.4 16.4-96.8 96.8-109.2 109.2l-37.4 37.4c-25 25-74.2 45.4-109.4 45.4h-256c-35.2 0-64-28.8-64-64v-384c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v128c0 70.4-57.6 128-128 128zM896 512h-768c-70.4 0-128-57.6-128-128v-320c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v320c0 70.4-57.6 128-128 128z" />
 | 
			
		||||
<glyph unicode="󡄐" glyph-name="icon-image" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM896 64h-768v768h768v-768zM320 704l-128-128v-448h640v320l-128 128-128-128z" />
 | 
			
		||||
<glyph unicode="󡄑" glyph-name="icon-layout" d="M448 960h-256c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h256v1024zM832 960h-256v-577.664h448v385.664c0 105.6-86.4 192-192 192zM576-64h256c105.6 0 192 86.4 192 192v129.664h-448v-321.664z" />
 | 
			
		||||
<glyph unicode="󡄒" glyph-name="icon-object" d="M512-64l512 320v384l-512.020 320-511.98-320v-384l512-320zM512 768l358.4-224-358.4-224-358.4 224 358.4 224z" />
 | 
			
		||||
<glyph unicode="󡄓" glyph-name="icon-object-unknown" d="M510 962l-512-320v-384l512-320 512 320v384l-512 320zM585.4 100.8c-21.2-20.8-46-30.8-76-30.8-31.2 0-56.2 9.8-76.2 29.6-20 20-29.6 44.8-29.6 76.2 0 30.4 10.2 55.2 31 76.2s45.2 31.2 74.8 31.2c29.6 0 54.2-10.4 75.6-32s31.8-46.4 31.8-76c-0.2-29-10.8-54-31.4-74.4zM638.2 413.4c-23.6-11.8-37.4-22-43.4-32.4-3.6-6.2-6-14.8-7.4-26.8v-41h-161.4v44.2c0 40.2 4.4 69.8 13 88 8 17.2 22.6 30.2 44.8 40l34.8 15.4c32 14.2 48.2 35.2 48.2 62.8 0 16-6 30.4-17.2 41.8-11.2 11.2-25.6 17.2-41.6 17.2-24 0-54.4-10-62.8-57.4l-2.2-12.2h-147l1.4 16.2c4 44.6 17 82.4 38.8 112.2 19.6 27 45.6 48.6 77 64.6s64.6 24 98.2 24c60.6 0 110.2-19.4 151.4-59.6 41.2-40 61.2-88 61.2-147.2 0-70.8-28.8-121.4-85.8-149.8z" />
 | 
			
		||||
<glyph unicode="󡄔" glyph-name="icon-packet" d="M511.98 960l-511.98-320v-512c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v512l-512.020 320zM512 768l358.4-224-358.4-224-358.4 224 358.4 224z" />
 | 
			
		||||
<glyph unicode="󡄕" glyph-name="icon-page" d="M702 452c-105.6 0-192 86.4-192 192v320h-320c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v320h-320zM766 580h256l-384 384v-256c0-70.4 57.6-128 128-128z" />
 | 
			
		||||
<glyph unicode="󡄖" glyph-name="icon-plot-overlay" d="M830 960h-636c-106.7 0-194-87.3-194-194v-406.82c14.18-18.64 25.66-28.34 32-30.84 14.28 5.62 54.44 47.54 92.96 146 42.46 108.38 116.32 237.66 227.040 237.66 52.4 0 101.42-29.16 145.7-86.68 37.34-48.5 64.84-108.92 81.34-151.080 38.52-98.38 78.68-140.3 92.96-146 14.28 5.62 54.44 47.54 92.96 146 42.46 108.48 116.32 237.76 227.040 237.76 11.354-0.003 22.389-1.366 32.952-3.936l-0.952 57.936c0 106.7-87.3 194-194 194zM992 567.66c-14.28-5.62-54.44-47.52-92.96-146-42.46-108.38-116.32-237.66-227.040-237.66-52.4 0-101.42 29.16-145.7 86.68-37.34 48.5-64.84 108.92-81.34 151.080-38.52 98.38-78.68 140.3-92.96 146-14.28-5.62-54.44-47.52-92.96-146-42.46-108.48-116.32-237.76-227.040-237.76-11.355 0.003-22.389 1.367-32.952 3.936l0.952-57.936c0-106.7 87.3-194 194-194h636c106.7 0 194 87.3 194 194v406.82c-14.18 18.64-25.66 28.34-32 30.84z" />
 | 
			
		||||
<glyph unicode="󡄗" glyph-name="icon-plot-stacked" d="M89.6 648c24.98 0 48.96 26.52 85.52 70.18 45.42 54.28 102 121.82 196 121.82 44.64 0 86.62-15.46 124.8-46 28.68-22.9 51.16-50.42 72.92-77.060 38.42-46.94 59.16-68.94 83.96-68.94h371.2v118c0 106.7-87.3 194-194 194h-636c-106.7 0-194-87.3-194-194v-118h89.6zM529.5 549.6c-28.24 22.64-50.52 50-72 76.28-35.5 43.48-58.76 70.12-86.3 70.12-25.060 0-49.080-26.54-85.66-70.24-45.4-54.24-102-121.76-196-121.76h-89.54v-112h371.2c44 0 85.54-15.34 123.3-45.6 28.24-22.64 50.52-50 72-76.28 35.5-43.48 58.76-70.12 86.3-70.12 25.060 0 49.080 26.54 85.66 70.24 45.4 54.24 102 121.76 196 121.76h89.54v112h-371.2c-44.060 0-85.54 15.34-123.3 45.6zM934.4 248c-24.98 0-48.96-26.52-85.52-70.18-45.42-54.28-102-121.82-196-121.82-44.64 0-86.62 15.46-124.8 46-28.68 22.9-51.16 50.42-72.92 77.060-38.42 46.94-59.16 68.94-83.96 68.94h-371.2v-118c0-106.7 87.3-194 194-194h636c106.7 0 194 87.3 194 194v118h-89.6z" />
 | 
			
		||||
<glyph unicode="󡄘" glyph-name="icon-session" d="M635.6 435.6c6.6-4.2 13.2-8.6 19.2-13.6l120.4-96.4c29.6-23.8 83.8-23.8 113.4 0l135.2 108c0.2 4.8 0.2 9.4 0.2 14.2 0 52.2-7.8 102.4-22.2 149.8l-154.8-123.6c-58.2-46.6-140.2-59.2-211.4-38.4zM248.6 325.8l120.4 96.4c58 46.4 140 59.2 211.2 38.4-6.6 4.2-13.2 8.6-19.2 13.6l-120.4 96.4c-29.6 23.8-83.8 23.8-113.4 0l-120.2-96.6c-40-32-91.4-48-143-48-21.6 0-43 2.8-63.8 8.4 0-0.6 0-1.2 0-1.6 5-3.4 10-6.8 14.6-10.6l120.4-96.4c29.8-23.8 83.8-23.8 113.4 0zM120.6 581.8l120.4 96.4c80.2 64.2 205.6 64.2 285.8 0l120.4-96.4c29.6-23.8 83.8-23.8 113.4 0l181 144.8c-91.2 140.4-249.6 233.4-429.6 233.4-238.6 0-439.2-163.2-496-384.2 30.8-17.6 77.8-15.6 104.6 6zM689 218l-120.4 96.4c-29.6 23.8-83.8 23.8-113.4 0l-120.2-96.4c-40-32-91.4-48-143-48-47.8 0-95.4 13.8-134.2 41.4 85.6-163.6 256.8-275.4 454.2-275.4s368.6 111.8 454.2 275.4c-80.4-57.4-199.8-55.2-277.2 6.6z" />
 | 
			
		||||
<glyph unicode="󡄙" glyph-name="icon-tabular" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM640 512h-256v192h256v-192zM384 448h256v-192h-256v192zM320 256h-256v192h256v-192zM320 704v-192h-256v192h256zM128 0c-17 0-33 6.6-45.2 18.8s-18.8 28.2-18.8 45.2v128h256v-192h-192zM384 0v192h256v-192h-256zM960 64c0-17-6.6-33-18.8-45.2s-28.2-18.8-45.2-18.8h-192v192h256v-128zM960 256h-256v192h256v-192zM960 512h-256v192h256v-192z" />
 | 
			
		||||
<glyph unicode="󡄠" glyph-name="icon-tabular-lad" d="M896 960h-768c-70.606-0.215-127.785-57.394-128-127.979v-768.021c0.215-70.606 57.394-127.785 127.979-128h768.021c70.606 0.215 127.785 57.394 128 127.979v768.021c-0.215 70.606-57.394 127.785-127.979 128zM64 704h256v-192h-256v192zM64 448h256v-192h-256v192zM128 0c-35.26 0.214-63.786 28.74-64 63.98v128.020h256v-192h-192zM384 0v192h256v-192h-256zM960 64c-0.214-35.26-28.74-63.786-63.98-64h-192.020v192h256v-128zM960 448v-192h-576v192h64v64h-64v192h576v-192h-64v-64h64zM782.32 412.62l-110.32 55.16v172.22c0 17.673-14.327 32-32 32s-32-14.327-32-32v-211.78l145.68-72.84c4.172-2.133 9.1-3.383 14.32-3.383 17.675 0 32.003 14.328 32.003 32.003 0 12.454-7.114 23.247-17.501 28.536z" />
 | 
			
		||||
<glyph unicode="󡄡" glyph-name="icon-tabular-lad-set" d="M128 192v576c-70.606-0.215-127.785-57.394-128-127.979v-576.021c0.215-70.606 57.394-127.785 127.979-128h576.021c70.606 0.215 127.785 57.394 128 127.979l-576 0.021c-70.606 0.215-127.785 57.394-128 127.979zM896 960h-576c-70.606-0.215-127.785-57.394-128-127.979v-576.021c0.215-70.606 57.394-127.785 127.979-128h576.021c70.606 0.215 127.785 57.394 128 127.979v576.021c-0.215 70.606-57.394 127.785-127.979 128zM256 768h192v-128h-192v128zM256 576h192v-192h-192v192zM320 192c-35.26 0.214-63.786 28.74-64 63.98v64.020h192v-128h-128zM512 192v128h192v-128h-192zM960 256c-0.214-35.26-28.74-63.786-63.98-64h-128.020v128h192v-64zM960 384h-448v384h448v-384zM832 480c0.002 0 0.005 0 0.007 0 17.673 0 32 14.327 32 32 0 14.055-9.062 25.994-21.662 30.293l-74.345 24.767v104.94c0 17.673-14.327 32-32 32s-32-14.327-32-32v-151.060l117.88-39.3c3.018-1.040 6.495-1.64 10.113-1.64 0.003 0 0.005 0 0.008 0z" />
 | 
			
		||||
<glyph unicode="󡄢" glyph-name="icon-tabular-realtime" d="M896 960h-768c-70.606-0.215-127.785-57.394-128-127.979v-768.021c0.215-70.606 57.394-127.785 127.979-128h768.021c70.606 0.215 127.785 57.394 128 127.979v768.021c-0.215 70.606-57.394 127.785-127.979 128zM448 668l25.060-25.32c7.916-7.922 18.856-12.822 30.94-12.822s23.024 4.9 30.94 12.822l75.5 76.3c29.97 30.338 71.571 49.128 117.56 49.128s87.59-18.79 117.544-49.112l50.456-50.997v-152.2c-24.111 8.83-44.678 22.255-61.542 39.342l-75.518 76.318c-7.916 7.922-18.856 12.822-30.94 12.822s-23.024-4.9-30.94-12.822l-75.5-76.3c-29.971-30.343-71.575-49.137-117.568-49.137-20.084 0-39.331 3.584-57.137 10.146l1.145 151.831zM320 0h-192c-35.26 0.214-63.786 28.74-64 63.98v128.020h256v-192zM320 256h-256v192h256v-192zM320 512h-256v192h256v-192zM640 0h-256v192h256v-192zM448 323.38v174.5c1.88-1.74 3.74-3.5 5.56-5.34l75.5-76.3c7.916-7.922 18.856-12.822 30.94-12.822s23.024 4.9 30.94 12.822l75.5 76.3c29.966 30.333 71.56 49.119 117.542 49.119 43.28 0 82.673-16.644 112.128-43.879l-0.11-174.399c-1.88 1.74-3.74 3.5-5.56 5.34l-75.5 76.3c-7.916 7.922-18.856 12.822-30.94 12.822s-23.024-4.9-30.94-12.822l-75.5-76.3c-29.966-30.333-71.56-49.119-117.542-49.119-43.28 0-82.673 16.644-112.128 43.879zM960 64c-0.214-35.26-28.74-63.786-63.98-64h-192.020v192h256v-128z" />
 | 
			
		||||
<glyph unicode="󡄣" glyph-name="icon-tabular-scrolling" d="M64 960c-35.2 0-64-28.8-64-64v-192h448v256h-384zM1024 704v192c0 35.2-28.8 64-64 64h-384v-256h448zM0 576v-192c0-35.2 28.8-64 64-64h384v256h-448zM960 320c35.2 0 64 28.8 64 64v192h-448v-256h384zM512-64l-256 256h512z" />
 | 
			
		||||
<glyph unicode="󡄤" glyph-name="icon-telemetry" d="M32 328.34c14.28 5.62 54.44 47.54 92.96 146 42.46 108.38 116.32 237.66 227.040 237.66 52.4 0 101.42-29.16 145.7-86.68 37.34-48.5 64.84-108.92 81.34-151.080 38.52-98.38 78.68-140.3 92.96-146 14.28 5.62 54.44 47.54 92.96 146 37.4 95.5 99.14 207.14 188.94 232.46-90.462 152.598-254.314 253.3-441.686 253.3-0.075 0-0.15 0-0.226 0-282.748 0-511.988-229.24-511.988-512 0-0.032 0-0.070 0-0.108 0-35.719 3.641-70.587 10.572-104.255 8.968-7.457 16.648-13.417 21.428-15.297zM992 567.66c-14.28-5.62-54.44-47.52-92.96-146-42.46-108.38-116.32-237.66-227.040-237.66-52.4 0-101.42 29.16-145.7 86.68-37.34 48.5-64.84 108.92-81.34 151.080-38.52 98.38-78.68 140.3-92.96 146-14.28-5.62-54.44-47.52-92.96-146-37.4-95.5-99.14-207.14-188.94-232.46 90.462-152.598 254.314-253.3 441.686-253.3 0.075 0 0.15 0 0.226 0 282.748 0 511.988 229.24 511.988 512 0 0.032 0 0.070 0 0.108 0 35.719-3.641 70.587-10.572 104.255-8.968 7.457-16.648 13.417-21.428 15.297z" />
 | 
			
		||||
<glyph unicode="󡄥" glyph-name="icon-telemetry-panel" d="M169.2 512c14 56.4 33 122 56.6 176.8 15.4 35.8 31.2 63.2 48.2 84 18.4 22.4 49 49.2 91 49.2s72.6-26.8 91-49.2c17-20.6 32.6-48.2 48.2-84 23.6-54.8 42.8-120.4 56.6-176.8h461.2v256c0 105.6-86.4 192-192 192h-640c-105.6 0-192-86.4-192-192v-256h171.2zM718.6 384h-127.2c25-93.4 48.4-144.4 63.6-168.6 15.2 24.2 38.6 75.2 63.6 168.6zM301.4 512h127.2c-25 93.4-48.4 144.4-63.6 168.6-15.2-24.2-38.6-75.2-63.6-168.6zM850.8 384c-14-56.4-33-122-56.6-176.8-15.4-35.8-31.2-63.2-48.2-84-18.4-22.4-49-49.2-91-49.2s-72.6 26.8-91 49.2c-17 20.6-32.6 48.2-48.2 84-23.6 54.8-42.8 120.4-56.6 176.8h-461.2v-256c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v256h-171.2z" />
 | 
			
		||||
<glyph unicode="󡄦" glyph-name="icon-timeline" d="M256 704h384v-128h-384v128zM384 512h384v-128h-384v128zM320 320h384v-128h-384v128zM832 960h-128v-192h127.6c0.2 0 0.2-0.2 0.4-0.4v-639.4c0-0.2-0.2-0.2-0.4-0.4h-127.6v-192h128c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192zM192 128.4v639.2c0 0.2 0.2 0.2 0.4 0.4h127.6v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192h-127.6c-0.2 0-0.4 0.2-0.4 0.4z" />
 | 
			
		||||
<glyph unicode="󡄧" glyph-name="icon-timer-v1.5" horiz-adv-x="896" d="M576 813.4v82.58c0 35.346-28.654 64-64 64h-128c-35.346 0-64-28.654-64-64v-82.58c-185.040-55.080-320-226.48-320-429.42 0-247.42 200.58-448 448-448s448 200.58 448 448c0 202.96-135 374.4-320 429.42zM468 363.98l-263.76-211c-57.105 59.935-92.24 141.251-92.24 230.772 0 0.080 0 0.16 0 0.24 0 185.268 150.72 335.988 336 335.988 6.72 0 13.38-0.22 20-0.62v-355.38z" />
 | 
			
		||||
<glyph unicode="󡄨" glyph-name="icon-topic" d="M454.36 483.36l86.3 86.3c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c19.328-19.358 42.832-34.541 69.047-44.082l1.313 171.722-57.64 57.64c-34.407 34.33-81.9 55.558-134.35 55.558s-99.943-21.228-134.354-55.562l-86.296-86.297c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-28.674 28.654v-172.14c19.045-7.022 41.040-11.084 63.984-11.084 52.463 0 99.966 21.239 134.379 55.587zM505.64 412.64l-86.3-86.3c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-86.294 86.294c-2 2-4.2 4-6.36 6v-197.36c33.664-30.72 78.65-49.537 128.031-49.537 52.44 0 99.923 21.22 134.333 55.541l86.296 86.296c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c2-2 4.2-4 6.36-6v197.36c-33.664 30.72-78.65 49.537-128.031 49.537-52.44 0-99.923-21.22-134.333-55.541zM832 960h-128v-192h127.66l0.34-0.34v-639.32l-0.34-0.34h-127.66v-192h128c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM320 128h-127.66l-0.34 0.34v639.32l0.34 0.34h127.66v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192z" />
 | 
			
		||||
<glyph unicode="󡄩" glyph-name="icon-box-with-dashed-lines" d="M0 576h128v-256h-128v256zM128 831.78l0.22 0.22h191.78v128h-192c-70.606-0.215-127.785-57.394-128-127.979v-192.021h128v191.78zM128 64.22v191.78h-128v-192c0.215-70.606 57.394-127.785 127.979-128h192.021v128h-191.78zM384 960h256v-128h-256v128zM896 64.22l-0.22-0.22h-191.78v-128h192c70.606 0.215 127.785 57.394 128 127.979v192.021h-128v-191.78zM896 960h-192v-128h191.78l0.22-0.22v-191.78h128v192c-0.215 70.606-57.394 127.785-127.979 128zM896 576h128v-256h-128v256zM384 64h256v-128h-256v128zM256 704h512v-512h-512v512z" />
 | 
			
		||||
<glyph unicode="󡄰" glyph-name="icon-summary-widget" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM847.8 349.6l-82.6-143.2-189.6 131.6 19.2-230h-165.4l19.2 230-189.6-131.6-82.6 143.2 208.6 98.4-208.8 98.4 82.6 143.2 189.6-131.6-19.2 230h165.4l-19.2-230 189.6 131.6 82.6-143.2-208.6-98.4 208.8-98.4z" />
 | 
			
		||||
<glyph unicode="󡄱" glyph-name="icon-notebook" d="M896 849.2c0 79.8-55.4 127.4-123 105.4l-773-250.6h896v145.2zM896 640h-896v-576c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v448c0 70.4-57.6 128-128 128zM832 128h-384v320h384v-320z" />
 | 
			
		||||
</font></defs></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 44 KiB  | 
| 
		 Before Width: | Height: | Size: 119 KiB  | 
| 
		 Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 348 B  | 
| 
		 Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 628 B  | 
| 
		 Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 1.6 KiB  | 
| 
		 Before Width: | Height: | Size: 15 KiB  | 
@@ -1,24 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
			
		||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
			
		||||
	 viewBox="20 0 640 150" enable-background="new 20 0 640 150" xml:space="preserve">
 | 
			
		||||
<g>
 | 
			
		||||
	<path fill="#FFFFFF" d="M90.7,13.2c14.8,0,22.8,8,22.8,22.8v46.3c0,14.8-8,22.8-22.8,22.8H62.8c-14.8,0-22.8-8-22.8-22.8V36
 | 
			
		||||
		c0-14.8,8-22.8,22.8-22.8H90.7z M97.8,36.2c0-5.8-3.1-9.2-9.2-9.2h-24c-5.8,0-9.2,3.2-9.2,9.2v45.9c0,6,3.4,9.2,9.2,9.2h24
 | 
			
		||||
		c6,0,9.2-3.2,9.2-9.2V36.2z"/>
 | 
			
		||||
	<path fill="#FFFFFF" d="M173.2,13.2c14.8,0,22.8,8,22.8,22.8v46.3c0,14.8-8,22.8-22.8,22.8h-9c-11.2,0-19.2-6.6-26.5-13.6v44.2
 | 
			
		||||
		h-15.5V13.2h15.5v13.6c7.3-7,15.3-13.6,26.5-13.6H173.2z M180.3,36.2c0-5.8-3.1-9.2-9.2-9.2h-8.3c-9.4,0-17,3.6-25.2,9.2v45.9
 | 
			
		||||
		c8.2,5.6,15.8,9.2,25.2,9.2h8.3c6.1,0,9.2-3.4,9.2-9.2V36.2z"/>
 | 
			
		||||
	<path fill="#FFFFFF" d="M220.3,82.8c0,6,3.2,9.2,9.2,9.2h23c6,0,9.2-3.4,9.2-9.2V76h15.6v6.3c0,14.8-8,22.8-22.8,22.8h-27
 | 
			
		||||
		c-14.8,0-22.8-8-22.8-22.8V36c0-14.8,8-22.8,22.8-22.8h27c14.8,0,22.8,8,22.8,22.8v26.9h-57V82.8z M229.5,26.3
 | 
			
		||||
		c-6,0-9.2,3.2-9.2,9.2v15.8h41.3V35.5c0-6-3.1-9.2-9.2-9.2H229.5z"/>
 | 
			
		||||
	<path fill="#FFFFFF" d="M285.7,13.2h15.5v13.6c7.3-7,15.3-13.6,26.5-13.6h7.1c14.8,0,22.8,8,22.8,22.8v69.1h-15.5V36.6
 | 
			
		||||
		c0-6-3.2-9.2-9.2-9.2h-6.6c-9.4,0-17,3.4-25.2,9.2v68.5h-15.5V13.2z"/>
 | 
			
		||||
	<path fill="#4F79F7" d="M495.4,105.1c-12.5,0-18.4-6-18.4-18.4V28.7c0-12.5,6.2-18.4,18.7-18.4h42.2c12.5,0,18.1,6,18.1,18.4v17.7
 | 
			
		||||
		h-25.4V33.9c0-1.9-0.5-2.4-2.4-2.4h-23.3c-1.9,0-2.4,0.5-2.4,2.4v47.6c0,1.9,0.5,2.4,2.4,2.4h23.3c1.9,0,2.4-0.5,2.4-2.4V69H556
 | 
			
		||||
		v17.7c0,12.5-6,18.4-18.4,18.4H495.4z"/>
 | 
			
		||||
	<path fill="#4F79F7" d="M613.7,32v73.1h-25.4V32H562V10.3h78V32H613.7z"/>
 | 
			
		||||
	<path fill="#4F79F7" d="M425.3,93.6l17.4-42.4v48.6c0,3,2.4,5.4,5.4,5.4h19V15.7c0-3-2.4-5.4-5.4-5.4h-23.3l-21.2,49.4l-21.2-49.4
 | 
			
		||||
		h-23.3c-3,0-5.4,2.4-5.4,5.4v89.5h19c3,0,5.4-2.4,5.4-5.4V51.2l17.4,42.4H425.3z"/>
 | 
			
		||||
</g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 2.0 KiB  | 
@@ -1,159 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!-- Generator: Adobe Illustrator 17.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
			
		||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 | 
			
		||||
<svg version="1.1" id="NASA_insignia_color" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
	 x="0px" y="0px" width="318px" height="260px" viewBox="0 0 318 260" enable-background="new 0 0 318 260" xml:space="preserve">
 | 
			
		||||
<path fill="#0B3D91" d="M275.948,130.19c0,69.085-56.915,125.944-126.068,125.944S23.811,199.275,23.811,130.19
 | 
			
		||||
	c0-69.086,56.915-125.944,126.068-125.944S275.948,61.104,275.948,130.19z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M178.316,196.477c53.713,22.095,44.551-33.774,15.798-76.703c-16.269-24.291-37.487-44.525-50.87-54.292
 | 
			
		||||
	c-44.55-32.512-71.723-12.626-40.443,51.136c10.133,20.655,23.146,34.595,33.313,47.733c7.762,10.03,22.884,15.054,17.557,19.815
 | 
			
		||||
	c-6.004,5.366-20.538-18.308-20.538-18.308c-10.742-12.941-20.972-26.762-31.516-45.711C77.525,76.845,81,32.654,124.603,51.909
 | 
			
		||||
	c37.008,16.343,72.355,62.183,86.571,94.737c6.587,15.086,24.332,74.451-32.542,50.463"/>
 | 
			
		||||
<path fill="#FC3D21" d="M10.826,167.524c23.697-15.783,46.161-25.971,84.393-38.597c53.718-17.741,94.156-29.671,143.763-54.607
 | 
			
		||||
	c24.158-12.144,59.858-35.653,74.25-58.396c-4.121,8.423-16.642,25.26-22.434,32.512C223.499,132.715,80.125,127.94,11.77,168.405"
 | 
			
		||||
	/>
 | 
			
		||||
<path fill="#FFFFFF" d="M45.201,105.929c21.582,0.167,19.56-0.044,19.812,0.209c0.379,0,17.315,29.166,17.315,29.418
 | 
			
		||||
	c0,0.127-0.126-10.365-0.126-23.484c0-1.515-4.171-5.935-4.045-5.935c6.191,0,14.282,0.126,14.282,0.126
 | 
			
		||||
	c-3.033,3.535-3.639,3.245-3.665,5.429c-0.084,7.028-0.166,20.012,0,34.595c0.025,2.186,1.643,3.03,4.297,6.818H73.228
 | 
			
		||||
	c-6.446-10.732-18.256-30.865-18.2-30.808c0.092,0.092-0.252,12.626,0.127,22.726c0.125,3.337,1.643,4.419,4.424,7.45
 | 
			
		||||
	c0,0,3.202-0.085-15.545,0.125c5.687-3.029,4.931-6.817,4.929-6.943c-0.205-13.952-0.042-25.884-0.042-33.586
 | 
			
		||||
	c0-1.263-0.084-1.137-4.002-5.935"/>
 | 
			
		||||
<g>
 | 
			
		||||
	<path fill="#FFFFFF" d="M112.971,127.475c1.818-6.321,3.375-11.973,4.112-15.656c0.126-0.631-1.39-2.904-3.792-5.176l-0.169-0.353
 | 
			
		||||
		c11.58,0.038,23.677,0.1,23.677,0.1c3.16,7.702,10.363,29.292,15.798,42.549c1.437,3.505,3.918,4.167,3.918,4.167
 | 
			
		||||
		c-9.858-0.127-28.152-0.042-28.058-0.127c4.929-4.418,4.297-4.418,2.148-10.857h-15.419c-3.16,7.322,0.985,10.759,1.517,10.731
 | 
			
		||||
		c-3.51,0.181-15.419,0-15.419,0c6.445-4.546,6.066-5.935,6.066-5.935C109.122,140.62,111.175,133.721,112.971,127.475l6.324,0.001
 | 
			
		||||
		c-1.358,4.357-2.717,8.712-2.717,8.712h12.259l-6.825-17.424c0,0-1.358,4.356-2.717,8.711L112.971,127.475z"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<path fill="#FFFFFF" d="M218.881,128.106c1.818-6.321,3.375-11.973,4.112-15.655c0.126-0.632-1.391-2.904-3.791-5.177l-0.169-0.353
 | 
			
		||||
		c11.58,0.038,23.676,0.1,23.676,0.1c3.16,7.702,10.364,29.292,15.798,42.55c1.437,3.505,3.919,4.166,3.919,4.166
 | 
			
		||||
		c-9.858-0.126-28.152-0.041-28.058-0.126c4.929-4.419,4.297-4.419,2.148-10.858h-15.419c-3.16,7.322,0.985,10.76,1.517,10.732
 | 
			
		||||
		c-3.511,0.18-15.419,0-15.419,0c6.445-4.546,6.066-5.935,6.066-5.935C215.032,141.252,217.085,134.353,218.881,128.106l6.324,0
 | 
			
		||||
		c-1.359,4.356-2.717,8.712-2.717,8.712h12.259l-6.824-17.424c0,0-1.359,4.356-2.718,8.712L218.881,128.106z"/>
 | 
			
		||||
</g>
 | 
			
		||||
<path fill="#FFFFFF" d="M198.98,117.753c-0.253-8.964,0-11.869,0-11.869c-3.918,3.157-1.939,2.756-11.754,1.136
 | 
			
		||||
	c-28.311-4.671-30.459,21.717-15.04,27.652c12.918,4.971,17.49,5.943,15.545,10.605c-0.632,1.515-12.386,7.07-24.518-4.167
 | 
			
		||||
	l0.254,15.657c1.516-1.562,5.688-4.42,5.688-4.42c0.125,0,13.147,5.739,24.897-0.252c18.072-9.217,9.051-24.133-10.237-30.05
 | 
			
		||||
	c-16.051-4.924-0.885-16.414,15.039-4.167"/>
 | 
			
		||||
<path fill="#FC3D21" d="M313.486,16.375c-19.213,56.998-96.179,101.005-160.969,143.028
 | 
			
		||||
	c-39.086,25.352-77.893,54.537-104.606,79.367c-7.044,6.547,1.436-2.449-1.264,0.316c37.283-42.93,80.167-68.494,103.864-84.592
 | 
			
		||||
	c40.082-27.229,62.877-34.09,132.019-97.784"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M178.316,196.477c53.713,22.095,44.551-33.774,15.798-76.703c-16.269-24.291-36.335-43.56-50.87-54.292
 | 
			
		||||
	c-16.976-12.535-18.642-13.573-18.642-13.573c37.916,17.992,72.355,62.183,86.571,94.737c6.587,15.086,24.332,74.451-32.542,50.463"
 | 
			
		||||
	/>
 | 
			
		||||
<path fill="#FFFFFF" d="M151.617,15.688c0,0.562-0.463,1.025-1.026,1.025c-0.563,0-1.026-0.463-1.026-1.025
 | 
			
		||||
	c0-0.563,0.463-1.026,1.026-1.026C151.154,14.662,151.617,15.125,151.617,15.688z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M158.727,31.233c0,0.693-0.57,1.263-1.264,1.263s-1.264-0.57-1.264-1.263c0-0.692,0.57-1.262,1.264-1.262
 | 
			
		||||
	S158.727,30.541,158.727,31.233z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M177.21,56.644c0,0.692-0.57,1.263-1.263,1.263c-0.694,0-1.264-0.57-1.264-1.263
 | 
			
		||||
	c0-0.693,0.569-1.263,1.264-1.263C176.64,55.381,177.21,55.951,177.21,56.644z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M147.51,39.993c0,0.563-0.463,1.026-1.026,1.026c-0.564,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.562,0.463-1.025,1.027-1.025C147.047,38.967,147.51,39.43,147.51,39.993z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M158.568,45.833c0,0.562-0.463,1.026-1.026,1.026c-0.564,0-1.026-0.463-1.026-1.026
 | 
			
		||||
	c0-0.563,0.463-1.026,1.026-1.026C158.105,44.807,158.568,45.27,158.568,45.833z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M144.193,29.498c0,0.692-0.571,1.263-1.264,1.263c-0.693,0-1.264-0.57-1.264-1.263
 | 
			
		||||
	c0-0.693,0.57-1.263,1.264-1.263C143.622,28.235,144.193,28.805,144.193,29.498z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M127.447,39.677c0,0.562-0.463,1.026-1.027,1.026s-1.027-0.463-1.027-1.026s0.463-1.026,1.027-1.026
 | 
			
		||||
	S127.447,39.115,127.447,39.677z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M130.448,41.729c0,0.562-0.463,1.026-1.027,1.026c-0.563,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.563,0.464-1.026,1.027-1.026C129.985,40.703,130.448,41.166,130.448,41.729z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M133.45,43.781c0,0.562-0.464,1.026-1.027,1.026c-0.563,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.563,0.463-1.026,1.027-1.026C132.986,42.755,133.45,43.218,133.45,43.781z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M128.869,47.726c0,0.563-0.464,1.026-1.027,1.026c-0.563,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.562,0.463-1.025,1.027-1.025C128.405,46.701,128.869,47.164,128.869,47.726z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M105.014,64.456c0,0.563-0.464,1.026-1.027,1.026c-0.563,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.562,0.464-1.025,1.027-1.025C104.55,63.43,105.014,63.893,105.014,64.456z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M109.437,69.822c0,0.563-0.463,1.026-1.027,1.026c-0.563,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.562,0.463-1.026,1.027-1.026C108.974,68.796,109.437,69.259,109.437,69.822z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M105.961,156.468c0,0.562-0.463,1.025-1.027,1.025c-0.563,0-1.027-0.463-1.027-1.025
 | 
			
		||||
	s0.463-1.025,1.027-1.025C105.498,155.442,105.961,155.905,105.961,156.468z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M106.593,180.378c0,0.693-0.57,1.264-1.264,1.264c-0.693,0-1.264-0.57-1.264-1.264
 | 
			
		||||
	c0-0.691,0.571-1.262,1.264-1.262C106.023,179.116,106.593,179.687,106.593,180.378z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M93.007,192.61c0,0.562-0.463,1.025-1.027,1.025c-0.563,0-1.027-0.463-1.027-1.025s0.464-1.026,1.027-1.026
 | 
			
		||||
	C92.543,191.584,93.007,192.048,93.007,192.61z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M76.735,197.581c0,0.693-0.571,1.263-1.264,1.263c-0.693,0-1.264-0.569-1.264-1.263
 | 
			
		||||
	c0-0.692,0.57-1.262,1.264-1.262C76.165,196.319,76.735,196.889,76.735,197.581z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M73.417,186.534c0,0.691-0.571,1.262-1.264,1.262c-0.693,0-1.264-0.57-1.264-1.262
 | 
			
		||||
	c0-0.693,0.571-1.264,1.264-1.264C72.847,185.27,73.417,185.841,73.417,186.534z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M71.521,193.557c0,0.563-0.463,1.026-1.027,1.026c-0.563,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.562,0.464-1.026,1.027-1.026C71.058,192.53,71.521,192.994,71.521,193.557z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M59.357,187.718c0,0.562-0.464,1.025-1.027,1.025c-0.563,0-1.027-0.463-1.027-1.025s0.464-1.026,1.027-1.026
 | 
			
		||||
	C58.894,186.691,59.357,187.155,59.357,187.718z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M101.854,207.445c0,0.563-0.463,1.026-1.027,1.026c-0.563,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.562,0.463-1.026,1.027-1.026C101.391,206.419,101.854,206.883,101.854,207.445z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M114.65,198.055c0,0.692-0.571,1.263-1.264,1.263c-0.693,0-1.264-0.57-1.264-1.263
 | 
			
		||||
	c0-0.692,0.571-1.263,1.264-1.263C114.08,196.792,114.65,197.362,114.65,198.055z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M116.072,210.128c0,0.562-0.464,1.027-1.027,1.027c-0.563,0-1.027-0.465-1.027-1.027
 | 
			
		||||
	s0.463-1.025,1.027-1.025C115.608,209.103,116.072,209.565,116.072,210.128z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M168.68,198.606c0,0.563-0.463,1.027-1.027,1.027c-0.562,0-1.026-0.464-1.026-1.027
 | 
			
		||||
	c0-0.562,0.464-1.025,1.026-1.025C168.217,197.581,168.68,198.044,168.68,198.606z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M144.193,207.288c0,0.562-0.464,1.025-1.027,1.025c-0.564,0-1.027-0.463-1.027-1.025
 | 
			
		||||
	s0.464-1.026,1.027-1.026C143.729,206.262,144.193,206.726,144.193,207.288z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M210.07,219.755c0,0.562-0.464,1.027-1.026,1.027c-0.563,0-1.027-0.465-1.027-1.027s0.464-1.025,1.027-1.025
 | 
			
		||||
	C209.606,218.729,210.07,219.192,210.07,219.755z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M215.441,171.225c0,0.692-0.57,1.263-1.264,1.263c-0.692,0-1.264-0.57-1.264-1.263
 | 
			
		||||
	c0-0.692,0.571-1.263,1.264-1.263C214.871,169.962,215.441,170.532,215.441,171.225z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M205.331,178.09c0,0.563-0.463,1.026-1.026,1.026c-0.564,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.562,0.463-1.026,1.027-1.026C204.868,177.063,205.331,177.527,205.331,178.09z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M215.283,180.062c0,0.692-0.569,1.263-1.264,1.263c-0.692,0-1.264-0.57-1.264-1.263s0.571-1.263,1.264-1.263
 | 
			
		||||
	C214.714,178.8,215.283,179.37,215.283,180.062z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M205.331,192.294c0,0.562-0.463,1.025-1.026,1.025c-0.564,0-1.027-0.463-1.027-1.025
 | 
			
		||||
	s0.463-1.025,1.027-1.025C204.868,191.269,205.331,191.731,205.331,192.294z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M231.082,164.358c0,0.563-0.464,1.027-1.026,1.027c-0.564,0-1.027-0.464-1.027-1.027
 | 
			
		||||
	c0-0.562,0.464-1.025,1.027-1.025C230.618,163.333,231.082,163.796,231.082,164.358z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M233.609,170.593c0,0.693-0.57,1.264-1.264,1.264s-1.264-0.57-1.264-1.264c0-0.692,0.57-1.262,1.264-1.262
 | 
			
		||||
	S233.609,169.9,233.609,170.593z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M251.303,178.011c0,0.693-0.57,1.263-1.263,1.263c-0.694,0-1.264-0.569-1.264-1.263
 | 
			
		||||
	c0-0.692,0.569-1.262,1.264-1.262C250.732,176.749,251.303,177.318,251.303,178.011z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M233.294,191.189c0,0.562-0.464,1.026-1.027,1.026c-0.563,0-1.027-0.464-1.027-1.026
 | 
			
		||||
	s0.464-1.026,1.027-1.026C232.83,190.163,233.294,190.627,233.294,191.189z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M244.668,180.458c0,0.562-0.463,1.025-1.026,1.025c-0.563,0-1.027-0.463-1.027-1.025
 | 
			
		||||
	c0-0.563,0.464-1.026,1.027-1.026C244.205,179.432,244.668,179.895,244.668,180.458z"/>
 | 
			
		||||
<path fill="#FFFFFF" d="M242.614,197.028c0,0.564-0.463,1.026-1.026,1.026c-0.564,0-1.027-0.463-1.027-1.026
 | 
			
		||||
	c0-0.562,0.464-1.025,1.027-1.025C242.151,196.003,242.614,196.466,242.614,197.028z"/>
 | 
			
		||||
<g>
 | 
			
		||||
	<path fill="#FFFFFF" d="M247.394,169.488c0,0.866-0.713,1.579-1.58,1.579c-0.866,0-1.579-0.713-1.579-1.579
 | 
			
		||||
		s0.713-1.578,1.579-1.578C246.681,167.91,247.394,168.622,247.394,169.488z"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<polygon fill="#FFFFFF" points="245.813,164.675 245.34,169.015 241.035,169.488 245.379,169.962 245.852,174.46 246.327,169.962 
 | 
			
		||||
		250.592,169.409 246.287,169.015 	"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<path fill="#FFFFFF" d="M236.335,196.95c0,0.865-0.713,1.578-1.58,1.578c-0.866,0-1.579-0.713-1.579-1.578
 | 
			
		||||
		c0-0.865,0.713-1.578,1.579-1.578C235.622,195.372,236.335,196.085,236.335,196.95z"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<polygon fill="#FFFFFF" points="234.755,192.136 234.281,196.477 229.977,196.95 234.32,197.423 234.794,201.921 235.269,197.423 
 | 
			
		||||
		239.533,196.871 235.228,196.477 	"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<path fill="#FFFFFF" d="M118.481,66.587c0,0.866-0.713,1.578-1.58,1.578c-0.866,0-1.58-0.712-1.58-1.578
 | 
			
		||||
		c0-0.866,0.713-1.578,1.58-1.578C117.768,65.008,118.481,65.721,118.481,66.587z"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<polygon fill="#FFFFFF" points="116.901,61.773 116.428,66.113 112.123,66.587 116.467,67.06 116.941,71.558 117.415,67.06 
 | 
			
		||||
		121.681,66.507 117.375,66.113 	"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<path fill="#FFFFFF" d="M177.25,28.393c0,0.866-0.714,1.579-1.58,1.579s-1.58-0.713-1.58-1.579s0.714-1.578,1.58-1.578
 | 
			
		||||
		S177.25,27.527,177.25,28.393z"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<polygon fill="#FFFFFF" points="175.67,23.579 175.196,27.919 170.891,28.393 175.235,28.866 175.71,33.364 176.184,28.866 
 | 
			
		||||
		180.449,28.314 176.144,27.919 	"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<path fill="#FFFFFF" d="M105.843,222.202c0,0.865-0.713,1.578-1.58,1.578s-1.58-0.713-1.58-1.578c0-0.865,0.713-1.578,1.58-1.578
 | 
			
		||||
		S105.843,221.337,105.843,222.202z"/>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
	<polygon fill="#FFFFFF" points="104.263,217.388 103.789,221.729 99.484,222.202 103.829,222.675 104.303,227.173 104.776,222.675 
 | 
			
		||||
		109.042,222.124 104.737,221.729 	"/>
 | 
			
		||||
</g>
 | 
			
		||||
<path fill="#EF3E42" d="M26.852,157.585c-6.899,3.377-13.081,6.711-18.324,9.967l3.191,1.16c4.584-2.822,10.091-5.771,15.891-8.365"
 | 
			
		||||
	/>
 | 
			
		||||
<path fill="#EF3E42" d="M63.279,221.362c-6.307,5.506-12.825,11.383-19.365,17.543l-0.29,4.35
 | 
			
		||||
	c5.988-6.168,13.34-12.828,21.829-19.895"/>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 12 KiB  | 
@@ -38,7 +38,7 @@ define([
 | 
			
		||||
            canEdit: function (domainObject) {
 | 
			
		||||
                return domainObject.type === 'LadTableSet';
 | 
			
		||||
            },
 | 
			
		||||
            view: function (domainObject) {
 | 
			
		||||
            view: function (domainObject, isEditing, objectPath) {
 | 
			
		||||
                let component;
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
@@ -49,7 +49,8 @@ define([
 | 
			
		||||
                            },
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                domainObject
 | 
			
		||||
                                domainObject,
 | 
			
		||||
                                objectPath
 | 
			
		||||
                            },
 | 
			
		||||
                            el: element,
 | 
			
		||||
                            template: '<lad-table-set></lad-table-set>'
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './components/LadTable.vue',
 | 
			
		||||
    './components/LADTable.vue',
 | 
			
		||||
    'vue'
 | 
			
		||||
], function (
 | 
			
		||||
    LadTableComponent,
 | 
			
		||||
@@ -38,7 +38,7 @@ define([
 | 
			
		||||
            canEdit: function (domainObject) {
 | 
			
		||||
                return domainObject.type === 'LadTable';
 | 
			
		||||
            },
 | 
			
		||||
            view: function (domainObject) {
 | 
			
		||||
            view: function (domainObject, isEditing, objectPath) {
 | 
			
		||||
                let component;
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
@@ -49,7 +49,8 @@ define([
 | 
			
		||||
                            },
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                domainObject
 | 
			
		||||
                                domainObject,
 | 
			
		||||
                                objectPath
 | 
			
		||||
                            },
 | 
			
		||||
                            el: element,
 | 
			
		||||
                            template: '<lad-table-component></lad-table-component>'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -21,7 +22,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
    <tr>
 | 
			
		||||
    <tr @contextmenu.prevent="showContextMenu">
 | 
			
		||||
        <td>{{name}}</td>
 | 
			
		||||
        <td>{{timestamp}}</td>
 | 
			
		||||
        <td :class="valueClass">
 | 
			
		||||
@@ -35,15 +36,25 @@
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
const CONTEXT_MENU_ACTIONS = [
 | 
			
		||||
    'viewHistoricalData',
 | 
			
		||||
    'remove'
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
    inject: ['openmct', 'objectPath'],
 | 
			
		||||
    props: ['domainObject'],
 | 
			
		||||
    data() {
 | 
			
		||||
        let currentObjectPath = this.objectPath.slice();
 | 
			
		||||
        currentObjectPath.unshift(this.domainObject);
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            name: this.domainObject.name,
 | 
			
		||||
            timestamp: '---',
 | 
			
		||||
            value: '---',
 | 
			
		||||
            valueClass: ''
 | 
			
		||||
            valueClass: '',
 | 
			
		||||
            currentObjectPath
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
@@ -73,11 +84,15 @@ export default {
 | 
			
		||||
                .request(this.domainObject, {strategy: 'latest'})
 | 
			
		||||
                .then((array) => this.updateValues(array[array.length - 1]));
 | 
			
		||||
 | 
			
		||||
        },
 | 
			
		||||
        showContextMenu(event) {
 | 
			
		||||
           this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
 | 
			
		||||
        this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
 | 
			
		||||
        this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
 | 
			
		||||
 | 
			
		||||
        this.limitEvaluator = openmct
 | 
			
		||||
            .telemetry
 | 
			
		||||
 
 | 
			
		||||
@@ -41,10 +41,10 @@
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import lodash from 'lodash';
 | 
			
		||||
import LadRow from './LadRow.vue';
 | 
			
		||||
import LadRow from './LADRow.vue';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct', 'domainObject'],
 | 
			
		||||
    inject: ['openmct', 'domainObject', 'objectPath'],
 | 
			
		||||
    components: {
 | 
			
		||||
        LadRow
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import lodash from 'lodash';
 | 
			
		||||
    import LadRow from './LadRow.vue';
 | 
			
		||||
    import LadRow from './LADRow.vue';
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
    inject: ['openmct', 'domainObject'],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								src/plugins/clearData/clearDataAction.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,40 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
export default class ClearDataAction {
 | 
			
		||||
    constructor(openmct, appliesToObjects) {
 | 
			
		||||
        this.name = 'Clear Data for Object';
 | 
			
		||||
        this.description = 'Clears current data for object, unsubscribes and resubscribes to data';
 | 
			
		||||
        this.cssClass = 'icon-clear-data';
 | 
			
		||||
 | 
			
		||||
        this._openmct = openmct;
 | 
			
		||||
        this._appliesToObjects = appliesToObjects;
 | 
			
		||||
    }
 | 
			
		||||
    invoke(objectPath) {
 | 
			
		||||
        this._openmct.objectViews.emit('clearData', objectPath[0]);
 | 
			
		||||
    }
 | 
			
		||||
    appliesTo(objectPath) {
 | 
			
		||||
        let contextualDomainObject = objectPath[0];
 | 
			
		||||
 | 
			
		||||
        return this._appliesToObjects.filter(type => contextualDomainObject.type === type).length;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								src/plugins/clearData/components/globalClearIndicator.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,18 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="c-indicator c-indicator--clickable icon-clear-data s-status-caution">
 | 
			
		||||
        <span class="label c-indicator__label">
 | 
			
		||||
            <button @click="globalClearEmit">Clear Data</button>
 | 
			
		||||
        </span>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
    methods: {
 | 
			
		||||
        globalClearEmit() {
 | 
			
		||||
            this.openmct.objectViews.emit('clearData');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										54
									
								
								src/plugins/clearData/plugin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,54 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2019, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * 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([
 | 
			
		||||
    './components/globalClearIndicator.vue',
 | 
			
		||||
    './clearDataAction',
 | 
			
		||||
    'vue'
 | 
			
		||||
], function (
 | 
			
		||||
    GlobaClearIndicator,
 | 
			
		||||
    ClearDataAction,
 | 
			
		||||
    Vue
 | 
			
		||||
) {
 | 
			
		||||
    return function plugin(appliesToObjects) {
 | 
			
		||||
        appliesToObjects = appliesToObjects || [];
 | 
			
		||||
 | 
			
		||||
        return function install(openmct) {
 | 
			
		||||
            let component = new Vue ({
 | 
			
		||||
                    provide: {
 | 
			
		||||
                        openmct
 | 
			
		||||
                    },
 | 
			
		||||
                    components: {
 | 
			
		||||
                        GlobalClearIndicator: GlobaClearIndicator.default
 | 
			
		||||
                    },
 | 
			
		||||
                    template: '<GlobalClearIndicator></GlobalClearIndicator>'
 | 
			
		||||
                }),
 | 
			
		||||
                indicator = {
 | 
			
		||||
                    element: component.$mount().$el
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
            openmct.indicators.add(indicator);
 | 
			
		||||
 | 
			
		||||
            openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										62
									
								
								src/plugins/clearData/test/clearDataActionSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,62 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
import ClearDataActionPlugin  from '../plugin.js';
 | 
			
		||||
import ClearDataAction from '../clearDataAction.js';
 | 
			
		||||
 | 
			
		||||
describe('When the Clear Data Plugin is installed,', function () {
 | 
			
		||||
    var mockObjectViews = jasmine.createSpyObj('objectViews', ['emit']),
 | 
			
		||||
        mockIndicatorProvider = jasmine.createSpyObj('indicators', ['add']),
 | 
			
		||||
        mockContextMenuProvider = jasmine.createSpyObj('contextMenu', ['registerAction']),
 | 
			
		||||
        openmct = {
 | 
			
		||||
            objectViews: mockObjectViews,
 | 
			
		||||
            indicators: mockIndicatorProvider,
 | 
			
		||||
            contextMenu: mockContextMenuProvider,
 | 
			
		||||
            install: function (plugin) {
 | 
			
		||||
                plugin(this);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mockObjectPath = [
 | 
			
		||||
            {name: 'mockObject1'},
 | 
			
		||||
            {name: 'mockObject2'}
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
    it('Global Clear Indicator is installed', function () {
 | 
			
		||||
        openmct.install(ClearDataActionPlugin([]));
 | 
			
		||||
 | 
			
		||||
        expect(mockIndicatorProvider.add).toHaveBeenCalled();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('Clear Data context menu action is installed', function () {
 | 
			
		||||
        openmct.install(ClearDataActionPlugin([]));
 | 
			
		||||
 | 
			
		||||
        expect(mockContextMenuProvider.registerAction).toHaveBeenCalled();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('clear data action emits a clearData event when invoked', function () {
 | 
			
		||||
        let action = new ClearDataAction(openmct);
 | 
			
		||||
 | 
			
		||||
        action.invoke(mockObjectPath);
 | 
			
		||||
 | 
			
		||||
        expect(mockObjectViews.emit).toHaveBeenCalledWith('clearData', mockObjectPath[0]);
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										78
									
								
								src/plugins/displayLayout/AlphanumericFormatViewProvider.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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './components/AlphanumericFormatView.vue',
 | 
			
		||||
    'vue'
 | 
			
		||||
], function (AlphanumericFormatView, Vue) {
 | 
			
		||||
 | 
			
		||||
    function AlphanumericFormatViewProvider(openmct, options) {
 | 
			
		||||
        function isTelemetryObject(selectionPath) {
 | 
			
		||||
            let selectedObject = selectionPath[0].context.item;
 | 
			
		||||
            let parentObject = selectionPath[1].context.item;
 | 
			
		||||
            return parentObject &&
 | 
			
		||||
                parentObject.type === 'layout' &&
 | 
			
		||||
                selectedObject &&
 | 
			
		||||
                openmct.telemetry.isTelemetryObject(selectedObject) &&
 | 
			
		||||
                !options.showAsView.includes(selectedObject.type)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            key: 'alphanumeric-format',
 | 
			
		||||
            name: 'Alphanumeric Format',
 | 
			
		||||
            canView: function (selection) {
 | 
			
		||||
                if (selection.length === 0 || selection[0].length === 1) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return selection.every(isTelemetryObject);
 | 
			
		||||
            },
 | 
			
		||||
            view: function (domainObject, isEditing, objectPath) {
 | 
			
		||||
                let component;
 | 
			
		||||
                return {
 | 
			
		||||
                    show: function (element) {
 | 
			
		||||
                        component = new Vue({
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                objectPath
 | 
			
		||||
                            },
 | 
			
		||||
                            components: {
 | 
			
		||||
                                AlphanumericFormatView: AlphanumericFormatView.default
 | 
			
		||||
                            },
 | 
			
		||||
                            template: '<alphanumeric-format-view></alphanumeric-format-view>',
 | 
			
		||||
                            el: element
 | 
			
		||||
                        });
 | 
			
		||||
                    },
 | 
			
		||||
                    destroy: function () {
 | 
			
		||||
                        component.$destroy();
 | 
			
		||||
                        component = undefined;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            priority: function () {
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return AlphanumericFormatViewProvider;
 | 
			
		||||
});
 | 
			
		||||
@@ -28,11 +28,17 @@ define([], function () {
 | 
			
		||||
            key: "layout",
 | 
			
		||||
            description: "A toolbar for objects inside a display layout.",
 | 
			
		||||
            forSelection: function (selection) {
 | 
			
		||||
                // Apply the layout toolbar if the selected object
 | 
			
		||||
                // is inside a layout, or the main layout is selected.
 | 
			
		||||
                return (selection &&
 | 
			
		||||
                    ((selection[1] && selection[1].context.item && selection[1].context.item.type === 'layout') ||
 | 
			
		||||
                        (selection[0].context.item && selection[0].context.item.type === 'layout')));
 | 
			
		||||
                if (!selection || selection.length === 0) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let selectionPath = selection[0];
 | 
			
		||||
                let selectedObject = selectionPath[0];
 | 
			
		||||
                let selectedParent = selectionPath[1];
 | 
			
		||||
 | 
			
		||||
                // Apply the layout toolbar if the selected object is inside a layout, or the main layout is selected.
 | 
			
		||||
                return (selectedParent && selectedParent.context.item && selectedParent.context.item.type === 'layout') ||
 | 
			
		||||
                    (selectedObject.context.item && selectedObject.context.item.type === 'layout');
 | 
			
		||||
            },
 | 
			
		||||
            toolbar: function (selection) {
 | 
			
		||||
                const DIALOG_FORM = {
 | 
			
		||||
@@ -73,190 +79,72 @@ define([], function () {
 | 
			
		||||
                    return openmct.$injector.get('dialogService').getUserInput(form, {});
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getPath() {
 | 
			
		||||
                    return `configuration.items[${selection[0].context.index}]`;
 | 
			
		||||
                function getPath(selectionPath) {
 | 
			
		||||
                    return `configuration.items[${selectionPath[0].context.index}]`;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let selectedParent = selection[1] && selection[1].context.item,
 | 
			
		||||
                    selectedObject = selection[0].context.item,
 | 
			
		||||
                    layoutItem = selection[0].context.layoutItem,
 | 
			
		||||
                    toolbar = [];
 | 
			
		||||
 | 
			
		||||
                if (selectedObject && selectedObject.type === 'layout') {
 | 
			
		||||
                    toolbar.push({
 | 
			
		||||
                        control: "menu",
 | 
			
		||||
                        domainObject: selectedObject,
 | 
			
		||||
                        method: function (option) {
 | 
			
		||||
                            let name = option.name.toLowerCase();
 | 
			
		||||
                            let form = DIALOG_FORM[name];
 | 
			
		||||
                            if (form) {
 | 
			
		||||
                                getUserInput(form)
 | 
			
		||||
                                    .then(element => selection[0].context.addElement(name, element));
 | 
			
		||||
                            } else {
 | 
			
		||||
                                selection[0].context.addElement(name);
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        key: "add",
 | 
			
		||||
                        icon: "icon-plus",
 | 
			
		||||
                        label: "Add",
 | 
			
		||||
                        options: [
 | 
			
		||||
                            {
 | 
			
		||||
                                "name": "Box",
 | 
			
		||||
                                "class": "icon-box-round-corners"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                "name": "Line",
 | 
			
		||||
                                "class": "icon-line-horz"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                "name": "Text",
 | 
			
		||||
                                "class": "icon-font"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                "name": "Image",
 | 
			
		||||
                                "class": "icon-image"
 | 
			
		||||
                            }
 | 
			
		||||
                        ]
 | 
			
		||||
                function getAllTypes(selection) {
 | 
			
		||||
                    return selection.filter(selectionPath => {
 | 
			
		||||
                        let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                        return type === 'text-view' ||
 | 
			
		||||
                            type === 'telemetry-view' ||
 | 
			
		||||
                            type === 'box-view' ||
 | 
			
		||||
                            type === 'image-view' ||
 | 
			
		||||
                            type === 'line-view' ||
 | 
			
		||||
                            type === 'subobject-view';
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!layoutItem) {
 | 
			
		||||
                    return toolbar;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let separator = {
 | 
			
		||||
                    control: "separator"
 | 
			
		||||
                };
 | 
			
		||||
                let remove = {
 | 
			
		||||
                    control: "button",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    icon: "icon-trash",
 | 
			
		||||
                    title: "Delete the selected object",
 | 
			
		||||
                    method: function () {
 | 
			
		||||
                        let removeItem = selection[1].context.removeItem;
 | 
			
		||||
                        let prompt = openmct.overlays.dialog({
 | 
			
		||||
                            iconClass: 'alert',
 | 
			
		||||
                            message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
 | 
			
		||||
                            buttons: [
 | 
			
		||||
                function getAddButton(selection, selectionPath) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        selectionPath = selectionPath || selection[0];
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "menu",
 | 
			
		||||
                            domainObject: selectionPath[0].context.item,
 | 
			
		||||
                            method: function (option) {
 | 
			
		||||
                                let name = option.name.toLowerCase();
 | 
			
		||||
                                let form = DIALOG_FORM[name];
 | 
			
		||||
                                if (form) {
 | 
			
		||||
                                    getUserInput(form)
 | 
			
		||||
                                        .then(element => selectionPath[0].context.addElement(name, element));
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    selectionPath[0].context.addElement(name);
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            key: "add",
 | 
			
		||||
                            icon: "icon-plus",
 | 
			
		||||
                            label: "Add",
 | 
			
		||||
                            options: [
 | 
			
		||||
                                {
 | 
			
		||||
                                    label: 'Ok',
 | 
			
		||||
                                    emphasis: 'true',
 | 
			
		||||
                                    callback: function () {
 | 
			
		||||
                                        removeItem(layoutItem, selection[0].context.index);
 | 
			
		||||
                                        prompt.dismiss();
 | 
			
		||||
                                    }
 | 
			
		||||
                                    "name": "Box",
 | 
			
		||||
                                    "class": "icon-box-round-corners"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    label: 'Cancel',
 | 
			
		||||
                                    callback: function () {
 | 
			
		||||
                                        prompt.dismiss();
 | 
			
		||||
                                    }
 | 
			
		||||
                                    "name": "Line",
 | 
			
		||||
                                    "class": "icon-line-horz"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Text",
 | 
			
		||||
                                    "class": "icon-font"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Image",
 | 
			
		||||
                                    "class": "icon-image"
 | 
			
		||||
                                }
 | 
			
		||||
                            ]
 | 
			
		||||
                        });
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                let stackOrder = {
 | 
			
		||||
                    control: "menu",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    icon: "icon-layers",
 | 
			
		||||
                    title: "Move the selected object above or below other objects",
 | 
			
		||||
                    options: [
 | 
			
		||||
                        {
 | 
			
		||||
                            name: "Move to Top",
 | 
			
		||||
                            value: "top",
 | 
			
		||||
                            class: "icon-arrow-double-up"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            name: "Move Up",
 | 
			
		||||
                            value: "up",
 | 
			
		||||
                            class: "icon-arrow-up"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            name: "Move Down",
 | 
			
		||||
                            value: "down",
 | 
			
		||||
                            class: "icon-arrow-down"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            name: "Move to Bottom",
 | 
			
		||||
                            value: "bottom",
 | 
			
		||||
                            class: "icon-arrow-double-down"
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    method: function (option) {
 | 
			
		||||
                        selection[1].context.orderItem(option.value, selection[0].context.index);
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                let useGrid = {
 | 
			
		||||
                    control: "toggle-button",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".useGrid";
 | 
			
		||||
                    },
 | 
			
		||||
                    options: [
 | 
			
		||||
                        {
 | 
			
		||||
                            value: false,
 | 
			
		||||
                            icon: "icon-grid-snap-to",
 | 
			
		||||
                            title: "Grid snapping enabled"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            value: true,
 | 
			
		||||
                            icon: "icon-grid-snap-no",
 | 
			
		||||
                            title: "Grid snapping disabled"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                };
 | 
			
		||||
                let x = {
 | 
			
		||||
                    control: "input",
 | 
			
		||||
                    type: "number",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".x";
 | 
			
		||||
                    },
 | 
			
		||||
                    label: "X:",
 | 
			
		||||
                    title: "X position"
 | 
			
		||||
                },
 | 
			
		||||
                y = {
 | 
			
		||||
                    control: "input",
 | 
			
		||||
                    type: "number",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".y";
 | 
			
		||||
                    },
 | 
			
		||||
                    label: "Y:",
 | 
			
		||||
                    title: "Y position",
 | 
			
		||||
                },
 | 
			
		||||
                width = {
 | 
			
		||||
                    control: 'input',
 | 
			
		||||
                    type: 'number',
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".width";
 | 
			
		||||
                    },
 | 
			
		||||
                    label: 'W:',
 | 
			
		||||
                    title: 'Resize object width'
 | 
			
		||||
                },
 | 
			
		||||
                height = {
 | 
			
		||||
                    control: 'input',
 | 
			
		||||
                    type: 'number',
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".height";
 | 
			
		||||
                    },
 | 
			
		||||
                    label: 'H:',
 | 
			
		||||
                    title: 'Resize object height'
 | 
			
		||||
                };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (layoutItem.type === 'subobject-view') {
 | 
			
		||||
                    if (toolbar.length > 0) {
 | 
			
		||||
                        toolbar.push(separator);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    toolbar.push({
 | 
			
		||||
                function getToggleFrameButton(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "toggle-button",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".hasFrame";
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath =>
 | 
			
		||||
                            selectionPath[0].context.layoutItem.type === 'subobject-view'
 | 
			
		||||
                        ),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".hasFrame";
 | 
			
		||||
                        },
 | 
			
		||||
                        options: [
 | 
			
		||||
                            {
 | 
			
		||||
@@ -270,52 +158,186 @@ define([], function () {
 | 
			
		||||
                                title: "Frame hidden"
 | 
			
		||||
                            }
 | 
			
		||||
                        ]
 | 
			
		||||
                    });
 | 
			
		||||
                    toolbar.push(separator);
 | 
			
		||||
                    toolbar.push(stackOrder);
 | 
			
		||||
                    toolbar.push(x);
 | 
			
		||||
                    toolbar.push(y);
 | 
			
		||||
                    toolbar.push(width);
 | 
			
		||||
                    toolbar.push(height);
 | 
			
		||||
                    toolbar.push(useGrid);
 | 
			
		||||
                    toolbar.push(separator);
 | 
			
		||||
                    toolbar.push(remove);
 | 
			
		||||
                } else {
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getRemoveButton(selectedParent, selectionPath, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "button",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        icon: "icon-trash",
 | 
			
		||||
                        title: "Delete the selected object",
 | 
			
		||||
                        method: function () {
 | 
			
		||||
                            let removeItem = selectionPath[1].context.removeItem;
 | 
			
		||||
                            let prompt = openmct.overlays.dialog({
 | 
			
		||||
                                iconClass: 'alert',
 | 
			
		||||
                                message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
 | 
			
		||||
                                buttons: [
 | 
			
		||||
                                    {
 | 
			
		||||
                                        label: 'Ok',
 | 
			
		||||
                                        emphasis: 'true',
 | 
			
		||||
                                        callback: function () {
 | 
			
		||||
                                            removeItem(getAllTypes(selection));
 | 
			
		||||
                                            prompt.dismiss();
 | 
			
		||||
                                        }
 | 
			
		||||
                                    },
 | 
			
		||||
                                    {
 | 
			
		||||
                                        label: 'Cancel',
 | 
			
		||||
                                        callback: function () {
 | 
			
		||||
                                            prompt.dismiss();
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                ]
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getStackOrder(selectedParent, selectionPath) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "menu",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        icon: "icon-layers",
 | 
			
		||||
                        title: "Move the selected object above or below other objects",
 | 
			
		||||
                        options: [
 | 
			
		||||
                            {
 | 
			
		||||
                                name: "Move to Top",
 | 
			
		||||
                                value: "top",
 | 
			
		||||
                                class: "icon-arrow-double-up"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                name: "Move Up",
 | 
			
		||||
                                value: "up",
 | 
			
		||||
                                class: "icon-arrow-up"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                name: "Move Down",
 | 
			
		||||
                                value: "down",
 | 
			
		||||
                                class: "icon-arrow-down"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                name: "Move to Bottom",
 | 
			
		||||
                                value: "bottom",
 | 
			
		||||
                                class: "icon-arrow-double-down"
 | 
			
		||||
                            }
 | 
			
		||||
                        ],
 | 
			
		||||
                        method: function (option) {
 | 
			
		||||
                            selectionPath[1].context.orderItem(option.value, getAllTypes(selection));
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getXInput(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: getAllTypes(selection),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".x";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "X:",
 | 
			
		||||
                            title: "X position"
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getYInput(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: getAllTypes(selection),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".y";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "Y:",
 | 
			
		||||
                            title: "Y position"
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getWidthInput(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: 'input',
 | 
			
		||||
                            type: 'number',
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: getAllTypes(selection),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".width";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: 'W:',
 | 
			
		||||
                            title: 'Resize object width'
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getHeightInput(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: 'input',
 | 
			
		||||
                            type: 'number',
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: getAllTypes(selection),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".height";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: 'H:',
 | 
			
		||||
                            title: 'Resize object height'
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getX2Input(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                                return selectionPath[0].context.layoutItem.type === 'line-view';
 | 
			
		||||
                            }),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".x2";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "X2:",
 | 
			
		||||
                            title: "X2 position"
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getY2Input(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                                return selectionPath[0].context.layoutItem.type === 'line-view';
 | 
			
		||||
                            }),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".y2";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "Y2:",
 | 
			
		||||
                            title: "Y2 position"
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getTextSizeMenu(selectedParent, selection) {
 | 
			
		||||
                    const TEXT_SIZE = [8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96, 128];
 | 
			
		||||
                    let fill = {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".fill";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-paint-bucket",
 | 
			
		||||
                        title: "Set fill color"
 | 
			
		||||
                    },
 | 
			
		||||
                    stroke = {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".stroke";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-line-horz",
 | 
			
		||||
                        title: "Set border color"
 | 
			
		||||
                    },
 | 
			
		||||
                    color = {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".color";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-font",
 | 
			
		||||
                        mandatory: true,
 | 
			
		||||
                        title: "Set text color",
 | 
			
		||||
                        preventNone: true
 | 
			
		||||
                    },
 | 
			
		||||
                    size = {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "select-menu",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".size";
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                            return type === 'text-view' || type === 'telemetry-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".size";
 | 
			
		||||
                        },
 | 
			
		||||
                        title: "Set text size",
 | 
			
		||||
                        options: TEXT_SIZE.map(size => {
 | 
			
		||||
@@ -324,13 +346,128 @@ define([], function () {
 | 
			
		||||
                            };
 | 
			
		||||
                        })
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                    if (layoutItem.type === 'telemetry-view') {
 | 
			
		||||
                        let displayMode = {
 | 
			
		||||
                function getFillMenu(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                            return type === 'text-view' ||
 | 
			
		||||
                                type === 'telemetry-view' ||
 | 
			
		||||
                                type === 'box-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".fill";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-paint-bucket",
 | 
			
		||||
                        title: "Set fill color"
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getStrokeMenu(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                            return type === 'text-view' ||
 | 
			
		||||
                                type === 'telemetry-view' ||
 | 
			
		||||
                                type === 'box-view' ||
 | 
			
		||||
                                type === 'image-view' ||
 | 
			
		||||
                                type === 'line-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".stroke";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-line-horz",
 | 
			
		||||
                        title: "Set border color"
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getTextColorMenu(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                            return type === 'text-view' || type === 'telemetry-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".color";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-font",
 | 
			
		||||
                        mandatory: true,
 | 
			
		||||
                        title: "Set text color",
 | 
			
		||||
                        preventNone: true
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getURLButton(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "button",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            return selectionPath[0].context.layoutItem.type === 'image-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath);
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-image",
 | 
			
		||||
                        title: "Edit image properties",
 | 
			
		||||
                        dialog: DIALOG_FORM.image
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getTextButton(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "button",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            return selectionPath[0].context.layoutItem.type === 'text-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath);
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-gear",
 | 
			
		||||
                        title: "Edit text properties",
 | 
			
		||||
                        dialog: DIALOG_FORM.text
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getTelemetryValueMenu(selectionPath, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "select-menu",
 | 
			
		||||
                            domainObject: selectionPath[1].context.item,
 | 
			
		||||
                            applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                                return selectionPath[0].context.layoutItem.type === 'telemetry-view';
 | 
			
		||||
                            }),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".value";
 | 
			
		||||
                            },
 | 
			
		||||
                            title: "Set value",
 | 
			
		||||
                            options: openmct.telemetry.getMetadata(selectionPath[0].context.item).values().map(value => {
 | 
			
		||||
                                return {
 | 
			
		||||
                                    name: value.name,
 | 
			
		||||
                                    value: value.key
 | 
			
		||||
                                }
 | 
			
		||||
                            })
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getDisplayModeMenu(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "select-menu",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath() + ".displayMode";
 | 
			
		||||
                            applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                                return selectionPath[0].context.layoutItem.type === 'telemetry-view';
 | 
			
		||||
                            }),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".displayMode";
 | 
			
		||||
                            },
 | 
			
		||||
                            title: "Set display mode",
 | 
			
		||||
                            options: [
 | 
			
		||||
@@ -347,146 +484,196 @@ define([], function () {
 | 
			
		||||
                                    value: "value"
 | 
			
		||||
                                }
 | 
			
		||||
                            ]
 | 
			
		||||
                        },
 | 
			
		||||
                        value = {
 | 
			
		||||
                            control: "select-menu",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath() + ".value";
 | 
			
		||||
                            },
 | 
			
		||||
                            title: "Set value",
 | 
			
		||||
                            options: openmct.telemetry.getMetadata(selectedObject).values().map(value => {
 | 
			
		||||
                                return {
 | 
			
		||||
                                    name: value.name,
 | 
			
		||||
                                    value: value.key
 | 
			
		||||
                                }
 | 
			
		||||
                            })
 | 
			
		||||
                        };
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            displayMode,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            value,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            fill,
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            color,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            size,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            height,
 | 
			
		||||
                            width,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    } else if (layoutItem.type === 'text-view') {
 | 
			
		||||
                        let text = {
 | 
			
		||||
                            control: "button",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath();
 | 
			
		||||
                            },
 | 
			
		||||
                            icon: "icon-gear",
 | 
			
		||||
                            title: "Edit text properties",
 | 
			
		||||
                            dialog: DIALOG_FORM['text']
 | 
			
		||||
                        };
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            fill,
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            color,
 | 
			
		||||
                            size,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            height,
 | 
			
		||||
                            width,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            text,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    } else if (layoutItem.type === 'box-view') {
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            fill,
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            height,
 | 
			
		||||
                            width,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    } else if (layoutItem.type === 'image-view') {
 | 
			
		||||
                        let url = {
 | 
			
		||||
                            control: "button",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath();
 | 
			
		||||
                            },
 | 
			
		||||
                            icon: "icon-image",
 | 
			
		||||
                            title: "Edit image properties",
 | 
			
		||||
                            dialog: DIALOG_FORM['image']
 | 
			
		||||
                        };
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            height,
 | 
			
		||||
                            width,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            url,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    } else if (layoutItem.type === 'line-view') {
 | 
			
		||||
                        let x2 = {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath() + ".x2";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "X2:",
 | 
			
		||||
                            title: "X2 position"
 | 
			
		||||
                        },
 | 
			
		||||
                        y2 = {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath() + ".y2";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "Y2:",
 | 
			
		||||
                            title: "Y2 position",
 | 
			
		||||
                        };
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            x2,
 | 
			
		||||
                            y2,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return toolbar;
 | 
			
		||||
                function getSeparator() {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "separator"
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function isMainLayoutSelected(selectionPath) {
 | 
			
		||||
                    let selectedObject = selectionPath[0].context.item;
 | 
			
		||||
                    return selectedObject && selectedObject.type === 'layout' &&
 | 
			
		||||
                        !selectionPath[0].context.layoutItem;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (isMainLayoutSelected(selection[0])) {
 | 
			
		||||
                    return [getAddButton(selection)];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let toolbar = {
 | 
			
		||||
                    'add-menu': [],
 | 
			
		||||
                    'toggle-frame': [],
 | 
			
		||||
                    'display-mode': [],
 | 
			
		||||
                    'telemetry-value': [],
 | 
			
		||||
                    'style': [],
 | 
			
		||||
                    'text-style': [],
 | 
			
		||||
                    'position': [],
 | 
			
		||||
                    'text': [],
 | 
			
		||||
                    'url': [],
 | 
			
		||||
                    'remove': []
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                selection.forEach(selectionPath => {
 | 
			
		||||
                    let selectedParent = selectionPath[1].context.item;
 | 
			
		||||
                    let layoutItem = selectionPath[0].context.layoutItem;
 | 
			
		||||
 | 
			
		||||
                    if (layoutItem.type === 'subobject-view') {
 | 
			
		||||
                        if (toolbar['add-menu'].length === 0 && selectionPath[0].context.item.type === 'layout') {
 | 
			
		||||
                            toolbar['add-menu'] = [getAddButton(selection, selectionPath)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['toggle-frame'].length === 0) {
 | 
			
		||||
                            toolbar['toggle-frame'] = [getToggleFrameButton(selectedParent, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.position.length === 0) {
 | 
			
		||||
                            toolbar.position = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.remove.length === 0) {
 | 
			
		||||
                            toolbar.remove = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if (layoutItem.type === 'telemetry-view') {
 | 
			
		||||
                        if (toolbar['display-mode'].length === 0) {
 | 
			
		||||
                            toolbar['display-mode'] = [getDisplayModeMenu(selectedParent, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['telemetry-value'].length === 0) {
 | 
			
		||||
                            toolbar['telemetry-value'] = [getTelemetryValueMenu(selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.style.length < 2) {
 | 
			
		||||
                            toolbar.style = [
 | 
			
		||||
                                getFillMenu(selectedParent, selection),
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['text-style'].length === 0) {
 | 
			
		||||
                            toolbar['text-style'] = [
 | 
			
		||||
                                getTextColorMenu(selectedParent, selection),
 | 
			
		||||
                                getTextSizeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.position.length === 0) {
 | 
			
		||||
                            toolbar.position = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.remove.length === 0) {
 | 
			
		||||
                            toolbar.remove = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if (layoutItem.type === 'text-view') {
 | 
			
		||||
                        if (toolbar.style.length < 2) {
 | 
			
		||||
                            toolbar.style = [
 | 
			
		||||
                                getFillMenu(selectedParent, selection),
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['text-style'].length === 0) {
 | 
			
		||||
                            toolbar['text-style'] = [
 | 
			
		||||
                                getTextColorMenu(selectedParent, selection),
 | 
			
		||||
                                getTextSizeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.position.length === 0) {
 | 
			
		||||
                            toolbar.position = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.text.length === 0) {
 | 
			
		||||
                            toolbar.text = [getTextButton(selectedParent, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.remove.length === 0) {
 | 
			
		||||
                            toolbar.remove = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if (layoutItem.type === 'box-view') {
 | 
			
		||||
                        if (toolbar.style.length < 2) {
 | 
			
		||||
                            toolbar.style = [
 | 
			
		||||
                                getFillMenu(selectedParent, selection),
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.position.length === 0) {
 | 
			
		||||
                            toolbar.position = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.remove.length === 0) {
 | 
			
		||||
                            toolbar.remove = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if (layoutItem.type === 'image-view') {
 | 
			
		||||
                        if (toolbar.style.length === 0) {
 | 
			
		||||
                            toolbar.style = [
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.position.length === 0) {
 | 
			
		||||
                            toolbar.position = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.url.length === 0) {
 | 
			
		||||
                            toolbar.url = [getURLButton(selectedParent, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.remove.length === 0) {
 | 
			
		||||
                            toolbar.remove = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if (layoutItem.type === 'line-view') {
 | 
			
		||||
                        if (toolbar.style.length === 0) {
 | 
			
		||||
                            toolbar.style = [
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.position.length === 0) {
 | 
			
		||||
                            toolbar.position = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getX2Input(selectedParent, selection),
 | 
			
		||||
                                getY2Input(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar.remove.length === 0) {
 | 
			
		||||
                            toolbar.remove = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                let toolbarArray = Object.values(toolbar);
 | 
			
		||||
                return _.flatten(toolbarArray.reduce((accumulator, group, index) => {
 | 
			
		||||
                    group = group.filter(control => control !== undefined);
 | 
			
		||||
 | 
			
		||||
                    if (group.length > 0) {
 | 
			
		||||
                        accumulator.push(group);
 | 
			
		||||
 | 
			
		||||
                        if (index < toolbarArray.length - 1) {
 | 
			
		||||
                            accumulator.push(getSeparator());
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return accumulator;
 | 
			
		||||
                }, []));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ define(function () {
 | 
			
		||||
                domainObject.composition = [];
 | 
			
		||||
                domainObject.configuration = {
 | 
			
		||||
                    items: [],
 | 
			
		||||
                    layoutGrid: [10, 10],
 | 
			
		||||
                    layoutGrid: [10, 10]
 | 
			
		||||
                };
 | 
			
		||||
            },
 | 
			
		||||
            form: [
 | 
			
		||||
 
 | 
			
		||||
@@ -95,7 +95,7 @@ define(
 | 
			
		||||
         * @param {number[]} pixelDelta the offset from the
 | 
			
		||||
         *        original position, in pixels
 | 
			
		||||
         */
 | 
			
		||||
        LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
 | 
			
		||||
        LayoutDrag.prototype.getAdjustedPositionAndDimensions = function (pixelDelta) {
 | 
			
		||||
            var gridDelta = toGridDelta(this.gridSize, pixelDelta);
 | 
			
		||||
            return {
 | 
			
		||||
                position: max(add(
 | 
			
		||||
@@ -109,6 +109,16 @@ define(
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
 | 
			
		||||
            var gridDelta = toGridDelta(this.gridSize, pixelDelta);
 | 
			
		||||
            return {
 | 
			
		||||
                position: max(add(
 | 
			
		||||
                    this.rawPosition.position,
 | 
			
		||||
                    multiply(gridDelta, this.posFactor)
 | 
			
		||||
                ), [0, 0])
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return LayoutDrag;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,90 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="c-properties" v-if="isEditing">
 | 
			
		||||
        <div class="c-properties__header">Alphanumeric Format</div>
 | 
			
		||||
        <ul class="c-properties__section">
 | 
			
		||||
            <li class="c-properties__row">
 | 
			
		||||
                <div class="c-properties__label" title="Printf formatting for the selected telemetry">
 | 
			
		||||
                    <label for="telemetryPrintfFormat">Format</label>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="c-properties__value">
 | 
			
		||||
                    <input id="telemetryPrintfFormat"
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        @change="formatTelemetry"
 | 
			
		||||
                        :value="telemetryFormat"
 | 
			
		||||
                        :placeholder="nonMixedFormat ? '' : 'Mixed'"
 | 
			
		||||
                    >
 | 
			
		||||
                </div>
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    export default {
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        data() {
 | 
			
		||||
            let selectionPath = this.openmct.selection.get()[0];
 | 
			
		||||
            return {
 | 
			
		||||
                isEditing: this.openmct.editor.isEditing(),
 | 
			
		||||
                telemetryFormat: undefined,
 | 
			
		||||
                nonMixedFormat: false
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        methods: {
 | 
			
		||||
            toggleEdit(isEditing) {
 | 
			
		||||
                this.isEditing = isEditing;
 | 
			
		||||
            },
 | 
			
		||||
            formatTelemetry(event) {
 | 
			
		||||
                let newFormat = event.currentTarget.value;
 | 
			
		||||
                this.openmct.selection.get().forEach(selectionPath => {
 | 
			
		||||
                    selectionPath[0].context.updateTelemetryFormat(newFormat);    
 | 
			
		||||
                });
 | 
			
		||||
                this.telemetryFormat = newFormat;
 | 
			
		||||
            },
 | 
			
		||||
            handleSelection(selection) {
 | 
			
		||||
                if (selection.length === 0 || selection[0].length < 2) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let format = selection[0][0].context.layoutItem.format;
 | 
			
		||||
                this.nonMixedFormat = selection.every(selectionPath => {
 | 
			
		||||
                    return selectionPath[0].context.layoutItem.format === format;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                this.telemetryFormat = this.nonMixedFormat ? format : '';
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
            this.openmct.editor.on('isEditing', this.toggleEdit);
 | 
			
		||||
            this.openmct.selection.on('change', this.handleSelection);
 | 
			
		||||
            this.handleSelection(this.openmct.selection.get());
 | 
			
		||||
        },
 | 
			
		||||
        destroyed() {
 | 
			
		||||
            this.openmct.editor.off('isEditing', this.toggleEdit);
 | 
			
		||||
            this.openmct.selection.off('change', this.handleSelection);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
@@ -23,7 +23,8 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <layout-frame :item="item"
 | 
			
		||||
                  :grid-size="gridSize"
 | 
			
		||||
                  @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
                  @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                  @endMove="() => $emit('endMove')">
 | 
			
		||||
        <div class="c-box-view"
 | 
			
		||||
             :style="style">
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -54,8 +55,7 @@
 | 
			
		||||
                x: 1,
 | 
			
		||||
                y: 1,
 | 
			
		||||
                width: 10, 
 | 
			
		||||
                height: 5,
 | 
			
		||||
                useGrid: true
 | 
			
		||||
                height: 5
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,11 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="l-layout"
 | 
			
		||||
         @dragover="handleDragOver"
 | 
			
		||||
         @click="bypassSelection"
 | 
			
		||||
         @drop="handleDrop">
 | 
			
		||||
         @click.capture="bypassSelection"
 | 
			
		||||
         @drop="handleDrop"
 | 
			
		||||
         :class="{
 | 
			
		||||
            'is-multi-selected': selectedLayoutItems.length > 1
 | 
			
		||||
            }">
 | 
			
		||||
        <!-- Background grid -->
 | 
			
		||||
        <div class="l-layout__grid-holder c-grid">
 | 
			
		||||
            <div class="c-grid__x l-grid l-grid-x"
 | 
			
		||||
@@ -39,18 +42,39 @@
 | 
			
		||||
                   :is="item.type"
 | 
			
		||||
                   :item="item"
 | 
			
		||||
                   :key="item.id"
 | 
			
		||||
                   :gridSize="item.useGrid ? gridSize : [1, 1]"
 | 
			
		||||
                   :gridSize="gridSize"
 | 
			
		||||
                   :initSelect="initSelectIndex === index"
 | 
			
		||||
                   :index="index"
 | 
			
		||||
                   @endDrag="endDrag"
 | 
			
		||||
        >
 | 
			
		||||
                   :multiSelect="selectedLayoutItems.length > 1"
 | 
			
		||||
                   @move="move"
 | 
			
		||||
                   @endMove="endMove"
 | 
			
		||||
                   @endLineResize='endLineResize'
 | 
			
		||||
                   @formatChanged='updateTelemetryFormat'>
 | 
			
		||||
        </component>
 | 
			
		||||
        <edit-marquee v-if='showMarquee'
 | 
			
		||||
                      :gridSize="gridSize"
 | 
			
		||||
                      :selectedLayoutItems="selectedLayoutItems"
 | 
			
		||||
                      @endResize="endResize">
 | 
			
		||||
        </edit-marquee>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
 | 
			
		||||
    @mixin displayMarquee($c) {
 | 
			
		||||
        > .c-frame-edit {
 | 
			
		||||
            // All other frames
 | 
			
		||||
            //@include test($c, 0.4);
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
        > .c-frame > .c-frame-edit {
 | 
			
		||||
            // Line object frame
 | 
			
		||||
            //@include test($c, 0.4);
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .l-layout {
 | 
			
		||||
        @include abs();
 | 
			
		||||
        display: flex;
 | 
			
		||||
@@ -70,7 +94,7 @@
 | 
			
		||||
        .l-shell__main-container {
 | 
			
		||||
            &[s-selected],
 | 
			
		||||
            &[s-selected-parent] {
 | 
			
		||||
                // Display grid in main layout holder when editing
 | 
			
		||||
                // Display grid and allow edit marquee to display in main layout holder when editing
 | 
			
		||||
                > .l-layout {
 | 
			
		||||
                    background: $editUIGridColorBg;
 | 
			
		||||
 | 
			
		||||
@@ -84,7 +108,7 @@
 | 
			
		||||
        .l-layout__frame {
 | 
			
		||||
            &[s-selected],
 | 
			
		||||
            &[s-selected-parent] {
 | 
			
		||||
                // Display grid in nested layouts when editing
 | 
			
		||||
                // Display grid and allow edit marquee to display in nested layouts when editing
 | 
			
		||||
                > * > * > .l-layout {
 | 
			
		||||
                    background: $editUIGridColorBg;
 | 
			
		||||
                    box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
 | 
			
		||||
@@ -95,10 +119,21 @@
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*********************** EDIT MARQUEE CONTROL */
 | 
			
		||||
        *[s-selected-parent] {
 | 
			
		||||
            > .l-layout {
 | 
			
		||||
                // When main shell layout is the parent
 | 
			
		||||
                @include displayMarquee(deeppink);
 | 
			
		||||
            }
 | 
			
		||||
            > * > * > * {
 | 
			
		||||
                // When a sub-layout is the parent
 | 
			
		||||
                @include displayMarquee(blue);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import uuid from 'uuid';
 | 
			
		||||
 | 
			
		||||
@@ -108,6 +143,7 @@
 | 
			
		||||
    import TextView from './TextView.vue'
 | 
			
		||||
    import LineView from './LineView.vue'
 | 
			
		||||
    import ImageView from './ImageView.vue'
 | 
			
		||||
    import EditMarquee from './EditMarquee.vue'
 | 
			
		||||
 | 
			
		||||
    const ITEM_TYPE_VIEW_MAP = {
 | 
			
		||||
        'subobject-view': SubobjectView,
 | 
			
		||||
@@ -123,9 +159,11 @@
 | 
			
		||||
        down: -1,
 | 
			
		||||
        bottom: Number.NEGATIVE_INFINITY
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
 | 
			
		||||
 | 
			
		||||
    let components = ITEM_TYPE_VIEW_MAP;
 | 
			
		||||
    components['edit-marquee'] = EditMarquee;
 | 
			
		||||
 | 
			
		||||
    function getItemDefinition(itemType, ...options) {
 | 
			
		||||
        let itemView = ITEM_TYPE_VIEW_MAP[itemType];
 | 
			
		||||
 | 
			
		||||
@@ -141,7 +179,8 @@
 | 
			
		||||
            let domainObject = JSON.parse(JSON.stringify(this.domainObject));
 | 
			
		||||
            return {
 | 
			
		||||
                internalDomainObject: domainObject,
 | 
			
		||||
                initSelectIndex: undefined
 | 
			
		||||
                initSelectIndex: undefined,
 | 
			
		||||
                selection: []
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
@@ -150,82 +189,145 @@
 | 
			
		||||
            },
 | 
			
		||||
            layoutItems() {
 | 
			
		||||
                return this.internalDomainObject.configuration.items;
 | 
			
		||||
            },
 | 
			
		||||
            selectedLayoutItems() {
 | 
			
		||||
                return this.layoutItems.filter(item => {
 | 
			
		||||
                    return this.itemIsInCurrentSelection(item);
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            showMarquee() {
 | 
			
		||||
                let selectionPath = this.selection[0];
 | 
			
		||||
                let singleSelectedLine = this.selection.length === 1 &&
 | 
			
		||||
                    selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.type === 'line-view';
 | 
			
		||||
                return selectionPath && selectionPath.length > 1 && !singleSelectedLine;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct', 'options'],
 | 
			
		||||
        inject: ['openmct', 'options', 'objectPath'],
 | 
			
		||||
        props: ['domainObject'],
 | 
			
		||||
        components: ITEM_TYPE_VIEW_MAP,
 | 
			
		||||
        components: components,
 | 
			
		||||
        methods: {
 | 
			
		||||
            addElement(itemType, element) {
 | 
			
		||||
                this.addItem(itemType + '-view', element);
 | 
			
		||||
            },
 | 
			
		||||
            setSelection(selection) {
 | 
			
		||||
                if (selection.length === 0) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (this.removeSelectionListener) {
 | 
			
		||||
                    this.removeSelectionListener();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let itemIndex = selection[0].context.index;
 | 
			
		||||
 | 
			
		||||
                if (itemIndex !== undefined) {
 | 
			
		||||
                    this.attachSelectionListener(itemIndex);
 | 
			
		||||
                }
 | 
			
		||||
                this.selection = selection;
 | 
			
		||||
            },
 | 
			
		||||
            attachSelectionListener(index) {
 | 
			
		||||
                let path = `configuration.items[${index}].useGrid`;
 | 
			
		||||
                this.removeSelectionListener = this.openmct.objects.observe(this.internalDomainObject, path, function (value) {
 | 
			
		||||
                    let item = this.layoutItems[index];
 | 
			
		||||
 | 
			
		||||
                    if (value) {
 | 
			
		||||
                        item.x = Math.round(item.x / this.gridSize[0]);
 | 
			
		||||
                        item.y = Math.round(item.y / this.gridSize[1]);
 | 
			
		||||
                        item.width = Math.round(item.width / this.gridSize[0]);
 | 
			
		||||
                        item.height = Math.round(item.height / this.gridSize[1]);
 | 
			
		||||
 | 
			
		||||
                        if (item.x2) {
 | 
			
		||||
                            item.x2 = Math.round(item.x2 / this.gridSize[0]);
 | 
			
		||||
                        }
 | 
			
		||||
                        if (item.y2) {
 | 
			
		||||
                            item.y2 = Math.round(item.y2 / this.gridSize[1]);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        item.x = this.gridSize[0] * item.x;
 | 
			
		||||
                        item.y = this.gridSize[1] * item.y;
 | 
			
		||||
                        item.width = this.gridSize[0] * item.width;
 | 
			
		||||
                        item.height = this.gridSize[1] * item.height;
 | 
			
		||||
 | 
			
		||||
                        if (item.x2) {
 | 
			
		||||
                            item.x2 = this.gridSize[0] * item.x2;
 | 
			
		||||
                        }
 | 
			
		||||
                        if (item.y2) {
 | 
			
		||||
                            item.y2 = this.gridSize[1] * item.y2;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    item.useGrid = value;
 | 
			
		||||
                    this.mutate(`configuration.items[${index}]`, item);
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
            itemIsInCurrentSelection(item) {
 | 
			
		||||
                return this.selection.some(selectionPath =>
 | 
			
		||||
                    selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.id === item.id);
 | 
			
		||||
            },
 | 
			
		||||
            bypassSelection($event) {
 | 
			
		||||
                if (this.dragInProgress) {
 | 
			
		||||
                    if ($event) {
 | 
			
		||||
                        $event.stopImmediatePropagation();
 | 
			
		||||
                    }
 | 
			
		||||
                    this.dragInProgress = false;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            endDrag(item, updates) {
 | 
			
		||||
            endLineResize(item, updates) {
 | 
			
		||||
                this.dragInProgress = true;
 | 
			
		||||
                setTimeout(function () {
 | 
			
		||||
                    this.dragInProgress = false;
 | 
			
		||||
                }.bind(this), 0);
 | 
			
		||||
 | 
			
		||||
                let index = this.layoutItems.indexOf(item);
 | 
			
		||||
                Object.assign(item, updates);
 | 
			
		||||
                this.mutate(`configuration.items[${index}]`, item);
 | 
			
		||||
            },
 | 
			
		||||
            endResize(scaleWidth, scaleHeight, marqueeStart, marqueeOffset) {
 | 
			
		||||
                this.dragInProgress = true;
 | 
			
		||||
                this.layoutItems.forEach(item => {
 | 
			
		||||
                    if (this.itemIsInCurrentSelection(item)) {
 | 
			
		||||
                        let itemXInMarqueeSpace = item.x - marqueeStart.x;
 | 
			
		||||
                        let itemXInMarqueeSpaceAfterScale = Math.round(itemXInMarqueeSpace * scaleWidth);
 | 
			
		||||
                        item.x = itemXInMarqueeSpaceAfterScale + marqueeOffset.x + marqueeStart.x;
 | 
			
		||||
 | 
			
		||||
                        let itemYInMarqueeSpace = item.y - marqueeStart.y;
 | 
			
		||||
                        let itemYInMarqueeSpaceAfterScale = Math.round(itemYInMarqueeSpace * scaleHeight);
 | 
			
		||||
                        item.y = itemYInMarqueeSpaceAfterScale + marqueeOffset.y + marqueeStart.y;
 | 
			
		||||
 | 
			
		||||
                        if (item.x2) {
 | 
			
		||||
                            let itemX2InMarqueeSpace = item.x2 - marqueeStart.x;
 | 
			
		||||
                            let itemX2InMarqueeSpaceAfterScale = Math.round(itemX2InMarqueeSpace * scaleWidth);
 | 
			
		||||
                            item.x2 = itemX2InMarqueeSpaceAfterScale + marqueeOffset.x + marqueeStart.x;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            item.width = Math.round(item.width * scaleWidth);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (item.y2) {
 | 
			
		||||
                            let itemY2InMarqueeSpace = item.y2 - marqueeStart.y;
 | 
			
		||||
                            let itemY2InMarqueeSpaceAfterScale = Math.round(itemY2InMarqueeSpace * scaleHeight);
 | 
			
		||||
                            item.y2 = itemY2InMarqueeSpaceAfterScale + marqueeOffset.y + marqueeStart.y;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            item.height = Math.round(item.height * scaleHeight);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                this.mutate("configuration.items", this.layoutItems);
 | 
			
		||||
            },
 | 
			
		||||
            move(gridDelta) {
 | 
			
		||||
                this.dragInProgress = true;
 | 
			
		||||
 | 
			
		||||
                if (!this.initialPositions) {
 | 
			
		||||
                    this.initialPositions = {};
 | 
			
		||||
                    _.cloneDeep(this.selectedLayoutItems).forEach(selectedItem => {
 | 
			
		||||
                        if (selectedItem.type === 'line-view') {
 | 
			
		||||
                            this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y, selectedItem.x2, selectedItem.y2];
 | 
			
		||||
                            this.startingMinX2 = this.startingMinX2 !== undefined ? Math.min(this.startingMinX2, selectedItem.x2) : selectedItem.x2;
 | 
			
		||||
                            this.startingMinY2 = this.startingMinY2 !== undefined ? Math.min(this.startingMinY2, selectedItem.y2) : selectedItem.y2;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y];
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        this.startingMinX = this.startingMinX !== undefined ? Math.min(this.startingMinX, selectedItem.x) : selectedItem.x;
 | 
			
		||||
                        this.startingMinY = this.startingMinY !== undefined ? Math.min(this.startingMinY, selectedItem.y) : selectedItem.y;
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let layoutItems = this.layoutItems.map(item => {
 | 
			
		||||
                    if (this.initialPositions[item.id]) {
 | 
			
		||||
                        this.updateItemPosition(item, gridDelta);
 | 
			
		||||
                    }
 | 
			
		||||
                    return item;
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            updateItemPosition(item, gridDelta) {
 | 
			
		||||
                let startingPosition = this.initialPositions[item.id];
 | 
			
		||||
                let [startingX, startingY, startingX2, startingY2] = startingPosition;
 | 
			
		||||
 | 
			
		||||
                if (this.startingMinX + gridDelta[0] >= 0) {
 | 
			
		||||
                    if (item.x2 !== undefined) {
 | 
			
		||||
                        if (this.startingMinX2 + gridDelta[0] >= 0) {
 | 
			
		||||
                            item.x = startingX + gridDelta[0];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        item.x = startingX + gridDelta[0];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (this.startingMinY + gridDelta[1] >= 0) {
 | 
			
		||||
                    if (item.y2 !== undefined) {
 | 
			
		||||
                        if (this.startingMinY2 + gridDelta[1] >= 0) {
 | 
			
		||||
                            item.y = startingY + gridDelta[1];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        item.y = startingY + gridDelta[1];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (item.x2 !== undefined && this.startingMinX2 + gridDelta[0] >= 0 && this.startingMinX + gridDelta[0] >= 0) {
 | 
			
		||||
                    item.x2 = startingX2 + gridDelta[0];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (item.y2 !== undefined && this.startingMinY2 + gridDelta[1] >= 0 && this.startingMinY + gridDelta[1] >= 0) {
 | 
			
		||||
                    item.y2 = startingY2 + gridDelta[1];
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            endMove() {
 | 
			
		||||
                this.mutate('configuration.items', this.layoutItems);
 | 
			
		||||
                this.initialPositions = undefined;
 | 
			
		||||
                this.startingMinX = undefined;
 | 
			
		||||
                this.startingMinY = undefined;
 | 
			
		||||
                this.startingMinX2 = undefined;
 | 
			
		||||
                this.startingMinY2 = undefined;
 | 
			
		||||
            },
 | 
			
		||||
            mutate(path, value) {
 | 
			
		||||
                this.openmct.objects.mutate(this.internalDomainObject, path, value);
 | 
			
		||||
            },
 | 
			
		||||
@@ -313,11 +415,15 @@
 | 
			
		||||
                    this.objectViewMap[keyString] = true;
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            removeItem(item, index) {
 | 
			
		||||
            removeItem(selectedItems) {
 | 
			
		||||
                let indices = [];
 | 
			
		||||
                this.initSelectIndex = -1;
 | 
			
		||||
                this.layoutItems.splice(index, 1);
 | 
			
		||||
                selectedItems.forEach(selectedItem => {
 | 
			
		||||
                    indices.push(selectedItem[0].context.index);
 | 
			
		||||
                    this.untrackItem(selectedItem[0].context.layoutItem);
 | 
			
		||||
                });
 | 
			
		||||
                _.pullAt(this.layoutItems, indices);
 | 
			
		||||
                this.mutate("configuration.items", this.layoutItems);
 | 
			
		||||
                this.untrackItem(item);
 | 
			
		||||
                this.$el.click();
 | 
			
		||||
            },
 | 
			
		||||
            untrackItem(item) {
 | 
			
		||||
@@ -383,21 +489,80 @@
 | 
			
		||||
                this.mutate("configuration.items", layoutItems);
 | 
			
		||||
                this.$el.click();
 | 
			
		||||
            },
 | 
			
		||||
            orderItem(position, index) {
 | 
			
		||||
            orderItem(position, selectedItems) {
 | 
			
		||||
                let delta = ORDERS[position];
 | 
			
		||||
                let newIndex = Math.max(Math.min(index + delta, this.layoutItems.length - 1), 0);
 | 
			
		||||
                let item = this.layoutItems[index];
 | 
			
		||||
                let indices = [];
 | 
			
		||||
                let newIndex = -1;
 | 
			
		||||
                let items = [];
 | 
			
		||||
 | 
			
		||||
                if (newIndex !== index) {
 | 
			
		||||
                    this.layoutItems.splice(index, 1);
 | 
			
		||||
                    this.layoutItems.splice(newIndex, 0, item);
 | 
			
		||||
                    this.mutate('configuration.items', this.layoutItems);
 | 
			
		||||
                Object.assign(items, this.layoutItems);
 | 
			
		||||
                this.selectedLayoutItems.forEach(selectedItem => {
 | 
			
		||||
                    indices.push(this.layoutItems.indexOf(selectedItem));
 | 
			
		||||
                });
 | 
			
		||||
                indices.sort((a, b) => a - b);
 | 
			
		||||
 | 
			
		||||
                    if (this.removeSelectionListener) {
 | 
			
		||||
                        this.removeSelectionListener();
 | 
			
		||||
                        this.attachSelectionListener(newIndex);
 | 
			
		||||
                    }
 | 
			
		||||
                if (position === 'top' || position === 'up') {
 | 
			
		||||
                    indices.reverse();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (position === 'top' || position === 'bottom') {
 | 
			
		||||
                    this.moveToTopOrBottom(position, indices, items, delta);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.moveUpOrDown(position, indices, items, delta);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.mutate('configuration.items', this.layoutItems);
 | 
			
		||||
            },
 | 
			
		||||
            moveUpOrDown(position, indices, items, delta) {
 | 
			
		||||
                let previousItemIndex = -1;
 | 
			
		||||
                let newIndex = -1;
 | 
			
		||||
 | 
			
		||||
                indices.forEach((itemIndex, index) => {
 | 
			
		||||
                    let isAdjacentItemSelected = position === 'up' ?
 | 
			
		||||
                        itemIndex + 1 === previousItemIndex :
 | 
			
		||||
                        itemIndex - 1 === previousItemIndex;
 | 
			
		||||
 | 
			
		||||
                    if (index > 0 && isAdjacentItemSelected) {
 | 
			
		||||
                        if (position === 'up') {
 | 
			
		||||
                            newIndex -= 1;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            newIndex += 1;
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        newIndex = Math.max(Math.min(itemIndex + delta, this.layoutItems.length - 1), 0);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    previousItemIndex = itemIndex;
 | 
			
		||||
                    this.updateItemOrder(newIndex, itemIndex, items);
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            moveToTopOrBottom(position, indices, items, delta) {
 | 
			
		||||
                let newIndex = -1;
 | 
			
		||||
 | 
			
		||||
                indices.forEach((itemIndex, index) => {
 | 
			
		||||
                    if (index === 0) {
 | 
			
		||||
                        newIndex = Math.max(Math.min(itemIndex + delta, this.layoutItems.length - 1), 0);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (position === 'top') {
 | 
			
		||||
                            newIndex -= 1;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            newIndex += 1;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    this.updateItemOrder(newIndex, itemIndex, items);
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            updateItemOrder(newIndex, itemIndex, items) {
 | 
			
		||||
                if (newIndex !== itemIndex) {
 | 
			
		||||
                    this.layoutItems.splice(itemIndex, 1);
 | 
			
		||||
                    this.layoutItems.splice(newIndex, 0, items[itemIndex]);
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            updateTelemetryFormat(item, format) {
 | 
			
		||||
                let index = _.findIndex(this.layoutItems, item);
 | 
			
		||||
                item.format = format;
 | 
			
		||||
                this.mutate(`configuration.items[${index}]`, item);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
@@ -412,14 +577,10 @@
 | 
			
		||||
            this.composition.load();
 | 
			
		||||
        },
 | 
			
		||||
        destroyed: function () {
 | 
			
		||||
            this.openmct.off('change', this.setSelection);
 | 
			
		||||
            this.openmct.selection.off('change', this.setSelection);
 | 
			
		||||
            this.composition.off('add', this.addChild);
 | 
			
		||||
            this.composition.off('remove', this.removeChild);
 | 
			
		||||
            this.unlisten();
 | 
			
		||||
 | 
			
		||||
            if (this.removeSelectionListener) {
 | 
			
		||||
                this.removeSelectionListener();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										233
									
								
								src/plugins/displayLayout/components/EditMarquee.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,233 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
        <!-- Resize handles -->
 | 
			
		||||
        <div class="c-frame-edit" :style="style">
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--nw"
 | 
			
		||||
                 @mousedown="startResize([1,1], [-1,-1], $event)"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--ne"
 | 
			
		||||
                 @mousedown="startResize([0,1], [1,-1], $event)"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--sw"
 | 
			
		||||
                 @mousedown="startResize([1,0], [-1,1], $event)"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--se"
 | 
			
		||||
                 @mousedown="startResize([0,0], [1,1], $event)"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
 | 
			
		||||
    .c-frame-edit {
 | 
			
		||||
        // In Layouts, this is the editing rect and handles
 | 
			
		||||
        display: none; // Set to display: block in DisplayLayout.vue
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
        @include abs();
 | 
			
		||||
        border: $editMarqueeBorder;
 | 
			
		||||
 | 
			
		||||
        &__handle {
 | 
			
		||||
            $d: 6px;
 | 
			
		||||
            $o: floor($d * -0.5);
 | 
			
		||||
            background: $editFrameColorHandleFg;
 | 
			
		||||
            box-shadow: $editFrameColorHandleBg 0 0 0 2px;
 | 
			
		||||
            pointer-events: all;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            width: $d; height: $d;
 | 
			
		||||
            top: auto; right: auto; bottom: auto; left: auto;
 | 
			
		||||
 | 
			
		||||
            &:before {
 | 
			
		||||
                // Extended hit area
 | 
			
		||||
                @include abs(-10px);
 | 
			
		||||
                content: '';
 | 
			
		||||
                display: block;
 | 
			
		||||
                z-index: 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:hover {
 | 
			
		||||
                background: $editUIColor;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--nwse {
 | 
			
		||||
                cursor: nwse-resize;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--nw {
 | 
			
		||||
                cursor: nw-resize;
 | 
			
		||||
                left: $o; top: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--ne {
 | 
			
		||||
                cursor: ne-resize;
 | 
			
		||||
                right: $o; top: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--se {
 | 
			
		||||
                cursor: se-resize;
 | 
			
		||||
                right: $o; bottom: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--sw {
 | 
			
		||||
                cursor: sw-resize;
 | 
			
		||||
                left: $o; bottom: $o;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import LayoutDrag from './../LayoutDrag'
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        props: {
 | 
			
		||||
            selectedLayoutItems: Array,
 | 
			
		||||
            gridSize: Array
 | 
			
		||||
        },        
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                dragPosition: undefined
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
            style() {
 | 
			
		||||
                let x = Number.POSITIVE_INFINITY;
 | 
			
		||||
                let y = Number.POSITIVE_INFINITY;
 | 
			
		||||
                let width = Number.NEGATIVE_INFINITY;
 | 
			
		||||
                let height = Number.NEGATIVE_INFINITY;
 | 
			
		||||
 | 
			
		||||
                this.selectedLayoutItems.forEach(item => {
 | 
			
		||||
                    if (item.x2 !== undefined) {
 | 
			
		||||
                        let lineWidth = Math.abs(item.x - item.x2);
 | 
			
		||||
                        let lineMinX = Math.min(item.x, item.x2);
 | 
			
		||||
                        x = Math.min(lineMinX, x);
 | 
			
		||||
                        width = Math.max(lineWidth + lineMinX, width);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        x = Math.min(item.x, x);
 | 
			
		||||
                        width = Math.max(item.width + item.x, width);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (item.y2 !== undefined) {
 | 
			
		||||
                        let lineHeight = Math.abs(item.y - item.y2);
 | 
			
		||||
                        let lineMinY = Math.min(item.y, item.y2);
 | 
			
		||||
                        y = Math.min(lineMinY, y);
 | 
			
		||||
                        height = Math.max(lineHeight + lineMinY, height);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        y = Math.min(item.y, y);
 | 
			
		||||
                        height = Math.max(item.height + item.y, height);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                if (this.dragPosition) {
 | 
			
		||||
                    [x, y] = this.dragPosition.position;
 | 
			
		||||
                    [width, height] = this.dragPosition.dimensions;
 | 
			
		||||
                } else {
 | 
			
		||||
                    width = width - x;
 | 
			
		||||
                    height = height - y;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.marqueePosition = {
 | 
			
		||||
                    x: x,
 | 
			
		||||
                    y: y,
 | 
			
		||||
                    width: width,
 | 
			
		||||
                    height: height
 | 
			
		||||
                }
 | 
			
		||||
                return this.getMarqueeStyle(x, y, width, height);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        methods: {
 | 
			
		||||
            getMarqueeStyle(x, y, width, height) {
 | 
			
		||||
                return {
 | 
			
		||||
                    left: (this.gridSize[0] * x) + 'px',
 | 
			
		||||
                    top: (this.gridSize[1] * y) + 'px',
 | 
			
		||||
                    width: (this.gridSize[0] * width) + 'px',
 | 
			
		||||
                    height: (this.gridSize[1] * height) + 'px'
 | 
			
		||||
                };
 | 
			
		||||
            },
 | 
			
		||||
            updatePosition(event) {
 | 
			
		||||
                let currentPosition = [event.pageX, event.pageY];
 | 
			
		||||
                this.initialPosition = this.initialPosition || currentPosition;
 | 
			
		||||
                this.delta = currentPosition.map(function (value, index) {
 | 
			
		||||
                    return value - this.initialPosition[index];
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
            },
 | 
			
		||||
            startResize(posFactor, dimFactor, event) {
 | 
			
		||||
                document.body.addEventListener('mousemove', this.continueResize);
 | 
			
		||||
                document.body.addEventListener('mouseup', this.endResize);
 | 
			
		||||
                this.marqueeStartPosition = {
 | 
			
		||||
                    position: [this.marqueePosition.x, this.marqueePosition.y],
 | 
			
		||||
                    dimensions: [this.marqueePosition.width, this.marqueePosition.height]
 | 
			
		||||
                };
 | 
			
		||||
                this.updatePosition(event);
 | 
			
		||||
                this.activeDrag = new LayoutDrag(this.marqueeStartPosition, posFactor, dimFactor, this.gridSize);
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
            },
 | 
			
		||||
            continueResize(event) {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                this.updatePosition(event);
 | 
			
		||||
                this.dragPosition = this.activeDrag.getAdjustedPositionAndDimensions(this.delta);
 | 
			
		||||
            },
 | 
			
		||||
            endResize(event) {
 | 
			
		||||
                document.body.removeEventListener('mousemove', this.continueResize);
 | 
			
		||||
                document.body.removeEventListener('mouseup', this.endResize);
 | 
			
		||||
                this.continueResize(event);
 | 
			
		||||
 | 
			
		||||
                let marqueeStartWidth = this.marqueeStartPosition.dimensions[0];
 | 
			
		||||
                let marqueeStartHeight = this.marqueeStartPosition.dimensions[1];
 | 
			
		||||
                let marqueeStartX = this.marqueeStartPosition.position[0];
 | 
			
		||||
                let marqueeStartY = this.marqueeStartPosition.position[1];
 | 
			
		||||
 | 
			
		||||
                let marqueeEndX = this.dragPosition.position[0];
 | 
			
		||||
                let marqueeEndY = this.dragPosition.position[1];
 | 
			
		||||
                let marqueeEndWidth = this.dragPosition.dimensions[0];
 | 
			
		||||
                let marqueeEndHeight = this.dragPosition.dimensions[1];
 | 
			
		||||
 | 
			
		||||
                let scaleWidth =  marqueeEndWidth / marqueeStartWidth;
 | 
			
		||||
                let scaleHeight =  marqueeEndHeight / marqueeStartHeight;
 | 
			
		||||
 | 
			
		||||
                let marqueeStart = {
 | 
			
		||||
                    x: marqueeStartX,
 | 
			
		||||
                    y: marqueeStartY,
 | 
			
		||||
                    height: marqueeStartWidth,
 | 
			
		||||
                    width: marqueeStartHeight
 | 
			
		||||
                };
 | 
			
		||||
                let marqueeEnd = {
 | 
			
		||||
                    x: marqueeEndX,
 | 
			
		||||
                    y: marqueeEndY,
 | 
			
		||||
                    width: marqueeEndWidth,
 | 
			
		||||
                    height: marqueeEndHeight
 | 
			
		||||
                };
 | 
			
		||||
                let marqueeOffset = {
 | 
			
		||||
                    x: marqueeEnd.x - marqueeStart.x,
 | 
			
		||||
                    y: marqueeEnd.y - marqueeStart.y
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                this.$emit('endResize', scaleWidth, scaleHeight, marqueeStart, marqueeOffset);
 | 
			
		||||
                this.dragPosition = undefined;
 | 
			
		||||
                this.initialPosition = undefined;
 | 
			
		||||
                this.marqueeStartPosition = undefined;
 | 
			
		||||
                this.delta = undefined;
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
@@ -23,7 +23,8 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <layout-frame :item="item"
 | 
			
		||||
                  :grid-size="gridSize"
 | 
			
		||||
                  @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
                  @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                  @endMove="() => $emit('endMove')">
 | 
			
		||||
        <div class="c-image-view"
 | 
			
		||||
             :style="style">
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -56,8 +57,7 @@
 | 
			
		||||
                y: 1,
 | 
			
		||||
                width: 10,
 | 
			
		||||
                height: 5,
 | 
			
		||||
                url: element.url,
 | 
			
		||||
                useGrid: true
 | 
			
		||||
                url: element.url
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
 
 | 
			
		||||
@@ -24,25 +24,14 @@
 | 
			
		||||
    <div class="l-layout__frame c-frame"
 | 
			
		||||
         :class="{
 | 
			
		||||
             'no-frame': !item.hasFrame,
 | 
			
		||||
             'u-inspectable': inspectable,
 | 
			
		||||
             'is-resizing': isResizing
 | 
			
		||||
             'u-inspectable': inspectable
 | 
			
		||||
         }"
 | 
			
		||||
         :style="style">
 | 
			
		||||
 | 
			
		||||
        <slot></slot>
 | 
			
		||||
 | 
			
		||||
        <!-- Drag handles -->
 | 
			
		||||
        <div class="c-frame-edit">
 | 
			
		||||
            <div class="c-frame-edit__move"
 | 
			
		||||
                 @mousedown="startDrag([1,1], [0,0], $event, 'move')"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--nw"
 | 
			
		||||
                 @mousedown="startDrag([1,1], [-1,-1], $event, 'resize')"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--ne"
 | 
			
		||||
                 @mousedown="startDrag([0,1], [1,-1], $event, 'resize')"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--sw"
 | 
			
		||||
                 @mousedown="startDrag([1,0], [-1,1], $event, 'resize')"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--se"
 | 
			
		||||
                 @mousedown="startDrag([0,0], [1,1], $event, 'resize')"></div>
 | 
			
		||||
        <div class="c-frame-edit__move"
 | 
			
		||||
             @mousedown="startMove([1,1], [0,0], $event)">
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -50,7 +39,7 @@
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
 | 
			
		||||
    /******************************* FRAME */
 | 
			
		||||
    /******************* FRAME */
 | 
			
		||||
    .c-frame {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
@@ -59,124 +48,15 @@
 | 
			
		||||
        > *:first-child {
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:not(.no-frame) {
 | 
			
		||||
            background: $colorBodyBg;
 | 
			
		||||
            border: $browseFrameBorder;
 | 
			
		||||
            padding: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .c-frame-edit {
 | 
			
		||||
        // In Layouts, this is the editing rect and handles
 | 
			
		||||
        // In Fixed Position, this is a wrapper element
 | 
			
		||||
        @include abs();
 | 
			
		||||
    .c-frame-edit__move {
 | 
			
		||||
        display: none;
 | 
			
		||||
 | 
			
		||||
        &__move {
 | 
			
		||||
            @include abs();
 | 
			
		||||
            cursor: move;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__handle {
 | 
			
		||||
            $d: 6px;
 | 
			
		||||
            $o: floor($d * -0.5);
 | 
			
		||||
            background: $editFrameColorHandleFg;
 | 
			
		||||
            box-shadow: $editFrameColorHandleBg 0 0 0 2px;
 | 
			
		||||
            display: none; // Set to block via s-selected selector
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            width: $d; height: $d;
 | 
			
		||||
            top: auto; right: auto; bottom: auto; left: auto;
 | 
			
		||||
 | 
			
		||||
            &:before {
 | 
			
		||||
                // Extended hit area
 | 
			
		||||
                @include abs(-10px);
 | 
			
		||||
                content: '';
 | 
			
		||||
                display: block;
 | 
			
		||||
                z-index: 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:hover {
 | 
			
		||||
                background: $editUIColor;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--nwse {
 | 
			
		||||
                cursor: nwse-resize;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--nw {
 | 
			
		||||
                cursor: nw-resize;
 | 
			
		||||
                left: $o; top: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--ne {
 | 
			
		||||
                cursor: ne-resize;
 | 
			
		||||
                right: $o; top: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--se {
 | 
			
		||||
                cursor: se-resize;
 | 
			
		||||
                right: $o; bottom: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--sw {
 | 
			
		||||
                cursor: sw-resize;
 | 
			
		||||
                left: $o; bottom: $o;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .c-so-view.has-complex-content + .c-frame-edit {
 | 
			
		||||
        // Target frames that hold domain objects that include header elements, as opposed to drawing and alpha objects
 | 
			
		||||
        // Make the __move element a more affordable drag UI element
 | 
			
		||||
        .c-frame-edit__move {
 | 
			
		||||
            @include userSelectNone();
 | 
			
		||||
            background: $editFrameMovebarColorBg;
 | 
			
		||||
            box-shadow: rgba(black, 0.2) 0 1px;
 | 
			
		||||
            bottom: auto;
 | 
			
		||||
            height: 0; // Height is set on hover on s-selected.c-frame
 | 
			
		||||
            opacity: 0.8;
 | 
			
		||||
            max-height: 100%;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
            text-align: center;
 | 
			
		||||
 | 
			
		||||
            &:before {
 | 
			
		||||
                // Grippy
 | 
			
		||||
                $h: 4px;
 | 
			
		||||
                $tbOffset: ($editFrameMovebarH - $h) / 2;
 | 
			
		||||
                $lrOffset: 25%;
 | 
			
		||||
                @include grippy($editFrameMovebarColorFg);
 | 
			
		||||
                content: '';
 | 
			
		||||
                display: block;
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                top: $tbOffset; right: $lrOffset; bottom: $tbOffset; left: $lrOffset;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:hover {
 | 
			
		||||
                background: $editFrameHovMovebarColorBg;
 | 
			
		||||
                &:before { @include grippy($editFrameHovMovebarColorFg); }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .is-editing {
 | 
			
		||||
        /******************* STYLES FOR C-FRAME WHILE EDITING */
 | 
			
		||||
        .c-frame {
 | 
			
		||||
            $moveBarOutDelay: 500ms;
 | 
			
		||||
            &.no-frame {
 | 
			
		||||
                border: $editFrameBorder; // Base border style for a frame element while editing.
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &-edit {
 | 
			
		||||
                display: contents;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &-edit__move,
 | 
			
		||||
            .c-so-view {
 | 
			
		||||
                transition: $transOut;
 | 
			
		||||
                transition-delay: $moveBarOutDelay;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:not([s-selected]) {
 | 
			
		||||
                &:hover {
 | 
			
		||||
                    border: $editFrameBorderHov;
 | 
			
		||||
@@ -188,37 +68,110 @@
 | 
			
		||||
                border: $editFrameSelectedBorder;
 | 
			
		||||
                box-shadow: $editFrameSelectedShdw;
 | 
			
		||||
 | 
			
		||||
                > .c-frame-edit {
 | 
			
		||||
                    [class*='__handle'] {
 | 
			
		||||
                .c-frame-edit__move {
 | 
			
		||||
                    cursor: move;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /******************* DEFAULT STYLES FOR -EDIT__MOVE */
 | 
			
		||||
        // All object types
 | 
			
		||||
        .c-frame-edit__move {
 | 
			
		||||
            @include abs();
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Has-complex-content objects
 | 
			
		||||
        .c-so-view.has-complex-content {
 | 
			
		||||
            transition: $transOut;
 | 
			
		||||
            transition-delay: $moveBarOutDelay;
 | 
			
		||||
 | 
			
		||||
            > .c-so-view__local-controls {
 | 
			
		||||
                transition: transform 250ms ease-in-out;
 | 
			
		||||
                transition-delay: $moveBarOutDelay;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            + .c-frame-edit__move {
 | 
			
		||||
                display: none;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .l-layout {
 | 
			
		||||
            /******************* 0 - 1 ITEM SELECTED */
 | 
			
		||||
            &:not(.is-multi-selected) {
 | 
			
		||||
                > .l-layout__frame[s-selected] {
 | 
			
		||||
                    > .c-so-view.has-complex-content {
 | 
			
		||||
                        > .c-so-view__local-controls {
 | 
			
		||||
                            transition: transform $transOutTime ease-in-out;
 | 
			
		||||
                            transition-delay: $moveBarOutDelay;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        + .c-frame-edit__move {
 | 
			
		||||
                            transition: $transOut;
 | 
			
		||||
                            transition-delay: $moveBarOutDelay;
 | 
			
		||||
                            @include userSelectNone();
 | 
			
		||||
                            background: $editFrameMovebarColorBg;
 | 
			
		||||
                            box-shadow: rgba(black, 0.2) 0 1px;
 | 
			
		||||
                            bottom: auto;
 | 
			
		||||
                            display: block;
 | 
			
		||||
                            height: 0; // Height is set on hover below
 | 
			
		||||
                            opacity: 0.8;
 | 
			
		||||
                            max-height: 100%;
 | 
			
		||||
                            overflow: hidden;
 | 
			
		||||
                            text-align: center;
 | 
			
		||||
 | 
			
		||||
                            &:before {
 | 
			
		||||
                                // Grippy
 | 
			
		||||
                                $h: 4px;
 | 
			
		||||
                                $tbOffset: ($editFrameMovebarH - $h) / 2;
 | 
			
		||||
                                $lrOffset: 25%;
 | 
			
		||||
                                @include grippy($editFrameMovebarColorFg);
 | 
			
		||||
                                content: '';
 | 
			
		||||
                                display: block;
 | 
			
		||||
                                position: absolute;
 | 
			
		||||
                                top: $tbOffset;
 | 
			
		||||
                                right: $lrOffset;
 | 
			
		||||
                                bottom: $tbOffset;
 | 
			
		||||
                                left: $lrOffset;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    &:hover {
 | 
			
		||||
                        > .c-so-view.has-complex-content {
 | 
			
		||||
                            transition: $transIn;
 | 
			
		||||
                            transition-delay: 0s;
 | 
			
		||||
                            padding-top: $editFrameMovebarH + $interiorMarginSm;
 | 
			
		||||
 | 
			
		||||
                            > .c-so-view__local-controls {
 | 
			
		||||
                                transform: translateY($editFrameMovebarH);
 | 
			
		||||
                                transition: transform $transInTime ease-in-out;
 | 
			
		||||
                                transition-delay: 0s;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            + .c-frame-edit__move {
 | 
			
		||||
                                transition: $transIn;
 | 
			
		||||
                                transition-delay: 0s;
 | 
			
		||||
                                height: $editFrameMovebarH;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /******************* > 1 ITEMS SELECTED */
 | 
			
		||||
            &.is-multi-selected {
 | 
			
		||||
                .l-layout__frame[s-selected] {
 | 
			
		||||
                    > .c-so-view.has-complex-content + .c-frame-edit__move {
 | 
			
		||||
                        display: block;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .l-layout__frame:not(.is-resizing) {
 | 
			
		||||
            // Show and animate the __move bar for sub-object views with complex content
 | 
			
		||||
            &:hover > .c-so-view.has-complex-content {
 | 
			
		||||
                // Move content down so the __move bar doesn't cover it.
 | 
			
		||||
                padding-top: $editFrameMovebarH;
 | 
			
		||||
                transition: $transIn;
 | 
			
		||||
 | 
			
		||||
                &.c-so-view--no-frame {
 | 
			
		||||
                    // Move content down with a bit more space
 | 
			
		||||
                    padding-top: $editFrameMovebarH + $interiorMarginSm;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Show the move bar
 | 
			
		||||
                + .c-frame-edit .c-frame-edit__move {
 | 
			
		||||
                    height: $editFrameMovebarH;
 | 
			
		||||
                    transition: $transIn;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import LayoutDrag from './../LayoutDrag'
 | 
			
		||||
 | 
			
		||||
@@ -228,21 +181,9 @@
 | 
			
		||||
            item: Object,
 | 
			
		||||
            gridSize: Array
 | 
			
		||||
        },
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                dragPosition: undefined,
 | 
			
		||||
                isResizing: undefined
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
            style() {
 | 
			
		||||
                let {x, y, width, height} = this.item;
 | 
			
		||||
 | 
			
		||||
                if (this.dragPosition) {
 | 
			
		||||
                    [x, y] = this.dragPosition.position;
 | 
			
		||||
                    [width, height] = this.dragPosition.dimensions;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    left: (this.gridSize[0] * x) + 'px',
 | 
			
		||||
                    top: (this.gridSize[1] * y) + 'px',
 | 
			
		||||
@@ -264,36 +205,40 @@
 | 
			
		||||
                    return value - this.initialPosition[index];
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
            },
 | 
			
		||||
            startDrag(posFactor, dimFactor, event, type) {
 | 
			
		||||
                document.body.addEventListener('mousemove', this.continueDrag);
 | 
			
		||||
                document.body.addEventListener('mouseup', this.endDrag);
 | 
			
		||||
 | 
			
		||||
            startMove(posFactor, dimFactor, event) {
 | 
			
		||||
                document.body.addEventListener('mousemove', this.continueMove);
 | 
			
		||||
                document.body.addEventListener('mouseup', this.endMove);
 | 
			
		||||
                this.dragPosition = {
 | 
			
		||||
                    position: [this.item.x, this.item.y],
 | 
			
		||||
                    dimensions: [this.item.width, this.item.height]
 | 
			
		||||
                    position: [this.item.x, this.item.y]
 | 
			
		||||
                };
 | 
			
		||||
                this.updatePosition(event);
 | 
			
		||||
                this.activeDrag = new LayoutDrag(this.dragPosition, posFactor, dimFactor, this.gridSize);
 | 
			
		||||
                this.isResizing = type === 'resize';
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
            },
 | 
			
		||||
            continueDrag(event) {
 | 
			
		||||
            continueMove(event) {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                this.updatePosition(event);
 | 
			
		||||
                this.dragPosition = this.activeDrag.getAdjustedPosition(this.delta);
 | 
			
		||||
                let newPosition = this.activeDrag.getAdjustedPosition(this.delta);
 | 
			
		||||
 | 
			
		||||
                if (!_.isEqual(newPosition, this.dragPosition)) {
 | 
			
		||||
                    this.dragPosition = newPosition;
 | 
			
		||||
                    this.$emit('move', this.toGridDelta(this.delta));
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            endDrag(event) {
 | 
			
		||||
                document.body.removeEventListener('mousemove', this.continueDrag);
 | 
			
		||||
                document.body.removeEventListener('mouseup', this.endDrag);
 | 
			
		||||
                this.continueDrag(event);
 | 
			
		||||
                let [x, y] = this.dragPosition.position;
 | 
			
		||||
                let [width, height] = this.dragPosition.dimensions;
 | 
			
		||||
                this.$emit('endDrag', this.item, {x, y, width, height});
 | 
			
		||||
            endMove(event) {
 | 
			
		||||
                document.body.removeEventListener('mousemove', this.continueMove);
 | 
			
		||||
                document.body.removeEventListener('mouseup', this.endMove);
 | 
			
		||||
                this.continueMove(event);
 | 
			
		||||
                this.$emit('endMove');
 | 
			
		||||
                this.dragPosition = undefined;
 | 
			
		||||
                this.initialPosition = undefined;
 | 
			
		||||
                this.delta = undefined;
 | 
			
		||||
                this.isResizing = undefined;
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
            },
 | 
			
		||||
            toGridDelta(pixelDelta) {
 | 
			
		||||
                return pixelDelta.map((v, i) => {
 | 
			
		||||
                    return Math.round(v / this.gridSize[i]);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -30,9 +30,9 @@
 | 
			
		||||
            </line>
 | 
			
		||||
        </svg>
 | 
			
		||||
 | 
			
		||||
        <div class="c-frame-edit">
 | 
			
		||||
            <div class="c-frame-edit__move"
 | 
			
		||||
                 @mousedown="startDrag($event)"></div>
 | 
			
		||||
        <div class="c-frame-edit__move"
 | 
			
		||||
             @mousedown="startDrag($event)"></div>
 | 
			
		||||
        <div class="c-frame-edit" v-if="showFrameEdit">
 | 
			
		||||
            <div class="c-frame-edit__handle"
 | 
			
		||||
                 :class="startHandleClass"
 | 
			
		||||
                 @mousedown="startDrag($event, 'start')"></div>
 | 
			
		||||
@@ -66,8 +66,7 @@
 | 
			
		||||
                y: 10,
 | 
			
		||||
                x2: 10,
 | 
			
		||||
                y2: 5,
 | 
			
		||||
                stroke: '#717171',
 | 
			
		||||
                useGrid: true
 | 
			
		||||
                stroke: '#717171'
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
@@ -76,24 +75,31 @@
 | 
			
		||||
            gridSize: Array,
 | 
			
		||||
            initSelect: Boolean,
 | 
			
		||||
            index: Number,
 | 
			
		||||
            multiSelect: Boolean
 | 
			
		||||
        },
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                dragPosition: undefined
 | 
			
		||||
                dragPosition: undefined,
 | 
			
		||||
                dragging: undefined,
 | 
			
		||||
                selection: []
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
            showFrameEdit() {
 | 
			
		||||
                let layoutItem = this.selection.length > 0 && this.selection[0][0].context.layoutItem;
 | 
			
		||||
                return !this.multiSelect && layoutItem && layoutItem.id === this.item.id;
 | 
			
		||||
            },
 | 
			
		||||
            position() {
 | 
			
		||||
                let {x, y, x2, y2} = this.item;
 | 
			
		||||
                if (this.dragPosition) {
 | 
			
		||||
                if (this.dragging && this.dragPosition) {
 | 
			
		||||
                    ({x, y, x2, y2} = this.dragPosition);
 | 
			
		||||
                }
 | 
			
		||||
                return {x, y, x2, y2};
 | 
			
		||||
            },
 | 
			
		||||
            style() {
 | 
			
		||||
                let {x, y, x2, y2} = this.position;
 | 
			
		||||
                let width = this.gridSize[0] * Math.abs(x - x2);
 | 
			
		||||
                let height = this.gridSize[1] * Math.abs(y - y2);
 | 
			
		||||
                let width = Math.max(this.gridSize[0] * Math.abs(x - x2), 1);
 | 
			
		||||
                let height = Math.max(this.gridSize[1] * Math.abs(y - y2), 1);
 | 
			
		||||
                let left = this.gridSize[0] * Math.min(x, x2);
 | 
			
		||||
                let top = this.gridSize[1] * Math.min(y, y2);
 | 
			
		||||
                return {
 | 
			
		||||
@@ -175,13 +181,27 @@
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                let pxDeltaX = this.startPosition[0] - event.pageX;
 | 
			
		||||
                let pxDeltaY = this.startPosition[1] - event.pageY;
 | 
			
		||||
                this.dragPosition = this.calculateDragPosition(pxDeltaX, pxDeltaY);
 | 
			
		||||
                let newPosition = this.calculateDragPosition(pxDeltaX, pxDeltaY);
 | 
			
		||||
 | 
			
		||||
                if (!this.dragging) {
 | 
			
		||||
                    if (!_.isEqual(newPosition, this.dragPosition)) {
 | 
			
		||||
                        let gridDelta = [event.pageX - this.startPosition[0], event.pageY - this.startPosition[1]];
 | 
			
		||||
                        this.dragPosition = newPosition;
 | 
			
		||||
                        this.$emit('move', this.toGridDelta(gridDelta));
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.dragPosition = newPosition;
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            endDrag(event) {
 | 
			
		||||
                document.body.removeEventListener('mousemove', this.continueDrag);
 | 
			
		||||
                document.body.removeEventListener('mouseup', this.endDrag);
 | 
			
		||||
                let {x, y, x2, y2} = this.dragPosition;
 | 
			
		||||
                this.$emit('endDrag', this.item, {x, y, x2, y2});
 | 
			
		||||
                if (!this.dragging) {
 | 
			
		||||
                    this.$emit('endMove');
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.$emit('endLineResize', this.item, {x, y, x2, y2});
 | 
			
		||||
                }
 | 
			
		||||
                this.dragPosition = undefined;
 | 
			
		||||
                this.dragging = undefined;
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
@@ -191,6 +211,7 @@
 | 
			
		||||
                let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]?
 | 
			
		||||
                let {x, y, x2, y2} = this.item;
 | 
			
		||||
                let dragPosition = {x, y, x2, y2};
 | 
			
		||||
 | 
			
		||||
                if (this.dragging === 'start') {
 | 
			
		||||
                    dragPosition.x -= gridDeltaX;
 | 
			
		||||
                    dragPosition.y -= gridDeltaY;
 | 
			
		||||
@@ -205,6 +226,14 @@
 | 
			
		||||
                    dragPosition.y2 -= gridDeltaY;
 | 
			
		||||
                }
 | 
			
		||||
                return dragPosition;
 | 
			
		||||
            },
 | 
			
		||||
            setSelection(selection) {
 | 
			
		||||
                this.selection = selection;
 | 
			
		||||
            },
 | 
			
		||||
            toGridDelta(pixelDelta) {
 | 
			
		||||
                return pixelDelta.map((v, i) => {
 | 
			
		||||
                    return Math.round(v / this.gridSize[i]);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        watch: {
 | 
			
		||||
@@ -217,6 +246,7 @@
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
            this.openmct.selection.on('change', this.setSelection);
 | 
			
		||||
            this.context = {
 | 
			
		||||
                layoutItem: this.item,
 | 
			
		||||
                index: this.index
 | 
			
		||||
@@ -228,6 +258,7 @@
 | 
			
		||||
            if (this.removeSelectable) {
 | 
			
		||||
                this.removeSelectable();
 | 
			
		||||
            }
 | 
			
		||||
            this.openmct.selection.off('change', this.setSelection);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 </script>
 | 
			
		||||
 
 | 
			
		||||
@@ -22,10 +22,12 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <layout-frame :item="item"
 | 
			
		||||
                  :grid-size="gridSize"
 | 
			
		||||
                  @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
                  :title="domainObject && domainObject.name"
 | 
			
		||||
                  @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                  @endMove="() => $emit('endMove')">
 | 
			
		||||
        <object-frame v-if="domainObject"
 | 
			
		||||
                      :domain-object="domainObject"
 | 
			
		||||
                      :object-path="objectPath"
 | 
			
		||||
                      :object-path="currentObjectPath"
 | 
			
		||||
                      :has-frame="item.hasFrame"
 | 
			
		||||
                      :show-edit-view="false"
 | 
			
		||||
                      ref="objectFrame">
 | 
			
		||||
@@ -66,11 +68,10 @@
 | 
			
		||||
                x: position[0],
 | 
			
		||||
                y: position[1],
 | 
			
		||||
                identifier: domainObject.identifier,
 | 
			
		||||
                hasFrame: hasFrameByDefault(domainObject.type),
 | 
			
		||||
                useGrid: true
 | 
			
		||||
                hasFrame: hasFrameByDefault(domainObject.type)
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        inject: ['openmct', 'objectPath'],
 | 
			
		||||
        props: {
 | 
			
		||||
            item: Object,
 | 
			
		||||
            gridSize: Array,
 | 
			
		||||
@@ -80,7 +81,7 @@
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                domainObject: undefined,
 | 
			
		||||
                objectPath: []
 | 
			
		||||
                currentObjectPath: []
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        components: {
 | 
			
		||||
@@ -99,7 +100,7 @@
 | 
			
		||||
        methods: {
 | 
			
		||||
            setObject(domainObject) {
 | 
			
		||||
                this.domainObject = domainObject;
 | 
			
		||||
                this.objectPath = [this.domainObject].concat(this.openmct.router.path);
 | 
			
		||||
                this.currentObjectPath = [this.domainObject].concat(this.objectPath.slice());
 | 
			
		||||
                this.$nextTick(function () {
 | 
			
		||||
                    let childContext = this.$refs.objectFrame.getSelectionContext();
 | 
			
		||||
                    childContext.item = domainObject;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,10 +23,12 @@
 | 
			
		||||
 <template>
 | 
			
		||||
     <layout-frame :item="item"
 | 
			
		||||
                   :grid-size="gridSize"
 | 
			
		||||
                   @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
                   @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                   @endMove="() => $emit('endMove')">
 | 
			
		||||
        <div class="c-telemetry-view"
 | 
			
		||||
             :style="styleObject"
 | 
			
		||||
             v-if="domainObject">
 | 
			
		||||
             v-if="domainObject"
 | 
			
		||||
             @contextmenu.prevent="showContextMenu">
 | 
			
		||||
            <div v-if="showLabel"
 | 
			
		||||
                  class="c-telemetry-view__label">
 | 
			
		||||
                <div class="c-telemetry-view__label-text">{{ domainObject.name }}</div>
 | 
			
		||||
@@ -78,9 +80,11 @@
 | 
			
		||||
 | 
			
		||||
 <script>
 | 
			
		||||
    import LayoutFrame from './LayoutFrame.vue'
 | 
			
		||||
    import printj from 'printj'
 | 
			
		||||
 | 
			
		||||
    const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
 | 
			
		||||
          DEFAULT_POSITION = [1, 1];
 | 
			
		||||
          DEFAULT_POSITION = [1, 1],
 | 
			
		||||
          CONTEXT_MENU_ACTIONS = ['viewHistoricalData'];
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
        makeDefinition(openmct, gridSize, domainObject, position) {
 | 
			
		||||
@@ -96,13 +100,12 @@
 | 
			
		||||
                displayMode: 'all',
 | 
			
		||||
                value: metadata.getDefaultDisplayValue(),
 | 
			
		||||
                stroke: "transparent",
 | 
			
		||||
                fill: "",
 | 
			
		||||
                fill: "transparent",
 | 
			
		||||
                color: "",
 | 
			
		||||
                size: "13px",
 | 
			
		||||
                useGrid: true
 | 
			
		||||
                size: "13px"
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        inject: ['openmct', 'objectPath'],
 | 
			
		||||
        props: {
 | 
			
		||||
            item: Object,
 | 
			
		||||
            gridSize: Array,
 | 
			
		||||
@@ -143,6 +146,10 @@
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (this.item.format) {
 | 
			
		||||
                    return printj.sprintf(this.item.format, this.datum[this.valueMetadata.key]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return this.valueFormatter && this.valueFormatter.format(this.datum);
 | 
			
		||||
            },
 | 
			
		||||
            telemetryClass() {
 | 
			
		||||
@@ -158,7 +165,8 @@
 | 
			
		||||
            return {
 | 
			
		||||
                datum: undefined,
 | 
			
		||||
                formats: undefined,
 | 
			
		||||
                domainObject: undefined
 | 
			
		||||
                domainObject: undefined,
 | 
			
		||||
                currentObjectPath: undefined
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        watch: {
 | 
			
		||||
@@ -168,6 +176,9 @@
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.context.index = newIndex;
 | 
			
		||||
            },
 | 
			
		||||
            item(newItem) {
 | 
			
		||||
                this.context.layoutItem = newItem;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        methods: {
 | 
			
		||||
@@ -176,7 +187,8 @@
 | 
			
		||||
                let options = {
 | 
			
		||||
                    start: bounds.start,
 | 
			
		||||
                    end: bounds.end,
 | 
			
		||||
                    size: 1
 | 
			
		||||
                    size: 1,
 | 
			
		||||
                    strategy: 'latest'
 | 
			
		||||
                };
 | 
			
		||||
                this.openmct.telemetry.request(this.domainObject, options)
 | 
			
		||||
                    .then(data => {
 | 
			
		||||
@@ -209,19 +221,30 @@
 | 
			
		||||
            },
 | 
			
		||||
            setObject(domainObject) {
 | 
			
		||||
                this.domainObject = domainObject;
 | 
			
		||||
                this.keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
 | 
			
		||||
                this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
 | 
			
		||||
                this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.domainObject);
 | 
			
		||||
                this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
 | 
			
		||||
                this.requestHistoricalData();
 | 
			
		||||
                this.subscribeToObject();
 | 
			
		||||
 | 
			
		||||
                this.currentObjectPath = this.objectPath.slice();
 | 
			
		||||
                this.currentObjectPath.unshift(this.domainObject);
 | 
			
		||||
 | 
			
		||||
                this.context = {
 | 
			
		||||
                    item: domainObject,
 | 
			
		||||
                    layoutItem: this.item,
 | 
			
		||||
                    index: this.index
 | 
			
		||||
                    index: this.index,
 | 
			
		||||
                    updateTelemetryFormat: this.updateTelemetryFormat
 | 
			
		||||
                };
 | 
			
		||||
                this.removeSelectable = this.openmct.selection.selectable(
 | 
			
		||||
                    this.$el, this.context, this.initSelect);
 | 
			
		||||
            },
 | 
			
		||||
            updateTelemetryFormat(format) {
 | 
			
		||||
                this.$emit('formatChanged', this.item, format);
 | 
			
		||||
            },
 | 
			
		||||
            showContextMenu(event) {
 | 
			
		||||
                this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,8 @@
 | 
			
		||||
 <template>
 | 
			
		||||
    <layout-frame :item="item"
 | 
			
		||||
                  :grid-size="gridSize"
 | 
			
		||||
                  @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
                  @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                  @endMove="() => $emit('endMove')">
 | 
			
		||||
        <div class="c-text-view"
 | 
			
		||||
             :style="style">
 | 
			
		||||
            {{ item.text }}
 | 
			
		||||
@@ -59,8 +60,7 @@
 | 
			
		||||
                y: 1,
 | 
			
		||||
                width: 10,
 | 
			
		||||
                height: 5,
 | 
			
		||||
                text: element.text,
 | 
			
		||||
                useGrid: true
 | 
			
		||||
                text: element.text
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,8 @@ import Vue from 'vue'
 | 
			
		||||
import objectUtils from '../../api/objects/object-utils.js'
 | 
			
		||||
import DisplayLayoutType from './DisplayLayoutType.js'
 | 
			
		||||
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js'
 | 
			
		||||
import AlphaNumericFormatViewProvider from './AlphanumericFormatViewProvider.js'
 | 
			
		||||
 | 
			
		||||
export default function DisplayLayoutPlugin(options) {
 | 
			
		||||
    return function (openmct) {
 | 
			
		||||
        openmct.objectViews.addProvider({
 | 
			
		||||
@@ -35,7 +37,7 @@ export default function DisplayLayoutPlugin(options) {
 | 
			
		||||
            canEdit: function (domainObject) {
 | 
			
		||||
                return domainObject.type === 'layout';
 | 
			
		||||
            },
 | 
			
		||||
            view: function (domainObject) {
 | 
			
		||||
            view: function (domainObject, isEditing, objectPath) {
 | 
			
		||||
                let component;
 | 
			
		||||
                return {
 | 
			
		||||
                    show(container) {
 | 
			
		||||
@@ -47,19 +49,21 @@ export default function DisplayLayoutPlugin(options) {
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                objectUtils,
 | 
			
		||||
                                options
 | 
			
		||||
                                options,
 | 
			
		||||
                                objectPath
 | 
			
		||||
                            },
 | 
			
		||||
                            el: container,
 | 
			
		||||
                            data () {
 | 
			
		||||
                            data() {
 | 
			
		||||
                                return {
 | 
			
		||||
                                    domainObject: domainObject
 | 
			
		||||
                                }
 | 
			
		||||
                                };
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    },
 | 
			
		||||
                    getSelectionContext() {
 | 
			
		||||
                        return {
 | 
			
		||||
                            item: domainObject,
 | 
			
		||||
                            supportsMultiSelect: true,
 | 
			
		||||
                            addElement: component && component.$refs.displayLayout.addElement,
 | 
			
		||||
                            removeItem: component && component.$refs.displayLayout.removeItem,
 | 
			
		||||
                            orderItem: component && component.$refs.displayLayout.orderItem
 | 
			
		||||
@@ -75,7 +79,8 @@ export default function DisplayLayoutPlugin(options) {
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        openmct.types.addType('layout', DisplayLayoutType());
 | 
			
		||||
        openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct));
 | 
			
		||||
        openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct, options));
 | 
			
		||||
        openmct.inspectorViews.addProvider(new AlphaNumericFormatViewProvider(openmct, options));
 | 
			
		||||
        openmct.composition.addPolicy((parent, child) => {
 | 
			
		||||
            if (parent.type === 'layout' && child.type === 'folder') {
 | 
			
		||||
                return false;
 | 
			
		||||
 
 | 
			
		||||
@@ -33,23 +33,20 @@ define([
 | 
			
		||||
            key: 'filters-inspector',
 | 
			
		||||
            name: 'Filters Inspector View',
 | 
			
		||||
            canView: function (selection) {
 | 
			
		||||
                if (selection.length === 0) {
 | 
			
		||||
                if (selection.length === 0 || selection[0].length === 0) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                let object = selection[0].context.item;
 | 
			
		||||
                let object = selection[0][0].context.item;
 | 
			
		||||
 | 
			
		||||
                return object && supportedObjectTypesArray.some(type => object.type === type);
 | 
			
		||||
            },
 | 
			
		||||
            view: function (selection) {
 | 
			
		||||
                let component;
 | 
			
		||||
                let providedObject = selection[0].context.item;
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    show: function (element) {
 | 
			
		||||
                        component = new Vue({
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                providedObject
 | 
			
		||||
                                openmct
 | 
			
		||||
                            },
 | 
			
		||||
                            components: {
 | 
			
		||||
                                FiltersView: FiltersView.default
 | 
			
		||||
@@ -59,8 +56,10 @@ define([
 | 
			
		||||
                        });
 | 
			
		||||
                    },
 | 
			
		||||
                    destroy: function () {
 | 
			
		||||
                        component.$destroy();
 | 
			
		||||
                        component = undefined;
 | 
			
		||||
                        if (component) {
 | 
			
		||||
                            component.$destroy();
 | 
			
		||||
                            component = undefined;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
@@ -1,19 +1,20 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="u-contents c-filter-settings">
 | 
			
		||||
        <li class="grid-row c-filter-settings__setting"
 | 
			
		||||
    <div class="c-properties__section c-filter-settings">
 | 
			
		||||
        <li class="c-properties__row c-filter-settings__setting"
 | 
			
		||||
            v-for="(filter, index) in filterField.filters"
 | 
			
		||||
            :key="index">
 | 
			
		||||
            <div class="grid-cell label">
 | 
			
		||||
            <div class="c-properties__label label"
 | 
			
		||||
                 :disabled="useGlobal">
 | 
			
		||||
                {{ filterField.name }} =
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="grid-cell value">
 | 
			
		||||
            <div class="c-properties__value value">
 | 
			
		||||
                <!-- EDITING -->
 | 
			
		||||
                <!-- String input, editing -->
 | 
			
		||||
                <template v-if="!filter.possibleValues && isEditing">
 | 
			
		||||
                    <input class="c-input--flex"
 | 
			
		||||
                           type="text"
 | 
			
		||||
                           placeholder="Enter Value"
 | 
			
		||||
                           :id="`${filter}filterControl`"
 | 
			
		||||
                           :disabled="useGlobal"
 | 
			
		||||
                           :value="persistedValue(filter)"
 | 
			
		||||
                           @change="updateFilterValue($event, filter)">
 | 
			
		||||
                </template>
 | 
			
		||||
@@ -21,15 +22,16 @@
 | 
			
		||||
                <!-- Checkbox list, editing -->
 | 
			
		||||
                <template v-if="filter.possibleValues && isEditing">
 | 
			
		||||
                    <div class="c-checkbox-list__row"
 | 
			
		||||
                         v-for="value in filter.possibleValues"
 | 
			
		||||
                         :key="value">
 | 
			
		||||
                         v-for="option in filter.possibleValues"
 | 
			
		||||
                         :key="option.value">
 | 
			
		||||
                        <input class="c-checkbox-list__input"
 | 
			
		||||
                               type="checkbox"
 | 
			
		||||
                               :id="`${value}filterControl`"
 | 
			
		||||
                               @change="onUserSelect($event, filter.comparator, value)"
 | 
			
		||||
                               :checked="isChecked(filter.comparator, value)">
 | 
			
		||||
                               :id="`${option.value}filterControl`"
 | 
			
		||||
                               :disabled="useGlobal"
 | 
			
		||||
                               @change="updateFilterValue($event, filter.comparator, option.value)"
 | 
			
		||||
                               :checked="isChecked(filter.comparator, option.value)">
 | 
			
		||||
                        <span class="c-checkbox-list__value">
 | 
			
		||||
                            {{ value }}
 | 
			
		||||
                            {{ option.label }}
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </template>
 | 
			
		||||
@@ -42,33 +44,23 @@
 | 
			
		||||
 | 
			
		||||
                <!-- Checkbox list, NOT editing -->
 | 
			
		||||
                <template v-if="filter.possibleValues && !isEditing">
 | 
			
		||||
                    <span>{{persistedFilters[filter.comparator].join(', ')}}</span>
 | 
			
		||||
                    <span v-if="persistedFilters[filter.comparator]">
 | 
			
		||||
                        {{ getFilterLabels(filter) }}
 | 
			
		||||
                    </span>
 | 
			
		||||
                </template>
 | 
			
		||||
            </div>
 | 
			
		||||
        </li>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
 | 
			
		||||
    .c-filter-settings {
 | 
			
		||||
        &__setting {
 | 
			
		||||
            .grid-cell.label {
 | 
			
		||||
                white-space: nowrap;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
    inject: [
 | 
			
		||||
        'openmct'
 | 
			
		||||
    ],
 | 
			
		||||
    props: {
 | 
			
		||||
        filterField: Object, 
 | 
			
		||||
        filterField: Object,
 | 
			
		||||
        useGlobal: Boolean,
 | 
			
		||||
        persistedFilters: {
 | 
			
		||||
            type: Object,
 | 
			
		||||
            default: () => {
 | 
			
		||||
@@ -78,7 +70,6 @@ export default {
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            expanded: false,
 | 
			
		||||
            isEditing: this.openmct.editor.isEditing()
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -86,9 +77,6 @@ export default {
 | 
			
		||||
        toggleIsEditing(isEditing) {
 | 
			
		||||
            this.isEditing = isEditing;
 | 
			
		||||
        },
 | 
			
		||||
        onUserSelect(event, comparator, value){
 | 
			
		||||
            this.$emit('onUserSelect', this.filterField.key, comparator, value, event.target.checked);
 | 
			
		||||
        },
 | 
			
		||||
        isChecked(comparator, value) {
 | 
			
		||||
            if (this.persistedFilters[comparator] && this.persistedFilters[comparator].includes(value)) {
 | 
			
		||||
                return true;
 | 
			
		||||
@@ -99,8 +87,25 @@ export default {
 | 
			
		||||
        persistedValue(comparator) {
 | 
			
		||||
            return this.persistedFilters && this.persistedFilters[comparator];
 | 
			
		||||
        },
 | 
			
		||||
        updateFilterValue(event, comparator) {
 | 
			
		||||
            this.$emit('onTextEnter', this.filterField.key, comparator, event.target.value);
 | 
			
		||||
        updateFilterValue(event, comparator, value) {
 | 
			
		||||
            if (value !== undefined) {
 | 
			
		||||
                this.$emit('filterSelected', this.filterField.key, comparator, value, event.target.checked);
 | 
			
		||||
            } else {
 | 
			
		||||
                this.$emit('filterTextValueChanged', this.filterField.key, comparator, event.target.value);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        getFilterLabels(filter) {
 | 
			
		||||
            return this.persistedFilters[filter.comparator].reduce((accum, filterValue) => {
 | 
			
		||||
                accum.push(filter.possibleValues.reduce((label, possibleValue) => {
 | 
			
		||||
                    if (filterValue === possibleValue.value) {
 | 
			
		||||
                        label = possibleValue.label;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return label;
 | 
			
		||||
                }, ''));
 | 
			
		||||
 | 
			
		||||
                return accum;
 | 
			
		||||
            }, []).join(', ');
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <li>
 | 
			
		||||
    <li class="c-tree__item-h">
 | 
			
		||||
        <div class="c-tree__item menus-to-left"
 | 
			
		||||
             @click="toggleExpanded">
 | 
			
		||||
            <div class="c-filter-tree-item__filter-indicator"
 | 
			
		||||
                :class="{'icon-filter': hasActiveFilters }"></div>
 | 
			
		||||
            <span class="c-disclosure-triangle is-enabled flex-elem"
 | 
			
		||||
              :class="{'c-disclosure-triangle--expanded': expanded}"></span>
 | 
			
		||||
            <div class="c-tree__item__label">
 | 
			
		||||
            <div class="c-tree__item__label c-object-label">
 | 
			
		||||
                <div class="c-object-label">
 | 
			
		||||
                    <div class="c-object-label__type-icon"
 | 
			
		||||
                         :class="objectCssClass">
 | 
			
		||||
@@ -13,30 +15,47 @@
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <ul class="grid-properties" v-if="expanded">
 | 
			
		||||
            <filter-field
 | 
			
		||||
                    v-for="field in filterObject.valuesWithFilters"
 | 
			
		||||
                    :key="field.key"
 | 
			
		||||
                    :filterField="field"
 | 
			
		||||
                    :persistedFilters="persistedFilters[field.key]"
 | 
			
		||||
                    @onUserSelect="collectUserSelects"
 | 
			
		||||
                    @onTextEnter="updateTextFilter">
 | 
			
		||||
            </filter-field>
 | 
			
		||||
        </ul>
 | 
			
		||||
 | 
			
		||||
        <div v-if="expanded">
 | 
			
		||||
            <ul class="c-properties">
 | 
			
		||||
                <div class="c-properties__label span-all"
 | 
			
		||||
                     v-if="!isEditing && persistedFilters.useGlobal">
 | 
			
		||||
                    Uses global filter
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="c-properties__label span-all"
 | 
			
		||||
                     v-if="isEditing">
 | 
			
		||||
                    <toggle-switch
 | 
			
		||||
                            :id="keyString"
 | 
			
		||||
                            @change="useGlobalFilter"
 | 
			
		||||
                            :checked="persistedFilters.useGlobal">
 | 
			
		||||
                    </toggle-switch>
 | 
			
		||||
                    Use global filter
 | 
			
		||||
                </div>
 | 
			
		||||
                <filter-field
 | 
			
		||||
                        v-if="(!persistedFilters.useGlobal && !isEditing) || isEditing"
 | 
			
		||||
                        v-for="metadatum in filterObject.metadataWithFilters"
 | 
			
		||||
                        :key="metadatum.key"
 | 
			
		||||
                        :filterField="metadatum"
 | 
			
		||||
                        :useGlobal="persistedFilters.useGlobal"
 | 
			
		||||
                        :persistedFilters="updatedFilters[metadatum.key]"
 | 
			
		||||
                        @filterSelected="updateFiltersWithSelectedValue"
 | 
			
		||||
                        @filterTextValueChanged="updateFiltersWithTextValue">
 | 
			
		||||
                </filter-field>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
    </li>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import FilterField from './FilterField.vue';
 | 
			
		||||
import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
    components: {
 | 
			
		||||
        FilterField
 | 
			
		||||
        FilterField,
 | 
			
		||||
        ToggleSwitch
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
        filterObject: Object, 
 | 
			
		||||
@@ -51,43 +70,74 @@ export default {
 | 
			
		||||
        return {
 | 
			
		||||
            expanded: false,
 | 
			
		||||
            objectCssClass: undefined,
 | 
			
		||||
            updatedFilters: this.persistedFilters
 | 
			
		||||
            updatedFilters: JSON.parse(JSON.stringify(this.persistedFilters)),
 | 
			
		||||
            isEditing: this.openmct.editor.isEditing()
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    watch: {
 | 
			
		||||
        persistedFilters: {
 | 
			
		||||
            handler: function checkFilters(newpersistedFilters) {
 | 
			
		||||
                this.updatedFilters = JSON.parse(JSON.stringify(newpersistedFilters));
 | 
			
		||||
            },
 | 
			
		||||
            deep: true
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        hasActiveFilters() {
 | 
			
		||||
            // Should be true when the user has entered any filter values.
 | 
			
		||||
            return Object.values(this.persistedFilters).some(comparator => {
 | 
			
		||||
                return (typeof(comparator) === 'object' && !_.isEmpty(comparator));
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        toggleExpanded() {
 | 
			
		||||
            this.expanded = !this.expanded;
 | 
			
		||||
        },
 | 
			
		||||
        collectUserSelects(key, comparator, valueName, value) {
 | 
			
		||||
        updateFiltersWithSelectedValue(key, comparator, valueName, value) {
 | 
			
		||||
            let filterValue = this.updatedFilters[key];
 | 
			
		||||
 | 
			
		||||
            if (filterValue && filterValue[comparator]) {
 | 
			
		||||
                if (value === false) {
 | 
			
		||||
                    filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
 | 
			
		||||
                } else {
 | 
			
		||||
            if (filterValue[comparator]) {
 | 
			
		||||
                if (value === true) {
 | 
			
		||||
                    filterValue[comparator].push(valueName);
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (filterValue[comparator].length === 1) {
 | 
			
		||||
                        this.$set(this.updatedFilters, key, {});
 | 
			
		||||
                    } else {
 | 
			
		||||
                        filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if (!this.updatedFilters[key]) {
 | 
			
		||||
                    this.updatedFilters[key] = {};
 | 
			
		||||
                }
 | 
			
		||||
                this.updatedFilters[key][comparator] = [value ? valueName : undefined];
 | 
			
		||||
                this.$set(this.updatedFilters[key], comparator, [valueName]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.$emit('updateFilters', this.keyString, this.updatedFilters);
 | 
			
		||||
        },
 | 
			
		||||
        updateTextFilter(key, comparator, value) {
 | 
			
		||||
            if (!this.updatedFilters[key]) {
 | 
			
		||||
                this.updatedFilters[key] = {};
 | 
			
		||||
        updateFiltersWithTextValue(key, comparator, value) {
 | 
			
		||||
            if (value.trim() === '') {
 | 
			
		||||
                this.$set(this.updatedFilters, key, {});
 | 
			
		||||
            } else {
 | 
			
		||||
                this.$set(this.updatedFilters[key], comparator, value);
 | 
			
		||||
            }
 | 
			
		||||
            this.updatedFilters[key][comparator] = value;
 | 
			
		||||
 | 
			
		||||
            this.$emit('updateFilters', this.keyString, this.updatedFilters);
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
        useGlobalFilter(checked) {
 | 
			
		||||
            this.updatedFilters.useGlobal = checked;
 | 
			
		||||
            this.$emit('updateFilters', this.keyString, this.updatedFilters, checked);
 | 
			
		||||
        },
 | 
			
		||||
        toggleIsEditing(isEditing) {
 | 
			
		||||
            this.isEditing = isEditing;
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        let type = this.openmct.types.get(this.filterObject.domainObject.type) || {};
 | 
			
		||||
        this.keyString = this.openmct.objects.makeKeyString(this.filterObject.domainObject.identifier);
 | 
			
		||||
        this.objectCssClass = type.definition.cssClass;
 | 
			
		||||
        this.openmct.editor.on('isEditing', this.toggleIsEditing);
 | 
			
		||||
    },
 | 
			
		||||
    beforeDestroy() {
 | 
			
		||||
        this.openmct.editor.off('isEditing', this.toggleIsEditing);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,14 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <ul class="tree c-tree c-properties__section" v-if="Object.keys(children).length">
 | 
			
		||||
        <h2 class="c-properties__header">Filters</h2>
 | 
			
		||||
    <ul class="c-tree c-filter-tree" v-if="Object.keys(children).length">
 | 
			
		||||
        <h2>Data Filters</h2>
 | 
			
		||||
        <div class="c-filter-indication"
 | 
			
		||||
            v-if="hasActiveFilters">{{ label }}
 | 
			
		||||
        </div>
 | 
			
		||||
        <global-filters
 | 
			
		||||
            :globalFilters="globalFilters"
 | 
			
		||||
            :globalMetadata="globalMetadata"
 | 
			
		||||
            @persistGlobalFilters="persistGlobalFilters">
 | 
			
		||||
        </global-filters>
 | 
			
		||||
        <filter-object 
 | 
			
		||||
            v-for="(child, key) in children"
 | 
			
		||||
            :key="key"
 | 
			
		||||
@@ -12,74 +20,230 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
 | 
			
		||||
    .c-inspector {
 | 
			
		||||
        .c-filter-indication {
 | 
			
		||||
            border-radius: $smallCr;
 | 
			
		||||
            font-size: inherit;
 | 
			
		||||
            padding: $interiorMarginSm $interiorMargin;
 | 
			
		||||
            text-transform: inherit;
 | 
			
		||||
        }
 | 
			
		||||
        .c-filter-tree {
 | 
			
		||||
            // Filters UI uses a tree-based structure
 | 
			
		||||
            .c-properties {
 | 
			
		||||
                // Add extra margin to account for filter-indicator
 | 
			
		||||
                margin-left: 38px;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import FilterObject from './FilterObject.vue';
 | 
			
		||||
    import FilterObject from './FilterObject.vue';
 | 
			
		||||
    import GlobalFilters from './GlobalFilters.vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    components: {
 | 
			
		||||
        FilterObject
 | 
			
		||||
    },
 | 
			
		||||
    inject: [
 | 
			
		||||
        'openmct',
 | 
			
		||||
        'providedObject'
 | 
			
		||||
    ],
 | 
			
		||||
    data() {
 | 
			
		||||
        let persistedFilters = {};
 | 
			
		||||
    const FILTER_VIEW_TITLE = 'Filters applied';
 | 
			
		||||
    const FILTER_VIEW_TITLE_MIXED = 'Mixed filters applied';
 | 
			
		||||
    const USE_GLOBAL = 'useGlobal';
 | 
			
		||||
 | 
			
		||||
        if (this.providedObject.configuration && this.providedObject.configuration.filters) {
 | 
			
		||||
            persistedFilters = this.providedObject.configuration.filters;
 | 
			
		||||
        }
 | 
			
		||||
    export default {
 | 
			
		||||
        components: {
 | 
			
		||||
            FilterObject,
 | 
			
		||||
            GlobalFilters
 | 
			
		||||
        },
 | 
			
		||||
        inject: [
 | 
			
		||||
            'openmct'
 | 
			
		||||
        ],
 | 
			
		||||
        data() {
 | 
			
		||||
            let providedObject = this.openmct.selection.get()[0][0].context.item;
 | 
			
		||||
            let configuration = providedObject.configuration;
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            persistedFilters,
 | 
			
		||||
            children: {}
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        addChildren(child) {
 | 
			
		||||
            let keyString = this.openmct.objects.makeKeyString(child.identifier),
 | 
			
		||||
                metadata = this.openmct.telemetry.getMetadata(child),
 | 
			
		||||
                valuesWithFilters = metadata.valueMetadatas.filter((value) => value.filters),
 | 
			
		||||
                childObject = {
 | 
			
		||||
                    name: child.name,
 | 
			
		||||
                    domainObject: child,
 | 
			
		||||
                    valuesWithFilters
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
            if (childObject.valuesWithFilters.length) {
 | 
			
		||||
                this.$set(this.children, keyString, childObject);
 | 
			
		||||
            } else {
 | 
			
		||||
                return;
 | 
			
		||||
            return {
 | 
			
		||||
                persistedFilters: (configuration && configuration.filters) || {},
 | 
			
		||||
                globalFilters: (configuration && configuration.globalFilters) || {},
 | 
			
		||||
                globalMetadata: {},
 | 
			
		||||
                providedObject,
 | 
			
		||||
                children: {}
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        removeChildren(identifier) {
 | 
			
		||||
            let keyString = this.openmct.objects.makeKeyString(identifier);
 | 
			
		||||
            this.$delete(this.children, keyString);
 | 
			
		||||
            this.persistFilters(keyString);
 | 
			
		||||
        computed: {
 | 
			
		||||
            hasActiveFilters() {
 | 
			
		||||
                // Should be true when the user has entered any filter values.
 | 
			
		||||
                return Object.values(this.persistedFilters).some(filters => {
 | 
			
		||||
                    return Object.values(filters).some(comparator => {
 | 
			
		||||
                        return (typeof(comparator) === 'object' && !_.isEmpty(comparator));
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            hasMixedFilters() {
 | 
			
		||||
                // Should be true when filter values are mixed.
 | 
			
		||||
                let filtersToCompare = _.omit(this.persistedFilters[Object.keys(this.persistedFilters)[0]], [USE_GLOBAL]);
 | 
			
		||||
                return Object.values(this.persistedFilters).some(filters => {
 | 
			
		||||
                    return !_.isEqual(filtersToCompare, _.omit(filters, [USE_GLOBAL]));
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            label() {
 | 
			
		||||
                if (this.hasActiveFilters) {
 | 
			
		||||
                    if (this.hasMixedFilters) {
 | 
			
		||||
                        return FILTER_VIEW_TITLE_MIXED;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return FILTER_VIEW_TITLE;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        persistFilters(keyString, userSelects) {
 | 
			
		||||
            this.persistedFilters[keyString] = userSelects;
 | 
			
		||||
            this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
 | 
			
		||||
        },
 | 
			
		||||
        updatePersistedFilters(filters) {
 | 
			
		||||
            this.persistedFilters = filters;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    mounted(){
 | 
			
		||||
        this.composition = this.openmct.composition.get(this.providedObject);
 | 
			
		||||
        this.composition.on('add', this.addChildren);
 | 
			
		||||
        this.composition.on('remove', this.removeChildren);
 | 
			
		||||
        this.composition.load();
 | 
			
		||||
        methods: {
 | 
			
		||||
            addChildren(domainObject) {
 | 
			
		||||
                let keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
 | 
			
		||||
                let metadata = this.openmct.telemetry.getMetadata(domainObject);
 | 
			
		||||
                let metadataWithFilters = metadata.valueMetadatas.filter(value => value.filters);
 | 
			
		||||
                let hasFiltersWithKeyString = this.persistedFilters[keyString] !== undefined;
 | 
			
		||||
                let mutateFilters = false;
 | 
			
		||||
                let childObject = {
 | 
			
		||||
                    name: domainObject.name,
 | 
			
		||||
                    domainObject: domainObject,
 | 
			
		||||
                    metadataWithFilters
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
        this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
 | 
			
		||||
    },
 | 
			
		||||
    beforeDestroy() {
 | 
			
		||||
        this.composition.off('add', this.addChildren);
 | 
			
		||||
        this.composition.off('remove', this.removeChildren);
 | 
			
		||||
        this.unobserve();
 | 
			
		||||
                if (metadataWithFilters.length) {
 | 
			
		||||
                    this.$set(this.children, keyString, childObject);
 | 
			
		||||
 | 
			
		||||
                    metadataWithFilters.forEach(metadatum => {
 | 
			
		||||
                        if (!this.globalFilters[metadatum.key]) {
 | 
			
		||||
                            this.$set(this.globalFilters, metadatum.key, {});
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (!this.globalMetadata[metadatum.key]) {
 | 
			
		||||
                            this.$set(this.globalMetadata, metadatum.key, metadatum);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (!hasFiltersWithKeyString) {
 | 
			
		||||
                            if (!this.persistedFilters[keyString]) {
 | 
			
		||||
                                this.$set(this.persistedFilters, keyString, {});
 | 
			
		||||
                                this.$set(this.persistedFilters[keyString], 'useGlobal', true);
 | 
			
		||||
                                mutateFilters = true;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            this.$set(this.persistedFilters[keyString], metadatum.key, this.globalFilters[metadatum.key]);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (mutateFilters) {
 | 
			
		||||
                    this.mutateConfigurationFilters();
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            removeChildren(identifier) {
 | 
			
		||||
                let keyString = this.openmct.objects.makeKeyString(identifier);
 | 
			
		||||
                let globalFiltersToRemove = this.getGlobalFiltersToRemove(keyString);
 | 
			
		||||
 | 
			
		||||
                if (globalFiltersToRemove.length > 0) {
 | 
			
		||||
                    globalFiltersToRemove.forEach(key => {
 | 
			
		||||
                        this.$delete(this.globalFilters, key);
 | 
			
		||||
                        this.$delete(this.globalMetadata, key);
 | 
			
		||||
                    });
 | 
			
		||||
                    this.mutateConfigurationGlobalFilters();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.$delete(this.children, keyString);
 | 
			
		||||
                this.$delete(this.persistedFilters, keyString);
 | 
			
		||||
                this.mutateConfigurationFilters();
 | 
			
		||||
            },
 | 
			
		||||
            getGlobalFiltersToRemove(keyString) {
 | 
			
		||||
                let filtersToRemove = new Set();
 | 
			
		||||
 | 
			
		||||
                this.children[keyString].metadataWithFilters.forEach(metadatum => {
 | 
			
		||||
                    let keepFilter = false
 | 
			
		||||
                    Object.keys(this.children).forEach(childKeyString => {
 | 
			
		||||
                        if (childKeyString !== keyString) {
 | 
			
		||||
                            let filterMatched = this.children[childKeyString].metadataWithFilters.some(childMetadatum => childMetadatum.key === metadatum.key);
 | 
			
		||||
 | 
			
		||||
                            if (filterMatched) {
 | 
			
		||||
                                keepFilter = true;
 | 
			
		||||
                                return;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    if (!keepFilter) {
 | 
			
		||||
                        filtersToRemove.add(metadatum.key);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Array.from(filtersToRemove);
 | 
			
		||||
            },
 | 
			
		||||
            persistFilters(keyString, updatedFilters, useGlobalValues) {
 | 
			
		||||
                this.persistedFilters[keyString] = updatedFilters;
 | 
			
		||||
 | 
			
		||||
                if (useGlobalValues) {
 | 
			
		||||
                    Object.keys(this.persistedFilters[keyString]).forEach(key => {
 | 
			
		||||
                        if (typeof(this.persistedFilters[keyString][key]) === 'object') {
 | 
			
		||||
                            this.persistedFilters[keyString][key]  = this.globalFilters[key];
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            
 | 
			
		||||
                this.mutateConfigurationFilters();
 | 
			
		||||
            },
 | 
			
		||||
            updatePersistedFilters(filters) {
 | 
			
		||||
                this.persistedFilters = filters;
 | 
			
		||||
            },
 | 
			
		||||
            persistGlobalFilters(key, filters) {
 | 
			
		||||
                this.globalFilters[key] = filters[key];
 | 
			
		||||
                this.mutateConfigurationGlobalFilters();
 | 
			
		||||
                let mutateFilters = false;
 | 
			
		||||
 | 
			
		||||
                Object.keys(this.children).forEach(keyString => {
 | 
			
		||||
                    if (this.persistedFilters[keyString].useGlobal !== false && this.containsField(keyString, key)) {
 | 
			
		||||
                        if (!this.persistedFilters[keyString][key]) {
 | 
			
		||||
                            this.$set(this.persistedFilters[keyString], key, {});
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        this.$set(this.persistedFilters[keyString], key, filters[key]);
 | 
			
		||||
                        mutateFilters = true;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                if (mutateFilters) {
 | 
			
		||||
                    this.mutateConfigurationFilters();
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            updateGlobalFilters(filters) {
 | 
			
		||||
                this.globalFilters = filters;
 | 
			
		||||
            },
 | 
			
		||||
            containsField(keyString, field) {
 | 
			
		||||
                let hasField = false;
 | 
			
		||||
                this.children[keyString].metadataWithFilters.forEach(metadatum => {
 | 
			
		||||
                    if (metadatum.key === field) {
 | 
			
		||||
                        hasField = true;
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                return hasField;
 | 
			
		||||
            },
 | 
			
		||||
            mutateConfigurationFilters() {
 | 
			
		||||
                this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
 | 
			
		||||
            },
 | 
			
		||||
            mutateConfigurationGlobalFilters() {
 | 
			
		||||
                this.openmct.objects.mutate(this.providedObject, 'configuration.globalFilters', this.globalFilters);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted(){
 | 
			
		||||
            this.composition = this.openmct.composition.get(this.providedObject);
 | 
			
		||||
            this.composition.on('add', this.addChildren);
 | 
			
		||||
            this.composition.on('remove', this.removeChildren);
 | 
			
		||||
            this.composition.load();
 | 
			
		||||
            this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
 | 
			
		||||
            this.unobserveGlobalFilters = this.openmct.objects.observe(this.providedObject, 'configuration.globalFilters', this.updateGlobalFilters);
 | 
			
		||||
            this.unobserveAllMutation = this.openmct.objects.observe(this.providedObject, '*', (mutatedObject) => this.providedObject = mutatedObject);
 | 
			
		||||
        },
 | 
			
		||||
        beforeDestroy() {
 | 
			
		||||
            this.composition.off('add', this.addChildren);
 | 
			
		||||
            this.composition.off('remove', this.removeChildren);
 | 
			
		||||
            this.unobserve();
 | 
			
		||||
            this.unobserveGlobalFilters();
 | 
			
		||||
            this.unobserveAllMutation();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										135
									
								
								src/plugins/filters/components/GlobalFilters.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,135 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <li class="c-tree__item-h">
 | 
			
		||||
        <div class="c-tree__item menus-to-left"
 | 
			
		||||
            @click="toggleExpanded">
 | 
			
		||||
            <div class="c-filter-tree-item__filter-indicator"
 | 
			
		||||
                :class="{'icon-filter': hasActiveGlobalFilters }"></div>
 | 
			
		||||
            <span class="c-disclosure-triangle is-enabled flex-elem"
 | 
			
		||||
                :class="{'c-disclosure-triangle--expanded': expanded}"></span>
 | 
			
		||||
            <div class="c-tree__item__label c-object-label">
 | 
			
		||||
                <div class="c-object-label">
 | 
			
		||||
                    <div class="c-object-label__type-icon icon-gear"></div>
 | 
			
		||||
                    <div class="c-object-label__name flex-elem grows">Global Filtering</div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <ul class="c-properties" v-if="expanded">
 | 
			
		||||
            <filter-field
 | 
			
		||||
                v-for="metadatum in globalMetadata"
 | 
			
		||||
                :key="metadatum.key"
 | 
			
		||||
                :filterField="metadatum"
 | 
			
		||||
                :persistedFilters="updatedFilters[metadatum.key]"
 | 
			
		||||
                @filterSelected="updateFiltersWithSelectedValue"
 | 
			
		||||
                @filterTextValueChanged="updateFiltersWithTextValue">
 | 
			
		||||
            </filter-field>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </li>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
    .c-filter-indication {
 | 
			
		||||
        // Appears as a block element beneath tables
 | 
			
		||||
        @include userSelectNone();
 | 
			
		||||
        background: $colorFilterBg;
 | 
			
		||||
        color: $colorFilterFg;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        font-size: 0.9em;
 | 
			
		||||
        margin-top: $interiorMarginSm;
 | 
			
		||||
        padding: 2px;
 | 
			
		||||
        text-transform: uppercase;
 | 
			
		||||
 | 
			
		||||
        &:before {
 | 
			
		||||
            font-family: symbolsfont-12px;
 | 
			
		||||
            content: $glyph-icon-filter;
 | 
			
		||||
            display: block;
 | 
			
		||||
            font-size: 12px;
 | 
			
		||||
            margin-right: $interiorMarginSm;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .c-filter-tree-item {
 | 
			
		||||
        &__filter-indicator {
 | 
			
		||||
            color: $colorFilter;
 | 
			
		||||
            width: 1.2em; // Set width explicitly for layout reasons: will either have class icon-filter, or none.
 | 
			
		||||
            flex: 0 0 auto;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import FilterField from './FilterField.vue';
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        components: {
 | 
			
		||||
            FilterField
 | 
			
		||||
        },
 | 
			
		||||
        props: {
 | 
			
		||||
            globalMetadata: Object,
 | 
			
		||||
            globalFilters: {
 | 
			
		||||
                type: Object,
 | 
			
		||||
                default: () => {
 | 
			
		||||
                    return {};
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                expanded: false,
 | 
			
		||||
                updatedFilters: JSON.parse(JSON.stringify(this.globalFilters))
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
            hasActiveGlobalFilters() {
 | 
			
		||||
                return Object.values(this.globalFilters).some(field => {
 | 
			
		||||
                    return Object.values(field).some(comparator => {
 | 
			
		||||
                        return (comparator && (comparator !== '' || comparator.length > 0));
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        watch: {
 | 
			
		||||
            globalFilters: {
 | 
			
		||||
                handler: function checkFilters(newGlobalFilters) {
 | 
			
		||||
                    this.updatedFilters = JSON.parse(JSON.stringify(newGlobalFilters));
 | 
			
		||||
                },
 | 
			
		||||
                deep: true
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        methods: {
 | 
			
		||||
            toggleExpanded() {
 | 
			
		||||
                this.expanded = !this.expanded;
 | 
			
		||||
            },
 | 
			
		||||
            updateFiltersWithSelectedValue(key, comparator, valueName, value) {
 | 
			
		||||
                let filterValue = this.updatedFilters[key];
 | 
			
		||||
 | 
			
		||||
                if (filterValue[comparator]) {
 | 
			
		||||
                    if (value === true) {
 | 
			
		||||
                        filterValue[comparator].push(valueName);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (filterValue[comparator].length === 1) {
 | 
			
		||||
                            this.$set(this.updatedFilters, key, {});
 | 
			
		||||
                        } else {
 | 
			
		||||
                            filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.$set(this.updatedFilters[key], comparator, [valueName]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.$emit('persistGlobalFilters', key, this.updatedFilters);
 | 
			
		||||
            },
 | 
			
		||||
            updateFiltersWithTextValue(key, comparator, value) {
 | 
			
		||||
                if (value.trim() === '') {
 | 
			
		||||
                    this.$set(this.updatedFilters, key, {});
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.$set(this.updatedFilters[key], comparator, value);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.$emit('persistGlobalFilters', key, this.updatedFilters);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './filtersInspectorViewProvider'
 | 
			
		||||
    './FiltersInspectorViewProvider'
 | 
			
		||||
], function (
 | 
			
		||||
    FiltersInspectorViewProvider
 | 
			
		||||
) {
 | 
			
		||||
 
 | 
			
		||||
@@ -106,9 +106,6 @@
 | 
			
		||||
    .c-fl {
 | 
			
		||||
        @include abs();
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column; // TEMP: only needed to support temp-toolbar element
 | 
			
		||||
 | 
			
		||||
        > * + * {  margin-top: $interiorMargin; }
 | 
			
		||||
 | 
			
		||||
        .temp-toolbar {
 | 
			
		||||
            flex: 0 0 auto;
 | 
			
		||||
@@ -116,7 +113,8 @@
 | 
			
		||||
 | 
			
		||||
        &__container-holder {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex: 1 1 100%; // Must needs to be 100% to work
 | 
			
		||||
            flex: 1 1 100%; // Must be 100% to work
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
 | 
			
		||||
            // Columns by default
 | 
			
		||||
            flex-direction: row;
 | 
			
		||||
@@ -292,11 +290,6 @@
 | 
			
		||||
            margin-bottom: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__object-view {
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__size-indicator {
 | 
			
		||||
            $size: 35px;
 | 
			
		||||
 | 
			
		||||
@@ -422,6 +415,7 @@ import Container from '../utils/container';
 | 
			
		||||
import Frame from '../utils/frame';
 | 
			
		||||
import ResizeHandle from  './resizeHandle.vue';
 | 
			
		||||
import DropHint from './dropHint.vue';
 | 
			
		||||
import RemoveAction from '../../remove/RemoveAction.js';
 | 
			
		||||
 | 
			
		||||
const MIN_CONTAINER_SIZE = 5;
 | 
			
		||||
 | 
			
		||||
@@ -513,7 +507,7 @@ export default {
 | 
			
		||||
                remove associated domainObjects from composition
 | 
			
		||||
            */
 | 
			
		||||
            container.frames.forEach(f => {
 | 
			
		||||
                this.composition.remove({identifier: f.domainObjectIdentifier});
 | 
			
		||||
                this.removeFromComposition(f.domainObjectIdentifier);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.containers.splice(containerIndex, 1);
 | 
			
		||||
@@ -528,6 +522,7 @@ export default {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            sizeToFill(this.containers);
 | 
			
		||||
            this.setSelectionToParent();
 | 
			
		||||
            this.persist();
 | 
			
		||||
        },
 | 
			
		||||
        moveFrame(toContainerIndex, toFrameIndex, frameId, fromContainerIndex) {
 | 
			
		||||
@@ -561,20 +556,23 @@ export default {
 | 
			
		||||
        deleteFrame(frameId) {
 | 
			
		||||
            let container = this.containers
 | 
			
		||||
                .filter(c => c.frames.some(f => f.id === frameId))[0];
 | 
			
		||||
            let containerIndex = this.containers.indexOf(container);
 | 
			
		||||
            let frame = container
 | 
			
		||||
                .frames
 | 
			
		||||
                .filter((f => f.id === frameId))[0];
 | 
			
		||||
            let frameIndex = container.frames.indexOf(frame);
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
                remove associated domainObject from composition
 | 
			
		||||
            */
 | 
			
		||||
            this.composition.remove({identifier: frame.domainObjectIdentifier});
 | 
			
		||||
 | 
			
		||||
            container.frames.splice(frameIndex, 1);
 | 
			
		||||
            sizeToFill(container.frames);
 | 
			
		||||
            this.persist(containerIndex);
 | 
			
		||||
            this.removeFromComposition(frame.domainObjectIdentifier)
 | 
			
		||||
                .then(() => {
 | 
			
		||||
                    sizeToFill(container.frames)
 | 
			
		||||
                    this.setSelectionToParent();
 | 
			
		||||
                });
 | 
			
		||||
        },
 | 
			
		||||
        removeFromComposition(identifier) {
 | 
			
		||||
            return this.openmct.objects.get(identifier).then((childDomainObject) => {
 | 
			
		||||
                this.RemoveAction.removeFromComposition(this.domainObject, childDomainObject);
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        setSelectionToParent() {
 | 
			
		||||
            this.$el.click();
 | 
			
		||||
        },
 | 
			
		||||
        allowContainerDrop(event, index) {
 | 
			
		||||
            if (!event.dataTransfer.types.includes('containerid')) {
 | 
			
		||||
@@ -665,6 +663,8 @@ export default {
 | 
			
		||||
        this.composition.on('remove', this.removeChildObject);
 | 
			
		||||
        this.composition.on('add', this.addFrame);
 | 
			
		||||
 | 
			
		||||
        this.RemoveAction = new RemoveAction(this.openmct);
 | 
			
		||||
 | 
			
		||||
        this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
 | 
			
		||||
    },
 | 
			
		||||
    beforeDestroy() {
 | 
			
		||||
 
 | 
			
		||||
@@ -79,12 +79,14 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
        setSelection() {
 | 
			
		||||
            this.$nextTick(function () {
 | 
			
		||||
                let childContext = this.$refs.objectFrame.getSelectionContext();
 | 
			
		||||
                childContext.item = this.domainObject;
 | 
			
		||||
                childContext.type = 'frame';
 | 
			
		||||
                childContext.frameId = this.frame.id;
 | 
			
		||||
                this.unsubscribeSelection = this.openmct.selection.selectable(
 | 
			
		||||
                    this.$refs.frame, childContext, false);
 | 
			
		||||
                if (this.$refs && this.$refs.objectFrame) {
 | 
			
		||||
                    let childContext = this.$refs.objectFrame.getSelectionContext();
 | 
			
		||||
                    childContext.item = this.domainObject;
 | 
			
		||||
                    childContext.type = 'frame';
 | 
			
		||||
                    childContext.frameId = this.frame.id;
 | 
			
		||||
                    this.unsubscribeSelection = this.openmct.selection.selectable(
 | 
			
		||||
                        this.$refs.frame, childContext, false);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        initDrag(event) {
 | 
			
		||||
 
 | 
			
		||||
@@ -79,10 +79,12 @@ export default {
 | 
			
		||||
    mounted() {
 | 
			
		||||
        document.addEventListener('dragstart', this.setDragging);
 | 
			
		||||
        document.addEventListener('dragend', this.unsetDragging);
 | 
			
		||||
        document.addEventListener('drop', this.unsetDragging);
 | 
			
		||||
    },
 | 
			
		||||
    destroyed() {
 | 
			
		||||
        document.removeEventListener('dragstart', this.setDragging);
 | 
			
		||||
        document.removeEventListener('dragend', this.unsetDragging);
 | 
			
		||||
        document.removeEventListener('drop', this.unsetDragging);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||