Compare commits
	
		
			313 Commits
		
	
	
		
			forms-retu
			...
			conditions
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 1b16f620de | ||
|   | ece6223b23 | ||
|   | ecabd00b0c | ||
|   | 768df84f10 | ||
|   | f8b3899bb9 | ||
|   | 3b046db4f8 | ||
|   | 97f829da9f | ||
|   | fb1eed1982 | ||
|   | fa83b4867c | ||
|   | 47d4fc9103 | ||
|   | dabd0bff29 | ||
|   | 51c70d02d7 | ||
|   | b74733bf3f | ||
|   | 84ae65536b | ||
|   | 71424dcf8d | ||
|   | 2c40396139 | ||
|   | 16a0bf9d6c | ||
|   | 5498ba8e1e | ||
|   | 0f9d7d2832 | ||
|   | 9bd1c51a6e | ||
|   | fd74fb0ec4 | ||
|   | 3626ff9947 | ||
|   | fd568409d3 | ||
|   | 14e3500a88 | ||
|   | 83d08ae369 | ||
|   | 39bf601ee1 | ||
|   | cfafecdd64 | ||
|   | 89ae6ef8c7 | ||
|   | ba780981a5 | ||
|   | ac13bc5850 | ||
|   | e526626e09 | ||
|   | 564be6f8ba | ||
|   | 371a7d3a3e | ||
|   | 8539d60562 | ||
|   | d333fd5822 | ||
|   | 364191eddc | ||
|   | 583f4dac85 | ||
|   | 28255dce01 | ||
|   | c9419d3e2d | ||
|   | b386275330 | ||
|   | d2a45e46f1 | ||
|   | 1a409afb03 | ||
|   | e57c18fd69 | ||
|   | 3aec9ec6ff | ||
|   | 0e9bf74332 | ||
|   | 2609a41ee8 | ||
|   | b8dc5acf00 | ||
|   | 9d5c7a4015 | ||
|   | fc53e855c4 | ||
|   | 467c57b7c6 | ||
|   | a51c0d5139 | ||
|   | d46310ca7d | ||
|   | 8f87cc78e8 | ||
|   | ee6e0f310e | ||
|   | f328a1078e | ||
|   | b4cf81a0ef | ||
|   | 1b9b7e2345 | ||
|   | 4456633010 | ||
|   | cda97d142a | ||
|   | 858199e396 | ||
|   | f504a335af | ||
|   | 463ec47af6 | ||
|   | ec4d121a98 | ||
|   | fea6d2df96 | ||
|   | 598d2b31e9 | ||
|   | 25e28ab97c | ||
|   | 43056c4068 | ||
|   | 614206b10c | ||
|   | 30a493d038 | ||
|   | 96e433beaa | ||
|   | 0915aaea3b | ||
|   | 80656c1be0 | ||
|   | acd75f86f4 | ||
|   | 486dae54bd | ||
|   | 92ecf3af1d | ||
|   | fd0c19026d | ||
|   | 3109c8d825 | ||
|   | 78cf75323f | ||
|   | b744467f21 | ||
|   | 2bb2bb6a1b | ||
|   | 11ed7027e7 | ||
|   | 36bcfd5a41 | ||
|   | 70b5c627ca | ||
|   | f4f1d0387b | ||
|   | a1bf4a92e5 | ||
|   | 7d2256d70f | ||
|   | 5814d2a35e | ||
|   | 6ab84c0bc3 | ||
|   | a7fc9b3caa | ||
|   | 67f493f012 | ||
|   | 0686e6d38f | ||
|   | 7fc825949c | ||
|   | 2a9ccdcffd | ||
|   | 6db78af69f | ||
|   | 038489256c | ||
|   | 53b785269b | ||
|   | 007b14b5c9 | ||
|   | 50b331c451 | ||
|   | 44fc62e0ba | ||
|   | 2635f085f0 | ||
|   | 22161fce7f | ||
|   | 386fc75047 | ||
|   | fa6dd84945 | ||
|   | d425bd564c | ||
|   | 93e3065b3e | ||
|   | 0ad2d59924 | ||
|   | f4468a8233 | ||
|   | dc08877bbb | ||
|   | f08caa6135 | ||
|   | ad7d029ce8 | ||
|   | 387912b4d3 | ||
|   | 53e0ed4d4a | ||
|   | 11c205b5c4 | ||
|   | 4ede6351ec | ||
|   | 24bbcb466f | ||
|   | b6b5cfe403 | ||
|   | b6ce9c6ed7 | ||
|   | 6e5e8f0ce8 | ||
|   | 2415d785cc | ||
|   | 2b5d6beb84 | ||
|   | 86316d8940 | ||
|   | 1f2b5ec5c8 | ||
|   | 8db6f8f633 | ||
|   | 79557165a3 | ||
|   | ec1d4abde9 | ||
|   | 07c5e2800a | ||
|   | 79811d6662 | ||
|   | 67919ece16 | ||
|   | 7029dcf09e | ||
|   | fc03b3a79d | ||
|   | 096d6371f1 | ||
|   | e580734c95 | ||
|   | 2690156a9d | ||
|   | 7ac7a40b1b | ||
|   | dc9e572052 | ||
|   | b15ebfd492 | ||
|   | 8baee7a0c9 | ||
|   | dc85063467 | ||
|   | be428b326e | ||
|   | dd0e360709 | ||
|   | 04da88e3b4 | ||
|   | 9bcab02e35 | ||
|   | 1ff4d41b7c | ||
|   | 04a5c8f69f | ||
|   | 8886a94a01 | ||
|   | f25eebdf3f | ||
|   | f9ba46fe85 | ||
|   | 6f6fb859d6 | ||
|   | 1e3389b427 | ||
|   | c977c64139 | ||
|   | e419149378 | ||
|   | a5a3e41d21 | ||
|   | ecef8eaf86 | ||
|   | de03cfbe64 | ||
|   | 03a6de55d6 | ||
|   | 3c5047df5e | ||
|   | 3cc630d4c2 | ||
|   | b3488c54cd | ||
|   | 01b1d66bea | ||
|   | bc9cadaa77 | ||
|   | f42ec7e2c5 | ||
|   | d6a422fbdb | ||
|   | d98b54bea7 | ||
|   | 0beda1d053 | ||
|   | e912ab8f4e | ||
|   | 5055a18ca1 | ||
|   | 96746f4042 | ||
|   | b22ad3ded9 | ||
|   | 7e0f475c63 | ||
|   | efb3c2b71e | ||
|   | 862ea6986f | ||
|   | cfa5dcb02e | ||
|   | 23aaada79d | ||
|   | 9e4458db10 | ||
|   | a8da06033c | ||
|   | 0bf3597147 | ||
|   | cfd9730055 | ||
|   | e88ead30dc | ||
|   | 67b24ce846 | ||
|   | 709c3fff65 | ||
|   | ab6e87ae6b | ||
|   | cdb7066bed | ||
|   | 73d0507f1f | ||
|   | 4d263bcf32 | ||
|   | 2d8f61172d | ||
|   | 621c1dc11e | ||
|   | dd136a5ff4 | ||
|   | 8fc785bbd6 | ||
|   | 82be503f4f | ||
|   | 7feb933519 | ||
|   | e806e5a293 | ||
|   | 770951c6da | ||
|   | 7b7c7b528a | ||
|   | a554aa20f8 | ||
|   | ff1ef1f184 | ||
|   | bf1efaf912 | ||
|   | ff2bc41317 | ||
|   | bdaf8aff15 | ||
|   | 1dc4f9f6bb | ||
|   | d6320f5da1 | ||
|   | 276be5e857 | ||
|   | 3101e77ecc | ||
|   | ab6dae16f1 | ||
|   | 36222d79c6 | ||
|   | 08656a6674 | ||
|   | 8034317796 | ||
|   | a59f3a550e | ||
|   | 415b967c0b | ||
|   | 642499d519 | ||
|   | fa0a54eee7 | ||
|   | 82f175f6c7 | ||
|   | 8df549e8d9 | ||
|   | 9fd720777b | ||
|   | 4c68c725b1 | ||
|   | 06a5207c6d | ||
|   | 78b885c508 | ||
|   | a18a3b6099 | ||
|   | 68949e070c | ||
|   | 654333dabe | ||
|   | 81b8a76f1b | ||
|   | 31736fa194 | ||
|   | 33632ef1dc | ||
|   | 94305ed82c | ||
|   | c8abc45e25 | ||
|   | cd25459ac9 | ||
|   | aaf1eb8059 | ||
|   | 1589e4236a | ||
|   | 8ca202d0a9 | ||
|   | d2f7904118 | ||
|   | 2d059fb856 | ||
|   | 8bbd7898bb | ||
|   | ea6f8c9a50 | ||
|   | d152440436 | ||
|   | 1ffe76a525 | ||
|   | a6825f530c | ||
|   | 7cf6dc386f | ||
|   | 5d8252bb07 | ||
|   | e1e1e0fb2f | ||
|   | 4f7345563f | ||
|   | 68a2b9f3a8 | ||
|   | d79402c568 | ||
|   | d0e8f650be | ||
|   | d819c6efe2 | ||
|   | 91c877f234 | ||
|   | 55a674ba7b | ||
|   | 36055b7c04 | ||
|   | fe3cc661d3 | ||
|   | eb7efae1cc | ||
|   | 63f8fb54d4 | ||
|   | 097fa2e655 | ||
|   | 3d0b4d51c2 | ||
|   | 37650487f7 | ||
|   | 6ccc0b4fbf | ||
|   | 79fe95372d | ||
|   | 6adb190d0e | ||
|   | c094e6c6f4 | ||
|   | 8c796b4e57 | ||
|   | c08e9a89ff | ||
|   | cc8ba18ccc | ||
|   | 57c671a42e | ||
|   | 1ee6ecf3ae | ||
|   | 5f80b3773b | ||
|   | 8452455050 | ||
|   | e5d8f60cdb | ||
|   | de466000a0 | ||
|   | 49664c011c | ||
|   | cf34d6b127 | ||
|   | e52f6ce099 | ||
|   | 1ecdc4c487 | ||
|   | d38e2c49cb | ||
|   | f8464fa76f | ||
|   | 308ae2cb2e | ||
|   | 88219659fb | ||
|   | c34c2df061 | ||
|   | 99c7bd4c10 | ||
|   | f93d5a6fbf | ||
|   | cd116667be | ||
|   | 2f2de3952d | ||
|   | 45e56798c5 | ||
|   | 0664d480e6 | ||
|   | 283599ddf5 | ||
|   | 09e3ceefa0 | ||
|   | 87f76ebfe4 | ||
|   | 55a195b841 | ||
|   | c7946fd7b3 | ||
|   | 5d3ba3199c | ||
|   | f0d10306fc | ||
|   | 161943b5b8 | ||
|   | e545043a26 | ||
|   | 40fb58b5b7 | ||
|   | 1f9d4708b3 | ||
|   | 162809e081 | ||
|   | 482c871ac2 | ||
|   | f0b3311630 | ||
|   | 656d6d6c3f | ||
|   | ea45f0f4aa | ||
|   | 6a25cb0a58 | ||
|   | 4a1901420d | ||
|   | ad64f00608 | ||
|   | 65aea29cb9 | ||
|   | 7981424e9a | ||
|   | 10c4340475 | ||
|   | 0a95db1a51 | ||
|   | ace77dce65 | ||
|   | c1d58bb25f | ||
|   | fbcafe0f62 | ||
|   | 9a9d9222a9 | ||
|   | 221e5b4f6c | ||
|   | 5df74aee68 | ||
|   | 17838d8040 | ||
|   | f82ca91a61 | ||
|   | b06c234b59 | ||
|   | 31a7ebd4f1 | 
							
								
								
									
										2
									
								
								API.md
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								API.md
									
									
									
									
									
								
							| @@ -231,7 +231,7 @@ attributes | ||||
|     of this object. This is used for specifying an icon to appear next to each  | ||||
|     object of this type. | ||||
|  | ||||
| The [Open MCT Tutorials](https://github.com/nasa/openmct-tutorial) provide a  | ||||
| The [Open MCT Tutorials](https://github.com/openmct/openmct-tutorial) provide a  | ||||
| step-by-step examples of writing code for Open MCT that includes a [section on  | ||||
| defining a new object type](https://github.com/nasa/openmct-tutorial#step-3---providing-objects). | ||||
|  | ||||
|   | ||||
							
								
								
									
										80
									
								
								coverage/HeadlessChrome 0.0.0 (Mac OS X 10.14.6)/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								coverage/HeadlessChrome 0.0.0 (Mac OS X 10.14.6)/index.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| <!doctype html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <title>Code coverage report for All files</title> | ||||
|     <meta charset="utf-8" /> | ||||
|     <link rel="stylesheet" href="prettify.css" /> | ||||
|     <link rel="stylesheet" href="base.css" /> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|     <style type='text/css'> | ||||
|         .coverage-summary .sorter { | ||||
|             background-image: url(sort-arrow-sprite.png); | ||||
|         } | ||||
|     </style> | ||||
| </head> | ||||
| <body> | ||||
| <div class='wrapper'> | ||||
|   <div class='pad1'> | ||||
|     <h1> | ||||
|       / | ||||
|     </h1> | ||||
|     <div class='clearfix'> | ||||
|       <div class='fl pad1y space-right2'> | ||||
|         <span class="strong">100% </span> | ||||
|         <span class="quiet">Statements</span> | ||||
|         <span class='fraction'>0/0</span> | ||||
|       </div> | ||||
|       <div class='fl pad1y space-right2'> | ||||
|         <span class="strong">100% </span> | ||||
|         <span class="quiet">Branches</span> | ||||
|         <span class='fraction'>0/0</span> | ||||
|       </div> | ||||
|       <div class='fl pad1y space-right2'> | ||||
|         <span class="strong">100% </span> | ||||
|         <span class="quiet">Functions</span> | ||||
|         <span class='fraction'>0/0</span> | ||||
|       </div> | ||||
|       <div class='fl pad1y space-right2'> | ||||
|         <span class="strong">100% </span> | ||||
|         <span class="quiet">Lines</span> | ||||
|         <span class='fraction'>0/0</span> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
|   <div class='status-line high'></div> | ||||
| <div class="pad1"> | ||||
| <table class="coverage-summary"> | ||||
| <thead> | ||||
| <tr> | ||||
|    <th data-col="file" data-fmt="html" data-html="true" class="file">File</th> | ||||
|    <th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th> | ||||
|    <th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th> | ||||
|    <th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th> | ||||
|    <th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th> | ||||
|    <th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th> | ||||
|    <th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th> | ||||
|    <th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th> | ||||
|    <th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th> | ||||
|    <th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th> | ||||
| </tr> | ||||
| </thead> | ||||
| <tbody></tbody> | ||||
| </table> | ||||
| </div><div class='push'></div><!-- for sticky footer --> | ||||
| </div><!-- /wrapper --> | ||||
| <div class='footer quiet pad2 space-top1 center small'> | ||||
|   Code coverage | ||||
|   generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Wed Dec 11 2019 13:15:10 GMT-0800 (Pacific Standard Time) | ||||
| </div> | ||||
| </div> | ||||
| <script src="prettify.js"></script> | ||||
| <script> | ||||
| window.onload = function () { | ||||
|         if (typeof prettyPrint === 'function') { | ||||
|             prettyPrint(); | ||||
|         } | ||||
| }; | ||||
| </script> | ||||
| <script src="sorter.js"></script> | ||||
| </body> | ||||
| </html> | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 209 B | 
							
								
								
									
										158
									
								
								coverage/HeadlessChrome 0.0.0 (Mac OS X 10.14.6)/sorter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								coverage/HeadlessChrome 0.0.0 (Mac OS X 10.14.6)/sorter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | ||||
| var addSorting = (function () { | ||||
|     "use strict"; | ||||
|     var cols, | ||||
|         currentSort = { | ||||
|             index: 0, | ||||
|             desc: false | ||||
|         }; | ||||
|  | ||||
|     // returns the summary table element | ||||
|     function getTable() { return document.querySelector('.coverage-summary'); } | ||||
|     // returns the thead element of the summary table | ||||
|     function getTableHeader() { return getTable().querySelector('thead tr'); } | ||||
|     // returns the tbody element of the summary table | ||||
|     function getTableBody() { return getTable().querySelector('tbody'); } | ||||
|     // returns the th element for nth column | ||||
|     function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; } | ||||
|  | ||||
|     // loads all columns | ||||
|     function loadColumns() { | ||||
|         var colNodes = getTableHeader().querySelectorAll('th'), | ||||
|             colNode, | ||||
|             cols = [], | ||||
|             col, | ||||
|             i; | ||||
|  | ||||
|         for (i = 0; i < colNodes.length; i += 1) { | ||||
|             colNode = colNodes[i]; | ||||
|             col = { | ||||
|                 key: colNode.getAttribute('data-col'), | ||||
|                 sortable: !colNode.getAttribute('data-nosort'), | ||||
|                 type: colNode.getAttribute('data-type') || 'string' | ||||
|             }; | ||||
|             cols.push(col); | ||||
|             if (col.sortable) { | ||||
|                 col.defaultDescSort = col.type === 'number'; | ||||
|                 colNode.innerHTML = colNode.innerHTML + '<span class="sorter"></span>'; | ||||
|             } | ||||
|         } | ||||
|         return cols; | ||||
|     } | ||||
|     // attaches a data attribute to every tr element with an object | ||||
|     // of data values keyed by column name | ||||
|     function loadRowData(tableRow) { | ||||
|         var tableCols = tableRow.querySelectorAll('td'), | ||||
|             colNode, | ||||
|             col, | ||||
|             data = {}, | ||||
|             i, | ||||
|             val; | ||||
|         for (i = 0; i < tableCols.length; i += 1) { | ||||
|             colNode = tableCols[i]; | ||||
|             col = cols[i]; | ||||
|             val = colNode.getAttribute('data-value'); | ||||
|             if (col.type === 'number') { | ||||
|                 val = Number(val); | ||||
|             } | ||||
|             data[col.key] = val; | ||||
|         } | ||||
|         return data; | ||||
|     } | ||||
|     // loads all row data | ||||
|     function loadData() { | ||||
|         var rows = getTableBody().querySelectorAll('tr'), | ||||
|             i; | ||||
|  | ||||
|         for (i = 0; i < rows.length; i += 1) { | ||||
|             rows[i].data = loadRowData(rows[i]); | ||||
|         } | ||||
|     } | ||||
|     // sorts the table using the data for the ith column | ||||
|     function sortByIndex(index, desc) { | ||||
|         var key = cols[index].key, | ||||
|             sorter = function (a, b) { | ||||
|                 a = a.data[key]; | ||||
|                 b = b.data[key]; | ||||
|                 return a < b ? -1 : a > b ? 1 : 0; | ||||
|             }, | ||||
|             finalSorter = sorter, | ||||
|             tableBody = document.querySelector('.coverage-summary tbody'), | ||||
|             rowNodes = tableBody.querySelectorAll('tr'), | ||||
|             rows = [], | ||||
|             i; | ||||
|  | ||||
|         if (desc) { | ||||
|             finalSorter = function (a, b) { | ||||
|                 return -1 * sorter(a, b); | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         for (i = 0; i < rowNodes.length; i += 1) { | ||||
|             rows.push(rowNodes[i]); | ||||
|             tableBody.removeChild(rowNodes[i]); | ||||
|         } | ||||
|  | ||||
|         rows.sort(finalSorter); | ||||
|  | ||||
|         for (i = 0; i < rows.length; i += 1) { | ||||
|             tableBody.appendChild(rows[i]); | ||||
|         } | ||||
|     } | ||||
|     // removes sort indicators for current column being sorted | ||||
|     function removeSortIndicators() { | ||||
|         var col = getNthColumn(currentSort.index), | ||||
|             cls = col.className; | ||||
|  | ||||
|         cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); | ||||
|         col.className = cls; | ||||
|     } | ||||
|     // adds sort indicators for current column being sorted | ||||
|     function addSortIndicators() { | ||||
|         getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; | ||||
|     } | ||||
|     // adds event listeners for all sorter widgets | ||||
|     function enableUI() { | ||||
|         var i, | ||||
|             el, | ||||
|             ithSorter = function ithSorter(i) { | ||||
|                 var col = cols[i]; | ||||
|  | ||||
|                 return function () { | ||||
|                     var desc = col.defaultDescSort; | ||||
|  | ||||
|                     if (currentSort.index === i) { | ||||
|                         desc = !currentSort.desc; | ||||
|                     } | ||||
|                     sortByIndex(i, desc); | ||||
|                     removeSortIndicators(); | ||||
|                     currentSort.index = i; | ||||
|                     currentSort.desc = desc; | ||||
|                     addSortIndicators(); | ||||
|                 }; | ||||
|             }; | ||||
|         for (i =0 ; i < cols.length; i += 1) { | ||||
|             if (cols[i].sortable) { | ||||
|                 // add the click event handler on the th so users | ||||
|                 // dont have to click on those tiny arrows | ||||
|                 el = getNthColumn(i).querySelector('.sorter').parentElement; | ||||
|                 if (el.addEventListener) { | ||||
|                     el.addEventListener('click', ithSorter(i)); | ||||
|                 } else { | ||||
|                     el.attachEvent('onclick', ithSorter(i)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     // adds sorting functionality to the UI | ||||
|     return function () { | ||||
|         if (!getTable()) { | ||||
|             return; | ||||
|         } | ||||
|         cols = loadColumns(); | ||||
|         loadData(cols); | ||||
|         addSortIndicators(); | ||||
|         enableUI(); | ||||
|     }; | ||||
| })(); | ||||
|  | ||||
| window.addEventListener('load', addSorting); | ||||
| @@ -43,7 +43,7 @@ | ||||
|             openmct.legacyRegistry.enable.bind(openmct.legacyRegistry) | ||||
|         ); | ||||
|  | ||||
|         openmct.install(openmct.plugins.Espresso()); | ||||
|         openmct.install(openmct.plugins.Snow()); | ||||
|         openmct.install(openmct.plugins.MyItems()); | ||||
|         openmct.install(openmct.plugins.LocalStorage()); | ||||
|         openmct.install(openmct.plugins.Generator()); | ||||
|   | ||||
| @@ -64,6 +64,7 @@ | ||||
|     "request": "^2.69.0", | ||||
|     "split": "^1.0.0", | ||||
|     "style-loader": "^1.0.1", | ||||
|     "uuid": "^3.3.3", | ||||
|     "v8-compile-cache": "^1.1.0", | ||||
|     "vue": "2.5.6", | ||||
|     "vue-loader": "^15.2.6", | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2018, United States Government | ||||
|  * Open MCT, Copyright (c) 2014-2019, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
| @@ -264,6 +264,7 @@ define([ | ||||
|         this.install(this.plugins.GoToOriginalAction()); | ||||
|         this.install(this.plugins.ImportExport()); | ||||
|         this.install(this.plugins.WebPage()); | ||||
|         this.install(this.plugins.Condition()); | ||||
|     } | ||||
|  | ||||
|     MCT.prototype = Object.create(EventEmitter.prototype); | ||||
|   | ||||
							
								
								
									
										237
									
								
								src/plugins/condition/Condition.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								src/plugins/condition/Condition.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import * as EventEmitter from 'eventemitter3'; | ||||
| import uuid from 'uuid'; | ||||
| import TelemetryCriterion from "./criterion/TelemetryCriterion"; | ||||
| import { TRIGGER } from "./utils/constants"; | ||||
| import {computeCondition} from "./utils/evaluator"; | ||||
|  | ||||
| /* | ||||
| * conditionConfiguration = { | ||||
| *   identifier: { | ||||
| *       key: '', | ||||
| *       namespace: '' | ||||
| *   }, | ||||
| *   trigger: 'any'/'all', | ||||
| *   criteria: [ | ||||
| *       { | ||||
| *           telemetry: '', | ||||
| *           operation: '', | ||||
| *           input: [], | ||||
| *           metadata: '' | ||||
| *       } | ||||
| *   ] | ||||
| * } | ||||
| */ | ||||
| export default class ConditionClass extends EventEmitter { | ||||
|  | ||||
|     /** | ||||
|      * Manages criteria and emits the result of - true or false - based on criteria evaluated. | ||||
|      * @constructor | ||||
|      * @param conditionConfiguration: {identifier: {domainObject.identifier},trigger: enum, criteria: Array of {id: uuid, operation: enum, input: Array, metaDataKey: string, key: {domainObject.identifier} } | ||||
|      * @param openmct | ||||
|      */ | ||||
|     constructor(conditionConfiguration, openmct) { | ||||
|         super(); | ||||
|  | ||||
|         this.openmct = openmct; | ||||
|         this.id = this.openmct.objects.makeKeyString(conditionConfiguration.identifier); | ||||
|         this.criteria = []; | ||||
|         this.criteriaResults = {}; | ||||
|         this.result = undefined; | ||||
|         if (conditionConfiguration.configuration.criteria) { | ||||
|             this.createCriteria(conditionConfiguration.configuration.criteria); | ||||
|         } | ||||
|         this.trigger = conditionConfiguration.configuration.trigger; | ||||
|         this.openmct.objects.get(this.id).then(obj => this.observeForChanges(obj)); | ||||
|     } | ||||
|  | ||||
|     observeForChanges(conditionDO) { | ||||
|         this.stopObservingForChanges = this.openmct.objects.observe(conditionDO, '*', this.update.bind(this)); | ||||
|     } | ||||
|  | ||||
|     update(newDomainObject) { | ||||
|         this.updateTrigger(newDomainObject.configuration.trigger); | ||||
|         this.updateCriteria(newDomainObject.configuration.criteria); | ||||
|     } | ||||
|  | ||||
|     updateTrigger(trigger) { | ||||
|         if (this.trigger !== trigger) { | ||||
|             this.trigger = trigger; | ||||
|             this.handleConditionUpdated(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     generateCriterion(criterionConfiguration) { | ||||
|         return { | ||||
|             id: uuid(), | ||||
|             telemetry: criterionConfiguration.telemetry || '', | ||||
|             operation: criterionConfiguration.operation || '', | ||||
|             input: criterionConfiguration.input === undefined ? [] : criterionConfiguration.input, | ||||
|             metadata: criterionConfiguration.metadata || '' | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     createCriteria(criterionConfigurations) { | ||||
|         criterionConfigurations.forEach((criterionConfiguration) => { | ||||
|             this.addCriterion(criterionConfiguration); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     updateCriteria(criterionConfigurations) { | ||||
|         this.destroyCriteria(); | ||||
|         this.createCriteria(criterionConfigurations); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      *  adds criterion to the condition. | ||||
|      */ | ||||
|     addCriterion(criterionConfiguration) { | ||||
|         let criterionConfigurationWithId = this.generateCriterion(criterionConfiguration || null); | ||||
|         let criterion = new TelemetryCriterion(criterionConfigurationWithId, this.openmct); | ||||
|         criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj)); | ||||
|         criterion.on('criterionResultUpdated', (obj) => this.handleCriterionResult(obj)); | ||||
|         if (!this.criteria) { | ||||
|             this.criteria = []; | ||||
|         } | ||||
|         this.criteria.push(criterion); | ||||
|         return criterionConfigurationWithId.id; | ||||
|     } | ||||
|  | ||||
|     findCriterion(id) { | ||||
|         let criterion; | ||||
|  | ||||
|         for (let i=0, ii=this.criteria.length; i < ii; i ++) { | ||||
|             if (this.criteria[i].id === id) { | ||||
|                 criterion = { | ||||
|                     item: this.criteria[i], | ||||
|                     index: i | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return criterion; | ||||
|     } | ||||
|  | ||||
|     updateCriterion(id, criterionConfiguration) { | ||||
|         let found = this.findCriterion(id); | ||||
|         if (found) { | ||||
|             const newCriterionConfiguration = this.generateCriterion(criterionConfiguration); | ||||
|             let newCriterion = new TelemetryCriterion(newCriterionConfiguration, this.openmct); | ||||
|             newCriterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj)); | ||||
|             newCriterion.on('criterionResultUpdated', (obj) => this.handleCriterionResult(obj)); | ||||
|  | ||||
|             let criterion = found.item; | ||||
|             criterion.unsubscribe(); | ||||
|             criterion.off('criterionUpdated', (obj) => this.handleCriterionUpdated(obj)); | ||||
|             criterion.off('criterionResultUpdated', (obj) => this.handleCriterionResult(obj)); | ||||
|             this.criteria.splice(found.index, 1, newCriterion); | ||||
|             if (this.criteriaResults[criterion.id] !== undefined) { | ||||
|                 delete this.criteriaResults[criterion.id]; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     removeCriterion(id) { | ||||
|         if (this.destroyCriterion(id)) { | ||||
|             this.handleConditionUpdated(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     destroyCriterion(id) { | ||||
|         let found = this.findCriterion(id); | ||||
|         if (found) { | ||||
|             let criterion = found.item; | ||||
|             criterion.destroy(); | ||||
|             // TODO this is passing the wrong args | ||||
|             criterion.off('criterionUpdated', (result) => { | ||||
|                 this.handleCriterionUpdated(id, result); | ||||
|             }); | ||||
|             this.criteria.splice(found.index, 1); | ||||
|             if (this.criteriaResults[criterion.id] !== undefined) { | ||||
|                 delete this.criteriaResults[criterion.id]; | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     handleCriterionUpdated(criterion) { | ||||
|         let found = this.findCriterion(criterion.id); | ||||
|         if (found) { | ||||
|             this.criteria[found.index] = criterion.data; | ||||
|             this.subscribe(); | ||||
|             // TODO nothing is listening to this | ||||
|             this.emitEvent('conditionUpdated', { | ||||
|                 trigger: this.trigger, | ||||
|                 criteria: this.criteria | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     handleCriterionResult(eventData) { | ||||
|         const id = eventData.id; | ||||
|         const conditionData = eventData.data; | ||||
|          | ||||
|         if (this.findCriterion(id)) { | ||||
|             this.criteriaResults[id] = eventData.data.result; | ||||
|         } | ||||
|  | ||||
|         conditionData.result = computeCondition(this.criteriaResults, this.trigger === TRIGGER.ALL); | ||||
|         this.emitEvent('conditionResultUpdated', conditionData); | ||||
|     } | ||||
|  | ||||
|     subscribe() { | ||||
|         // TODO it looks like on any single criterion update subscriptions fire for all criteria | ||||
|         this.criteria.forEach((criterion) => { | ||||
|             criterion.subscribe(); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     getCriteria() { | ||||
|         return this.criteria; | ||||
|     } | ||||
|  | ||||
|     destroyCriteria() { | ||||
|         let success = true; | ||||
|         //looping through the array backwards since destroyCriterion modifies the criteria array | ||||
|         for (let i=this.criteria.length-1; i >= 0; i--) { | ||||
|             success = success && this.destroyCriterion(this.criteria[i].id); | ||||
|         } | ||||
|         return success; | ||||
|     } | ||||
|  | ||||
|     emitEvent(eventName, data) { | ||||
|         this.emit(eventName, { | ||||
|             id: this.id, | ||||
|             data: data | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     destroy() { | ||||
|         if (typeof this.stopObservingForChanges === 'function') { | ||||
|             this.stopObservingForChanges(); | ||||
|         } | ||||
|         this.destroyCriteria(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										254
									
								
								src/plugins/condition/ConditionManager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								src/plugins/condition/ConditionManager.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,254 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import Condition from "./Condition"; | ||||
| import uuid from "uuid"; | ||||
| import * as EventEmitter from 'eventemitter3'; | ||||
|  | ||||
| export default class ConditionManager extends EventEmitter { | ||||
|     constructor(domainObject, openmct) { | ||||
|         super(); | ||||
|         this.domainObject = domainObject; | ||||
|         this.openmct = openmct; | ||||
|         this.instantiate = this.openmct.$injector.get('instantiate'); | ||||
|         this.initialize(); | ||||
|     } | ||||
|  | ||||
|     initialize() { | ||||
|         this.conditionResults = {}; | ||||
|         this.openmct.objects.get(this.domainObject.identifier).then((obj) => { | ||||
|             this.observeForChanges(obj); | ||||
|             this.conditionCollection = []; | ||||
|             if (this.domainObject.configuration.conditionCollection.length) { | ||||
|                 this.domainObject.configuration.conditionCollection.forEach((conditionConfigurationId, index) => { | ||||
|                     this.openmct.objects.get(conditionConfigurationId).then((conditionConfiguration) => { | ||||
|                         this.initCondition(conditionConfiguration, index) | ||||
|                     }); | ||||
|                 }); | ||||
|             } else { | ||||
|                 this.addCondition(true); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     observeForChanges(domainObject) { | ||||
|         //TODO: Observe only the conditionCollection property instead of the whole domainObject | ||||
|         this.stopObservingForChanges = this.openmct.objects.observe(domainObject, '*', this.handleConditionCollectionUpdated.bind(this)); | ||||
|     } | ||||
|  | ||||
|     handleConditionCollectionUpdated(newDomainObject) { | ||||
|         let oldConditionIdentifiers = this.domainObject.configuration.conditionCollection.map((conditionConfigurationId) => { | ||||
|             return this.openmct.objects.makeKeyString(conditionConfigurationId); | ||||
|         }); | ||||
|         let newConditionIdentifiers = newDomainObject.configuration.conditionCollection.map((conditionConfigurationId) => { | ||||
|             return this.openmct.objects.makeKeyString(conditionConfigurationId); | ||||
|         }); | ||||
|  | ||||
|         this.domainObject = newDomainObject; | ||||
|  | ||||
|         //check for removed conditions | ||||
|         oldConditionIdentifiers.forEach((identifier, index) => { | ||||
|             if (newConditionIdentifiers.indexOf(identifier) < 0) { | ||||
|                 this.removeCondition(identifier); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         let newConditionCount = this.domainObject.configuration.conditionCollection.length - this.conditionCollection.length; | ||||
|  | ||||
|         for (let i = 0; i < newConditionCount; i++) { | ||||
|             let conditionConfigurationId = this.domainObject.configuration.conditionCollection[i]; | ||||
|             this.openmct.objects.get(conditionConfigurationId).then((conditionConfiguration) => { | ||||
|                 this.initCondition(conditionConfiguration, i); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     initCondition(conditionConfiguration, index) { | ||||
|         let condition = new Condition(conditionConfiguration, this.openmct); | ||||
|         condition.on('conditionResultUpdated', this.handleConditionResult.bind(this)); | ||||
|         if (index !== undefined) { | ||||
|             this.conditionCollection.splice(index + 1, 0, condition); | ||||
|         } else { | ||||
|             this.conditionCollection.unshift(condition); | ||||
|         } | ||||
|         //There are no criteria for a default condition and hence no subscriptions. | ||||
|         //Hence the conditionResult must be manually triggered for it. | ||||
|         if (conditionConfiguration.isDefault) { | ||||
|             this.handleConditionResult(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     createConditionDomainObject(isDefault, conditionConfiguration) { | ||||
|         let conditionObj; | ||||
|         if (conditionConfiguration) { | ||||
|             conditionObj = { | ||||
|                 ...conditionConfiguration, | ||||
|                 name: `Copy of ${conditionConfiguration.name}`, | ||||
|                 identifier: { | ||||
|                     ...this.domainObject.identifier, | ||||
|                     key: uuid() | ||||
|                 } | ||||
|             }; | ||||
|         } else { | ||||
|             conditionObj = { | ||||
|                 isDefault: isDefault, | ||||
|                 type: 'condition', | ||||
|                 identifier: { | ||||
|                     ...this.domainObject.identifier, | ||||
|                     key: uuid() | ||||
|                 }, | ||||
|                 configuration: { | ||||
|                     name: isDefault ? 'Default' : 'Unnamed Condition', | ||||
|                     output: 'false', | ||||
|                     trigger: 'all', | ||||
|                     criteria: isDefault ? [] : [{ | ||||
|                         telemetry: '', | ||||
|                         operation: '', | ||||
|                         input: [], | ||||
|                         metadata: '' | ||||
|                     }] | ||||
|                 }, | ||||
|                 summary: '' | ||||
|             }; | ||||
|         } | ||||
|         let conditionDomainObjectKeyString = this.openmct.objects.makeKeyString(conditionObj.identifier); | ||||
|         let newDomainObject = this.instantiate(conditionObj, conditionDomainObjectKeyString); | ||||
|  | ||||
|         return newDomainObject.useCapability('adapter'); | ||||
|     } | ||||
|  | ||||
|     addCondition(isDefault, index) { | ||||
|         this.createAndSaveConditionDomainObject(!!isDefault, index); | ||||
|     } | ||||
|  | ||||
|     cloneCondition(conditionConfigurationId, index) { | ||||
|         this.openmct.objects.get(conditionConfigurationId).then((conditionConfiguration) => { | ||||
|             this.createAndSaveConditionDomainObject(false, index, conditionConfiguration); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     createAndSaveConditionDomainObject(isDefault, index, conditionConfiguration) { | ||||
|         let newConditionDomainObject = this.createConditionDomainObject(isDefault, conditionConfiguration); | ||||
|         //persist the condition domain object so that we can do an openmct.objects.get on it and only persist the identifier in the conditionCollection of conditionSet | ||||
|         this.openmct.objects.mutate(newConditionDomainObject, 'created', new Date()); | ||||
|         if (index !== undefined) { | ||||
|             this.domainObject.configuration.conditionCollection.splice(index + 1, 0, newConditionDomainObject.identifier); | ||||
|         } else { | ||||
|             this.domainObject.configuration.conditionCollection.unshift(newConditionDomainObject.identifier); | ||||
|         } | ||||
|         this.persist(); | ||||
|     } | ||||
|  | ||||
|     removeCondition(identifier) { | ||||
|         let found = this.findConditionById(identifier); | ||||
|         if (found) { | ||||
|             let index = found.index; | ||||
|             let condition = this.conditionCollection[index]; | ||||
|             let conditionIdAsString = condition.id; | ||||
|             condition.destroyCriteria(); | ||||
|             condition.off('conditionResultUpdated', this.handleConditionResult.bind(this)); | ||||
|             this.conditionCollection.splice(index, 1); | ||||
|             this.domainObject.configuration.conditionCollection.splice(index, 1); | ||||
|             if (this.conditionResults[conditionIdAsString] !== undefined) { | ||||
|                 delete this.conditionResults[conditionIdAsString]; | ||||
|             } | ||||
|             this.persist(); | ||||
|             this.handleConditionResult(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     findConditionById(identifier) { | ||||
|         let found; | ||||
|         for (let i=0, ii=this.conditionCollection.length; i < ii; i++) { | ||||
|             if (this.conditionCollection[i].id === this.openmct.objects.makeKeyString(identifier)) { | ||||
|                 found = { | ||||
|                     item: this.conditionCollection[i], | ||||
|                     index: i | ||||
|                 }; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return found; | ||||
|     } | ||||
|  | ||||
|     //this.$set(this.conditionCollection, reorderEvent.newIndex, oldConditions[reorderEvent.oldIndex]); | ||||
|     reorderConditions(reorderPlan) { | ||||
|         let oldConditions = Array.from(this.domainObject.configuration.conditionCollection); | ||||
|         let newCollection = []; | ||||
|         reorderPlan.forEach((reorderEvent) => { | ||||
|             let item = oldConditions[reorderEvent.oldIndex]; | ||||
|             newCollection.push(item); | ||||
|             this.domainObject.configuration.conditionCollection = newCollection; | ||||
|         }); | ||||
|         this.persist(); | ||||
|     } | ||||
|  | ||||
|     handleConditionResult(resultObj) { | ||||
|         let conditionCollection = this.domainObject.configuration.conditionCollection; | ||||
|         let currentConditionIdentifier = conditionCollection[conditionCollection.length-1]; | ||||
|  | ||||
|         if (resultObj) { | ||||
|             let idAsString = this.openmct.objects.makeKeyString(resultObj.id); | ||||
|             if (this.findConditionById(idAsString)) { | ||||
|                 this.conditionResults[idAsString] = resultObj.data.result; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (let i = 0; i < conditionCollection.length - 1; i++) { | ||||
|             let conditionIdAsString = this.openmct.objects.makeKeyString(conditionCollection[i]); | ||||
|             if (this.conditionResults[conditionIdAsString]) { | ||||
|                 //first condition to be true wins | ||||
|                 currentConditionIdentifier = conditionCollection[i]; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this.openmct.objects.get(currentConditionIdentifier).then((obj) => { | ||||
|             this.emit('conditionSetResultUpdated', | ||||
|                 Object.assign({}, | ||||
|                     resultObj ? resultObj.data : {}, | ||||
|                     { | ||||
|                         output: obj.configuration.output, | ||||
|                         id: this.domainObject.identifier, | ||||
|                         conditionId: currentConditionIdentifier | ||||
|                     } | ||||
|                 ) | ||||
|             ) | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     persist() { | ||||
|         this.openmct.objects.mutate(this.domainObject, 'configuration.conditionCollection', this.domainObject.configuration.conditionCollection); | ||||
|     } | ||||
|  | ||||
|     destroy() { | ||||
|         if (typeof this.stopObservingForChanges === 'function') { | ||||
|             this.stopObservingForChanges(); | ||||
|         } | ||||
|         this.conditionCollection.forEach((condition) => { | ||||
|             condition.off('conditionResultUpdated', this.handleConditionResult); | ||||
|             condition.destroy(); | ||||
|         }) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										98
									
								
								src/plugins/condition/ConditionManagerSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/plugins/condition/ConditionManagerSpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import ConditionManager  from './ConditionManager'; | ||||
|  | ||||
| describe('ConditionManager', () => { | ||||
|  | ||||
|     let conditionMgr; | ||||
|     let mockListener; | ||||
|     let openmct = {}; | ||||
|     let conditionSetDomainObject = { | ||||
|         identifier: { | ||||
|             namespace: "", | ||||
|             key: "600a7372-8d48-4dc4-98b6-548611b1ff7e" | ||||
|         }, | ||||
|         type: "conditionSet", | ||||
|         location: "mine", | ||||
|         configuration: { | ||||
|             conditionCollection: [] | ||||
|         } | ||||
|     }; | ||||
|     let mockConditionDomainObject = { | ||||
|         isDefault: true, | ||||
|         type: 'condition', | ||||
|         identifier: { | ||||
|             namespace: '', | ||||
|             key: '1234-5678' | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     function mockAngularComponents() { | ||||
|         let mockInjector = jasmine.createSpyObj('$injector', ['get']); | ||||
|  | ||||
|         let mockInstantiate = jasmine.createSpy('mockInstantiate'); | ||||
|         mockInstantiate.and.returnValue(mockInstantiate); | ||||
|  | ||||
|         let mockDomainObject = { | ||||
|             useCapability: function () { | ||||
|                 return mockConditionDomainObject; | ||||
|             } | ||||
|         }; | ||||
|         mockInstantiate.and.callFake(function () { | ||||
|             return mockDomainObject; | ||||
|         }); | ||||
|         mockInjector.get.and.callFake(function (service) { | ||||
|             return { | ||||
|                 'instantiate': mockInstantiate | ||||
|             }[service]; | ||||
|         }); | ||||
|  | ||||
|         openmct.$injector = mockInjector; | ||||
|     } | ||||
|  | ||||
|     beforeAll(function () { | ||||
|  | ||||
|         mockAngularComponents(); | ||||
|  | ||||
|         openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString', 'observe', 'mutate']); | ||||
|         openmct.objects.get.and.returnValues(new Promise(function (resolve, reject) { | ||||
|             resolve(conditionSetDomainObject); | ||||
|         }), new Promise(function (resolve, reject) { | ||||
|             resolve(mockConditionDomainObject); | ||||
|         })); | ||||
|         openmct.objects.makeKeyString.and.returnValue(conditionSetDomainObject.identifier.key); | ||||
|         openmct.objects.observe.and.returnValue(function () {}); | ||||
|         openmct.objects.mutate.and.returnValue(function () {}); | ||||
|         conditionMgr = new ConditionManager(conditionSetDomainObject, openmct); | ||||
|         mockListener = jasmine.createSpy('mockListener'); | ||||
|  | ||||
|         conditionMgr.on('conditionSetResultUpdated', mockListener); | ||||
|     }); | ||||
|  | ||||
|     it('creates a conditionCollection with a default condition', function () { | ||||
|         expect(conditionMgr.domainObject.configuration.conditionCollection.length).toEqual(1); | ||||
|         let defaultConditionIdentifier = conditionMgr.domainObject.configuration.conditionCollection[0]; | ||||
|         expect(defaultConditionIdentifier).toEqual(mockConditionDomainObject.identifier); | ||||
|     }); | ||||
|  | ||||
| }); | ||||
							
								
								
									
										33
									
								
								src/plugins/condition/ConditionSetCompositionPolicy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/plugins/condition/ConditionSetCompositionPolicy.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| export default function ConditionSetCompositionPolicy(openmct) { | ||||
|     return { | ||||
|         allow: function (parent, child) { | ||||
|             if (parent.type === 'conditionSet' && !openmct.telemetry.isTelemetryObject(child)) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										87
									
								
								src/plugins/condition/ConditionSetCompositionPolicySpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/plugins/condition/ConditionSetCompositionPolicySpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import ConditionSetCompositionPolicy  from './ConditionSetCompositionPolicy'; | ||||
|  | ||||
| describe('ConditionSetCompositionPolicy', () => { | ||||
|  | ||||
|     let policy; | ||||
|     let testTelemetryObject; | ||||
|     let openmct = {}; | ||||
|     let parentDomainObject; | ||||
|     let composition; | ||||
|  | ||||
|     beforeAll(function () { | ||||
|         testTelemetryObject = { | ||||
|             identifier:{ namespace: "", key: "test-object"}, | ||||
|             type: "test-object", | ||||
|             name: "Test Object", | ||||
|             telemetry: { | ||||
|                 values: [{ | ||||
|                     key: "some-key", | ||||
|                     name: "Some attribute", | ||||
|                     hints: { | ||||
|                         domain: 1 | ||||
|                     } | ||||
|                 }, { | ||||
|                     key: "some-other-key", | ||||
|                     name: "Another attribute", | ||||
|                     hints: { | ||||
|                         range: 1 | ||||
|                     } | ||||
|                 }] | ||||
|             } | ||||
|         }; | ||||
|         openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']); | ||||
|         openmct.objects.get.and.returnValue(testTelemetryObject); | ||||
|         openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key); | ||||
|         openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject']); | ||||
|         policy = new ConditionSetCompositionPolicy(openmct); | ||||
|         parentDomainObject = {}; | ||||
|         composition = {}; | ||||
|     }); | ||||
|  | ||||
|     it('returns true for object types that are not conditionSets', function () { | ||||
|         parentDomainObject.type = 'random'; | ||||
|         openmct.telemetry.isTelemetryObject.and.returnValue(false); | ||||
|         expect(policy.allow(parentDomainObject, {})).toBe(true); | ||||
|     }); | ||||
|  | ||||
|     it('returns false for object types that are not telemetry objects when parent is a conditionSet', function () { | ||||
|         parentDomainObject.type = 'conditionSet'; | ||||
|         openmct.telemetry.isTelemetryObject.and.returnValue(false); | ||||
|         expect(policy.allow(parentDomainObject, {})).toBe(false); | ||||
|     }); | ||||
|  | ||||
|     it('returns true for object types that are telemetry objects when parent is a conditionSet', function () { | ||||
|         parentDomainObject.type = 'conditionSet'; | ||||
|         openmct.telemetry.isTelemetryObject.and.returnValue(true); | ||||
|         expect(policy.allow(parentDomainObject, testTelemetryObject)).toBe(true); | ||||
|     }); | ||||
|  | ||||
|     it('returns true for object types that are telemetry objects when parent is not a conditionSet', function () { | ||||
|         parentDomainObject.type = 'random'; | ||||
|         openmct.telemetry.isTelemetryObject.and.returnValue(true); | ||||
|         expect(policy.allow(parentDomainObject, testTelemetryObject)).toBe(true); | ||||
|     }); | ||||
|  | ||||
| }); | ||||
							
								
								
									
										37
									
								
								src/plugins/condition/ConditionSetMetadataProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/plugins/condition/ConditionSetMetadataProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| export default class ConditionSetMetadataProvider { | ||||
|     constructor(openmct) { | ||||
|         this.openmct = openmct; | ||||
|     } | ||||
|  | ||||
|     supportsMetadata(domainObject) { | ||||
|         return domainObject.type === 'conditionSet'; | ||||
|     } | ||||
|  | ||||
|     getDomains(domainObject) { | ||||
|         return this.openmct.time.getAllTimeSystems().map(function (ts, i) { | ||||
|             return { | ||||
|                 key: ts.key, | ||||
|                 name: ts.name, | ||||
|                 format: ts.timeFormat, | ||||
|                 hints: { | ||||
|                     domain: i | ||||
|                 } | ||||
|             }; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     getMetadata(domainObject) { | ||||
|         return { | ||||
|             values: this.getDomains().concat([ | ||||
|                 { | ||||
|                     name: 'Output', | ||||
|                     key: 'output', | ||||
|                     format: 'string', | ||||
|                     hints: { | ||||
|                         range: 1 | ||||
|                     } | ||||
|                 } | ||||
|             ]) | ||||
|         }; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								src/plugins/condition/ConditionSetTelemetryProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/plugins/condition/ConditionSetTelemetryProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| import ConditionManager from './ConditionManager' | ||||
|  | ||||
| export default class ConditionSetTelemetryProvider { | ||||
|     constructor(openmct) { | ||||
|         this.openmct = openmct; | ||||
|     } | ||||
|  | ||||
|     isTelemetryObject(domainObject) { | ||||
|         return domainObject.type === 'conditionSet'; | ||||
|     } | ||||
|  | ||||
|     supportsRequest(domainObject, options) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     supportsSubscribe(domainObject) { | ||||
|         return domainObject.type === 'conditionSet'; | ||||
|     } | ||||
|  | ||||
|     subscribe(domainObject, callback) { | ||||
|         let conditionManager = new ConditionManager(domainObject, this.openmct); | ||||
|         conditionManager.on('conditionSetResultUpdated', callback); | ||||
|  | ||||
|         return function unsubscribe() { | ||||
|             conditionManager.off('conditionSetResultUpdated'); | ||||
|             conditionManager.destroy(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										84
									
								
								src/plugins/condition/ConditionSetViewProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/plugins/condition/ConditionSetViewProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import ConditionSet from './components/ConditionSet.vue'; | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| const DEFAULT_VIEW_PRIORITY = 100; | ||||
|  | ||||
| export default class ConditionSetViewProvider { | ||||
|     constructor(openmct) { | ||||
|         this.openmct = openmct; | ||||
|         this.name = 'Conditions View'; | ||||
|         this.key = 'conditionSet.view'; | ||||
|         this.cssClass = 'icon-conditional'; // TODO: replace with class for new icon | ||||
|     } | ||||
|  | ||||
|     canView(domainObject) { | ||||
|         return domainObject.type === 'conditionSet'; | ||||
|     } | ||||
|  | ||||
|     canEdit(domainObject) { | ||||
|         return domainObject.type === 'conditionSet'; | ||||
|     } | ||||
|  | ||||
|     view(domainObject, objectPath) { | ||||
|         let component; | ||||
|         const openmct = this.openmct; | ||||
|         return { | ||||
|             show: (container, isEditing) => { | ||||
|                 component = new Vue({ | ||||
|                     el: container, | ||||
|                     components: { | ||||
|                         ConditionSet | ||||
|                     }, | ||||
|                     provide: { | ||||
|                         openmct, | ||||
|                         domainObject, | ||||
|                         objectPath | ||||
|                     }, | ||||
|                     data() { | ||||
|                         return { | ||||
|                             isEditing | ||||
|                         } | ||||
|                     }, | ||||
|                     template: '<condition-set :isEditing="isEditing"></condition-set>' | ||||
|                 }); | ||||
|             }, | ||||
|             onEditModeChange: (isEditing) => { | ||||
|                 component.isEditing = isEditing; | ||||
|             }, | ||||
|             destroy: () => { | ||||
|                 component.$destroy(); | ||||
|                 component = undefined; | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     priority(domainObject) { | ||||
|         if (domainObject.type === 'conditionSet') { | ||||
|             return Number.MAX_VALUE; | ||||
|         } else { | ||||
|             return DEFAULT_VIEW_PRIORITY; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										121
									
								
								src/plugins/condition/ConditionSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/plugins/condition/ConditionSpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import Condition from "./Condition"; | ||||
| import {TRIGGER} from "./utils/constants"; | ||||
| import TelemetryCriterion from "./criterion/TelemetryCriterion"; | ||||
|  | ||||
| let openmct = {}, | ||||
|     mockListener, | ||||
|     testConditionDefinition, | ||||
|     testTelemetryObject, | ||||
|     conditionObj; | ||||
|  | ||||
| describe("The condition", function () { | ||||
|  | ||||
|     beforeEach (() => { | ||||
|         mockListener = jasmine.createSpy('listener'); | ||||
|         testTelemetryObject = { | ||||
|             identifier:{ namespace: "", key: "test-object"}, | ||||
|             type: "test-object", | ||||
|             name: "Test Object", | ||||
|             telemetry: { | ||||
|                 values: [{ | ||||
|                     key: "some-key", | ||||
|                     name: "Some attribute", | ||||
|                     hints: { | ||||
|                         domain: 1 | ||||
|                     } | ||||
|                 }, { | ||||
|                     key: "some-other-key", | ||||
|                     name: "Another attribute", | ||||
|                     hints: { | ||||
|                         range: 1 | ||||
|                     } | ||||
|                 }] | ||||
|             } | ||||
|         }; | ||||
|         openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']); | ||||
|         openmct.objects.get.and.returnValue(new Promise(function (resolve, reject) { | ||||
|             resolve(testTelemetryObject); | ||||
|         }));        openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key); | ||||
|         openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', 'subscribe', 'getMetadata']); | ||||
|         openmct.telemetry.isTelemetryObject.and.returnValue(true); | ||||
|         openmct.telemetry.subscribe.and.returnValue(function () {}); | ||||
|         openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry.values); | ||||
|  | ||||
|         testConditionDefinition = { | ||||
|             configuration: { | ||||
|                 trigger: TRIGGER.ANY, | ||||
|                 criteria: [ | ||||
|                     { | ||||
|                         operation: 'equalTo', | ||||
|                         input: false, | ||||
|                         metadata: 'value', | ||||
|                         telemetry: testTelemetryObject.identifier | ||||
|                     } | ||||
|                 ] | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         conditionObj = new Condition( | ||||
|             testConditionDefinition, | ||||
|             openmct | ||||
|         ); | ||||
|  | ||||
|         conditionObj.on('conditionUpdated', mockListener); | ||||
|  | ||||
|     }); | ||||
|  | ||||
|     it("generates criteria with an id", function () { | ||||
|         const testCriterion = testConditionDefinition.configuration.criteria[0]; | ||||
|         let criterion = conditionObj.generateCriterion(testCriterion); | ||||
|         expect(criterion.id).toBeDefined(); | ||||
|         expect(criterion.operation).toEqual(testCriterion.operation); | ||||
|         expect(criterion.input).toEqual(testCriterion.input); | ||||
|         expect(criterion.metadata).toEqual(testCriterion.metadata); | ||||
|         expect(criterion.telemetry).toEqual(testCriterion.telemetry); | ||||
|     }); | ||||
|  | ||||
|     it("initializes with an id", function () { | ||||
|         expect(conditionObj.id).toBeDefined(); | ||||
|     }); | ||||
|  | ||||
|     it("initializes with criteria from the condition definition", function () { | ||||
|         expect(conditionObj.criteria.length).toEqual(1); | ||||
|         let criterion = conditionObj.criteria[0]; | ||||
|         expect(criterion instanceof TelemetryCriterion).toBeTrue(); | ||||
|         expect(criterion.operator).toEqual(testConditionDefinition.configuration.criteria[0].operator); | ||||
|         expect(criterion.input).toEqual(testConditionDefinition.configuration.criteria[0].input); | ||||
|         expect(criterion.metadata).toEqual(testConditionDefinition.configuration.criteria[0].metadata); | ||||
|     }); | ||||
|  | ||||
|     it("initializes with the trigger from the condition definition", function () { | ||||
|         expect(conditionObj.trigger).toEqual(testConditionDefinition.configuration.trigger); | ||||
|     }); | ||||
|  | ||||
|     it("destroys all criteria for a condition", function () { | ||||
|         const result = conditionObj.destroyCriteria(); | ||||
|         expect(result).toBeTrue(); | ||||
|         expect(conditionObj.criteria.length).toEqual(0); | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										0
									
								
								src/plugins/condition/StyleRuleManager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/plugins/condition/StyleRuleManager.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										308
									
								
								src/plugins/condition/components/Condition.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								src/plugins/condition/components/Condition.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,308 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <div v-if="isEditing"> | ||||
|     <div v-if="domainObject" | ||||
|          class="c-c-editui__conditions c-c-container__container c-c__drag-wrapper" | ||||
|          :class="['widget-condition', { 'widget-condition--current': currentConditionIdentifier && (currentConditionIdentifier.key === conditionIdentifier.key) }]" | ||||
|     > | ||||
|         <div class="title-bar"> | ||||
|             <span class="c-c__menu-hamburger" | ||||
|                   :class="{ 'is-enabled': !domainObject.isDefault }" | ||||
|                   :draggable="!domainObject.isDefault" | ||||
|                   @dragstart="dragStart" | ||||
|                   @dragstop="dragStop" | ||||
|                   @dragover.stop | ||||
|             ></span> | ||||
|             <span | ||||
|                 class="is-enabled flex-elem" | ||||
|                 :class="['c-c__disclosure-triangle', { 'c-c__disclosure-triangle--expanded': expanded }]" | ||||
|                 @click="expanded = !expanded" | ||||
|             ></span> | ||||
|             <div class="condition-summary"> | ||||
|                 <span class="condition-name">{{ domainObject.configuration.name }}</span> | ||||
|                 <!-- TODO: description should be derived from criteria --> | ||||
|                 <span class="condition-description">{{ domainObject.configuration.name }}</span> | ||||
|             </div> | ||||
|             <span v-if="!domainObject.isDefault" | ||||
|                   class="is-enabled c-c__duplicate" | ||||
|                   @click="cloneCondition" | ||||
|             ></span> | ||||
|             <span v-if="!domainObject.isDefault" | ||||
|                   class="is-enabled c-c__trash" | ||||
|                   @click="removeCondition" | ||||
|             ></span> | ||||
|         </div> | ||||
|         <div v-if="expanded" | ||||
|              class="condition-config-edit widget-condition-content c-sw-editui__conditions-wrapper holder widget-conditions-wrapper flex-elem expanded" | ||||
|         > | ||||
|             <div id="conditionArea" | ||||
|                  class="c-c-editui__condition widget-conditions" | ||||
|             > | ||||
|                 <div class="c-c-condition"> | ||||
|                     <div class="c-c-condition__ui l-compact-form l-widget-condition has-local-controls"> | ||||
|                         <div> | ||||
|                             <ul class="t-widget-condition-config"> | ||||
|                                 <li> | ||||
|                                     <label>Condition Name</label> | ||||
|                                     <span class="controls"> | ||||
|                                         <input v-model="domainObject.configuration.name" | ||||
|                                                class="t-condition-input__name" | ||||
|                                                type="text" | ||||
|                                                @blur="persist" | ||||
|                                         > | ||||
|                                     </span> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <label>Output</label> | ||||
|                                     <span class="controls"> | ||||
|                                         <select v-model="selectedOutputSelection" | ||||
|                                                 @change="setOutputValue" | ||||
|                                         > | ||||
|                                             <option value="">- Select Output -</option> | ||||
|                                             <option v-for="option in outputOptions" | ||||
|                                                     :key="option" | ||||
|                                                     :value="option" | ||||
|                                             > | ||||
|                                                 {{ initCap(option) }} | ||||
|                                             </option> | ||||
|                                         </select> | ||||
|                                         <input v-if="selectedOutputSelection === outputOptions[2]" | ||||
|                                                v-model="domainObject.configuration.output" | ||||
|                                                class="t-condition-name-input" | ||||
|                                                type="text" | ||||
|                                                @blur="persist" | ||||
|                                         > | ||||
|                                     </span> | ||||
|                                 </li> | ||||
|                             </ul> | ||||
|                             <div v-if="!domainObject.isDefault" | ||||
|                                  class="widget-condition-content expanded" | ||||
|                             > | ||||
|                                 <ul class="t-widget-condition-config"> | ||||
|                                     <li class="has-local-controls t-condition"> | ||||
|                                         <label>Match when</label> | ||||
|                                         <span class="controls"> | ||||
|                                             <select v-model="domainObject.configuration.trigger" | ||||
|                                                     @change="persist" | ||||
|                                             > | ||||
|                                                 <option value="all">all criteria are met</option> | ||||
|                                                 <option value="any">any criteria are met</option> | ||||
|                                             </select> | ||||
|                                         </span> | ||||
|                                     </li> | ||||
|                                     <li v-if="!telemetry.length"> | ||||
|                                         <span class="help">Drag telemetry into the condition set to enable selection of telemetry parameters.</span> | ||||
|                                     </li> | ||||
|                                 </ul> | ||||
|                                 <ul v-if="telemetry.length" | ||||
|                                     class="t-widget-condition-config" | ||||
|                                 > | ||||
|                                     <li v-for="(criterion, index) in domainObject.configuration.criteria" | ||||
|                                         :key="index" | ||||
|                                         class="has-local-controls t-condition" | ||||
|                                     > | ||||
|                                         <Criterion :telemetry="telemetry" | ||||
|                                                    :criterion="criterion" | ||||
|                                                    :index="index" | ||||
|                                                    :trigger="domainObject.configuration.trigger" | ||||
|                                                    :is-default="domainObject.configuration.criteria.length === 1" | ||||
|                                                    @persist="persist" | ||||
|                                         /> | ||||
|                                         <div class="c-c__criterion-controls"> | ||||
|                                             <span class="is-enabled c-c__duplicate" | ||||
|                                                   @click="cloneCriterion(index)" | ||||
|                                             ></span> | ||||
|                                             <span v-if="!(domainObject.configuration.criteria.length === 1)" | ||||
|                                                   class="is-enabled c-c__trash" | ||||
|                                                   @click="removeCriterion(index)" | ||||
|                                             ></span> | ||||
|                                         </div> | ||||
|                                     </li> | ||||
|                                 </ul> | ||||
|                                 <div class="holder c-c-button-wrapper align-left"> | ||||
|                                     <span class="c-c-label-spacer"></span> | ||||
|                                     <button | ||||
|                                         class="c-c-button c-c-button--minor add-criteria-button" | ||||
|                                         @click="addCriteria" | ||||
|                                     > | ||||
|                                         <span class="c-c-button__label">Add Criteria</span> | ||||
|                                     </button> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| <div v-else> | ||||
|     <div v-if="domainObject" | ||||
|          id="conditionArea" | ||||
|          class="c-cs-ui__conditions" | ||||
|          :class="['widget-condition', { 'widget-condition--current': currentConditionIdentifier && (currentConditionIdentifier.key === conditionIdentifier.key) }]" | ||||
|     > | ||||
|         <div class="title-bar"> | ||||
|             <span class="condition-name"> | ||||
|                 {{ domainObject.configuration.name }} | ||||
|             </span> | ||||
|             <span class="condition-output"> | ||||
|                 Output: {{ domainObject.configuration.output }} | ||||
|             </span> | ||||
|         </div> | ||||
|         <div class="condition-config"> | ||||
|             <span class="condition-description"> | ||||
|                 {{ domainObject.configuration.description }} | ||||
|             </span> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import Criterion from './Criterion.vue'; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct'], | ||||
|     components: { | ||||
|         Criterion | ||||
|     }, | ||||
|     props: { | ||||
|         conditionIdentifier: { | ||||
|             type: Object, | ||||
|             required: true | ||||
|         }, | ||||
|         currentConditionIdentifier: { | ||||
|             type: Object, | ||||
|             required: true | ||||
|         }, | ||||
|         conditionIndex: { | ||||
|             type: Number, | ||||
|             required: true | ||||
|         }, | ||||
|         isEditing: { | ||||
|             type: Boolean, | ||||
|             required: true | ||||
|         }, | ||||
|         telemetry: { | ||||
|             type: Array, | ||||
|             required: true, | ||||
|             default: () => [] | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             domainObject: this.domainObject, | ||||
|             currentCriteria: this.currentCriteria, | ||||
|             expanded: true, | ||||
|             trigger: 'all', | ||||
|             selectedOutputSelection: '', | ||||
|             outputOptions: ['false', 'true', 'string'], | ||||
|             criterionIndex: 0 | ||||
|         }; | ||||
|     }, | ||||
|     destroyed() { | ||||
|         this.destroy(); | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.openmct.objects.get(this.conditionIdentifier).then((domainObject => { | ||||
|             this.domainObject = domainObject; | ||||
|             this.initialize(); | ||||
|         })); | ||||
|     }, | ||||
|     methods: { | ||||
|         initialize() { | ||||
|             this.setOutputSelection(); | ||||
|         }, | ||||
|         setOutputSelection() { | ||||
|             let conditionOutput = this.domainObject.configuration.output; | ||||
|             if (conditionOutput) { | ||||
|                 if (conditionOutput !== 'false' && conditionOutput !== 'true') { | ||||
|                     this.selectedOutputSelection = 'string'; | ||||
|                 } else { | ||||
|                     this.selectedOutputSelection = conditionOutput; | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         setOutputValue() { | ||||
|             if (this.selectedOutputSelection === 'string') { | ||||
|                 this.domainObject.configuration.output = ''; | ||||
|             } else { | ||||
|                 this.domainObject.configuration.output = this.selectedOutputSelection; | ||||
|             } | ||||
|             this.persist(); | ||||
|         }, | ||||
|         addCriteria() { | ||||
|             const criteriaObject = { | ||||
|                 telemetry: '', | ||||
|                 operation: '', | ||||
|                 input: '', | ||||
|                 metadata: '' | ||||
|             }; | ||||
|             this.domainObject.configuration.criteria.push(criteriaObject); | ||||
|         }, | ||||
|         dragStart(e) { | ||||
|             e.dataTransfer.setData('dragging', e.target); // required for FF to initiate drag | ||||
|             e.dataTransfer.effectAllowed = "copyMove"; | ||||
|             e.dataTransfer.setDragImage(e.target.closest('.c-c-container__container'), 0, 0); | ||||
|             this.$emit('setMoveIndex', this.conditionIndex); | ||||
|         }, | ||||
|         dragStop(e) { | ||||
|             e.dataTransfer.clearData(); | ||||
|         }, | ||||
|         destroy() { | ||||
|         }, | ||||
|         removeCondition(ev) { | ||||
|             this.$emit('removeCondition', this.conditionIdentifier); | ||||
|         }, | ||||
|         cloneCondition(ev) { | ||||
|             this.$emit('cloneCondition', { | ||||
|                 identifier: this.conditionIdentifier, | ||||
|                 index: Number(ev.target.closest('.widget-condition').getAttribute('data-condition-index')) | ||||
|             }); | ||||
|         }, | ||||
|         removeCriterion(index) { | ||||
|             this.domainObject.configuration.criteria.splice(index, 1); | ||||
|             this.persist() | ||||
|         }, | ||||
|         cloneCriterion(index) { | ||||
|             const clonedCriterion = {...this.domainObject.configuration.criteria[index]}; | ||||
|             this.domainObject.configuration.criteria.splice(index + 1, 0, clonedCriterion); | ||||
|             this.persist() | ||||
|         }, | ||||
|         hasTelemetry(identifier) { | ||||
|             // TODO: check parent domainObject.composition.hasTelemetry | ||||
|             return this.currentCriteria && identifier; | ||||
|         }, | ||||
|         persist() { | ||||
|             this.openmct.objects.mutate(this.domainObject, 'configuration', this.domainObject.configuration); | ||||
|         }, | ||||
|         initCap: function (string) { | ||||
|             return string.charAt(0).toUpperCase() + string.slice(1) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| </script> | ||||
|  | ||||
|  | ||||
							
								
								
									
										207
									
								
								src/plugins/condition/components/ConditionCollection.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								src/plugins/condition/components/ConditionCollection.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <section id="conditionCollection" | ||||
|          class="c-cs__ui_section" | ||||
| > | ||||
|     <div class="c-cs__ui__header"> | ||||
|         <span class="c-cs__ui__header-label">Conditions</span> | ||||
|         <span | ||||
|             class="is-enabled flex-elem" | ||||
|             :class="['c-cs__disclosure-triangle', { 'c-cs__disclosure-triangle--expanded': expanded }]" | ||||
|             @click="expanded = !expanded" | ||||
|         ></span> | ||||
|     </div> | ||||
|     <div v-if="expanded" | ||||
|          class="c-cs__ui_content" | ||||
|     > | ||||
|         <div v-show="isEditing" | ||||
|              class="help" | ||||
|         > | ||||
|             <span>The first condition to match is the one that wins. Drag conditions to rearrange.</span> | ||||
|         </div> | ||||
|         <div class="holder add-condition-button-wrapper align-left"> | ||||
|             <button | ||||
|                 v-show="isEditing" | ||||
|                 id="addCondition" | ||||
|                 class="c-cs-button c-cs-button--major add-condition-button" | ||||
|                 @click="addCondition" | ||||
|             > | ||||
|                 <span class="c-cs-button__label">Add Condition</span> | ||||
|             </button> | ||||
|         </div> | ||||
|         <div class="c-c__condition-collection"> | ||||
|             <ul class="c-c__container-holder"> | ||||
|                 <li v-for="(conditionIdentifier, index) in conditionCollection" | ||||
|                     :key="conditionIdentifier.key" | ||||
|                 > | ||||
|                     <div v-if="isEditing" | ||||
|                          class="c-c__drag-ghost" | ||||
|                          @drop.prevent="dropCondition" | ||||
|                          @dragenter="dragEnter" | ||||
|                          @dragleave="dragLeave" | ||||
|                          @dragover.prevent | ||||
|                     ></div> | ||||
|                     <Condition :condition-identifier="conditionIdentifier" | ||||
|                                :current-condition-identifier="currentConditionIdentifier" | ||||
|                                :condition-index="index" | ||||
|                                :telemetry="telemetryObjs" | ||||
|                                :is-editing="isEditing" | ||||
|                                @removeCondition="removeCondition" | ||||
|                                @cloneCondition="cloneCondition" | ||||
|                                @setMoveIndex="setMoveIndex" | ||||
|                     /> | ||||
|                 </li> | ||||
|             </ul> | ||||
|         </div> | ||||
|     </div> | ||||
| </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import Condition from './Condition.vue'; | ||||
| import ConditionManager from '../ConditionManager'; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct', 'domainObject'], | ||||
|     components: { | ||||
|         Condition | ||||
|     }, | ||||
|     props: { | ||||
|         isEditing: Boolean | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             expanded: true, | ||||
|             parentKeyString: this.openmct.objects.makeKeyString(this.domainObject.identifier), | ||||
|             conditionCollection: [], | ||||
|             conditionResults: {}, | ||||
|             conditions: [], | ||||
|             currentConditionIdentifier: this.currentConditionIdentifier || {}, | ||||
|             telemetryObjs: [], | ||||
|             moveIndex: Number, | ||||
|             isDragging: false | ||||
|         }; | ||||
|     }, | ||||
|     destroyed() { | ||||
|         this.composition.off('add', this.addTelemetryObject); | ||||
|         this.composition.off('remove', this.removeTelemetryObject); | ||||
|         if(this.conditionManager) { | ||||
|             this.conditionManager.destroy(); | ||||
|         } | ||||
|         if (typeof this.stopObservingForChanges === 'function') { | ||||
|             this.stopObservingForChanges(); | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.composition = this.openmct.composition.get(this.domainObject); | ||||
|         this.composition.on('add', this.addTelemetryObject); | ||||
|         this.composition.on('remove', this.removeTelemetryObject); | ||||
|         this.composition.load(); | ||||
|         this.conditionCollection = this.domainObject.configuration.conditionCollection; | ||||
|         this.conditionManager = new ConditionManager(this.domainObject, this.openmct); | ||||
|         this.observeForChanges(); | ||||
|     }, | ||||
|     methods: { | ||||
|         observeForChanges() { | ||||
|             this.stopObservingForChanges = this.openmct.objects.observe(this.domainObject, '*', (newDomainObject) => { | ||||
|                 this.conditionCollection = newDomainObject.configuration.conditionCollection; | ||||
|             }); | ||||
|         }, | ||||
|         setMoveIndex(index) { | ||||
|             this.moveIndex = index; | ||||
|             this.isDragging = true; | ||||
|         }, | ||||
|         dropCondition(e) { | ||||
|             let targetIndex = Array.from(document.querySelectorAll('.c-c__drag-ghost')).indexOf(e.target); | ||||
|             if (targetIndex > this.moveIndex) { targetIndex-- } // for 'downward' move | ||||
|             const oldIndexArr = Object.keys(this.conditionCollection); | ||||
|             const move = function (arr, old_index, new_index) { | ||||
|                 while (old_index < 0) { | ||||
|                     old_index += arr.length; | ||||
|                 } | ||||
|                 while (new_index < 0) { | ||||
|                     new_index += arr.length; | ||||
|                 } | ||||
|                 if (new_index >= arr.length) { | ||||
|                     var k = new_index - arr.length; | ||||
|                     while ((k--) + 1) { | ||||
|                         arr.push(undefined); | ||||
|                     } | ||||
|                 } | ||||
|                 arr.splice(new_index, 0, arr.splice(old_index, 1)[0]); | ||||
|                 return arr; | ||||
|             } | ||||
|             const newIndexArr = move(oldIndexArr, this.moveIndex, targetIndex); | ||||
|             const reorderPlan = []; | ||||
|  | ||||
|             for (let i = 0; i < oldIndexArr.length; i++) { | ||||
|                 reorderPlan.push({oldIndex: Number(newIndexArr[i]), newIndex: i}); | ||||
|             } | ||||
|  | ||||
|             this.reorder(reorderPlan); | ||||
|  | ||||
|             e.target.classList.remove("dragging"); | ||||
|             this.isDragging = false; | ||||
|         }, | ||||
|         dragEnter(e) { | ||||
|             if (!this.isDragging) { return } | ||||
|             let targetIndex = Array.from(document.querySelectorAll('.c-c__drag-ghost')).indexOf(e.target); | ||||
|             if (targetIndex > this.moveIndex) { targetIndex-- } // for 'downward' move | ||||
|             if (this.moveIndex === targetIndex) { return } | ||||
|             e.target.classList.add("dragging"); | ||||
|         }, | ||||
|         dragLeave(e) { | ||||
|             e.target.classList.remove("dragging"); | ||||
|         }, | ||||
|         addTelemetryObject(domainObject) { | ||||
|             this.telemetryObjs.push(domainObject); | ||||
|         }, | ||||
|         removeTelemetryObject(identifier) { | ||||
|             let index = _.findIndex(this.telemetryObjs, (obj) => { | ||||
|                 let objId = this.openmct.objects.makeKeyString(obj.identifier); | ||||
|                 let id = this.openmct.objects.makeKeyString(identifier); | ||||
|                 return objId === id; | ||||
|             }); | ||||
|             if (index > -1) { | ||||
|                 this.telemetryObjs.splice(index, 1); | ||||
|             } | ||||
|         }, | ||||
|         addCondition(event, isDefault, index) { | ||||
|             this.conditionManager.addCondition(!!isDefault, index); | ||||
|         }, | ||||
|         updateCurrentCondition(identifier) { | ||||
|             this.currentConditionIdentifier = identifier; | ||||
|         }, | ||||
|         removeCondition(identifier) { | ||||
|             this.conditionManager.removeCondition(identifier); | ||||
|         }, | ||||
|         reorder(reorderPlan) { | ||||
|             this.conditionManager.reorderConditions(reorderPlan); | ||||
|         }, | ||||
|         cloneCondition(condition) { | ||||
|             this.conditionManager.cloneCondition(condition.identifier, condition.index); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| </script> | ||||
							
								
								
									
										83
									
								
								src/plugins/condition/components/ConditionSet.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/plugins/condition/components/ConditionSet.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <div class="c-cs-edit w-condition-set"> | ||||
|     <div class="c-sw-edit__ui holder"> | ||||
|         <section id="current-output"> | ||||
|             <div class="c-cs__ui__header"> | ||||
|                 <span class="c-cs__ui__header-label">Current Output</span> | ||||
|             </div> | ||||
|             <div class="c-cs__ui_content"> | ||||
|                 <span v-if="currentConditionOutput" | ||||
|                       class="current-output" | ||||
|                 > | ||||
|                     {{ currentConditionOutput }} | ||||
|                 </span> | ||||
|                 <span v-else>No output selected</span> | ||||
|             </div> | ||||
|         </section> | ||||
|         <TestData :is-editing="isEditing" /> | ||||
|         <ConditionCollection :is-editing="isEditing" /> | ||||
|     </div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import TestData from './TestData.vue'; | ||||
| import ConditionCollection from './ConditionCollection.vue'; | ||||
|  | ||||
| export default { | ||||
|     inject: ["openmct", "domainObject"], | ||||
|     components: { | ||||
|         TestData, | ||||
|         ConditionCollection | ||||
|     }, | ||||
|     props: { | ||||
|         isEditing: Boolean | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             currentConditionOutput: '' | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.conditionSetIdentifier = this.openmct.objects.makeKeyString(this.domainObject.identifier); | ||||
|         this.provideTelemetry(); | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         if (this.stopProvidingTelemetry) { | ||||
|             this.stopProvidingTelemetry(); | ||||
|         } | ||||
|     }, | ||||
|     methods: { | ||||
|         updateCurrentOutput(currentConditionResult) { | ||||
|             this.currentConditionOutput = currentConditionResult.output; | ||||
|         }, | ||||
|         provideTelemetry() { | ||||
|             this.stopProvidingTelemetry = this.openmct.telemetry | ||||
|                 .subscribe(this.domainObject, output => { this.updateCurrentOutput(output); }); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
|  | ||||
							
								
								
									
										171
									
								
								src/plugins/condition/components/Criterion.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								src/plugins/condition/components/Criterion.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | ||||
| <template> | ||||
| <div> | ||||
|     <label>{{ setRowLabel }}</label> | ||||
|     <span class="t-configuration"> | ||||
|         <span class="controls"> | ||||
|             <select v-model="criterion.telemetry" | ||||
|                     @change="updateMetadataOptions" | ||||
|             > | ||||
|                 <option value="">- Select Telemetry -</option> | ||||
|                 <option v-for="telemetryOption in telemetry" | ||||
|                         :key="telemetryOption.identifier.key" | ||||
|                         :value="telemetryOption.identifier" | ||||
|                 > | ||||
|                     {{ telemetryOption.name }} | ||||
|                 </option> | ||||
|             </select> | ||||
|         </span> | ||||
|         <span v-if="criterion.telemetry" | ||||
|               class="controls" | ||||
|         > | ||||
|             <select v-model="criterion.metadata" | ||||
|                     @change="updateOperations" | ||||
|             > | ||||
|                 <option value="">- Select Field -</option> | ||||
|                 <option v-for="option in telemetryMetadataOptions" | ||||
|                         :key="option.key" | ||||
|                         :value="option.key" | ||||
|                 > | ||||
|                     {{ option.name }} | ||||
|                 </option> | ||||
|             </select> | ||||
|         </span> | ||||
|         <span v-if="criterion.telemetry && criterion.metadata" | ||||
|               class="controls" | ||||
|         > | ||||
|             <select v-model="criterion.operation" | ||||
|                     @change="updateOperationInputVisibility" | ||||
|             > | ||||
|                 <option value="">- Select Comparison -</option> | ||||
|                 <option v-for="option in filteredOps" | ||||
|                         :key="option.name" | ||||
|                         :value="option.name" | ||||
|                 > | ||||
|                     {{ option.text }} | ||||
|                 </option> | ||||
|             </select> | ||||
|             <span v-for="(item, inputIndex) in inputCount" | ||||
|                   :key="inputIndex" | ||||
|             > | ||||
|                 <input v-model="criterion.input[inputIndex]" | ||||
|                        class="t-condition-name-input" | ||||
|                        type="text" | ||||
|                        @blur="persist" | ||||
|                 > | ||||
|                 <span v-if="inputIndex < inputCount-1">and</span> | ||||
|             </span> | ||||
|         </span> | ||||
|     </span> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { OPERATIONS } from '../utils/operations'; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct'], | ||||
|     props: { | ||||
|         criterion: { | ||||
|             type: Object, | ||||
|             required: true | ||||
|         }, | ||||
|         telemetry: { | ||||
|             type: Array, | ||||
|             required: true, | ||||
|             default: () => [] | ||||
|         }, | ||||
|         index: { | ||||
|             type: Number, | ||||
|             required: true | ||||
|         }, | ||||
|         trigger: { | ||||
|             type: String, | ||||
|             required: true | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             telemetryMetadata: {}, | ||||
|             telemetryMetadataOptions: {}, | ||||
|             operations: OPERATIONS, | ||||
|             inputCount: 0, | ||||
|             rowLabel: '', | ||||
|             operationFormat: '' | ||||
|         } | ||||
|     }, | ||||
|     computed: { | ||||
|         setRowLabel: function () { | ||||
|             let operator = this.trigger === 'all' ? 'and ': 'or '; | ||||
|             return (this.index !== 0 ? operator : '') + 'when'; | ||||
|         }, | ||||
|         filteredOps: function () { | ||||
|             return [...this.operations.filter(op => op.appliesTo.indexOf(this.operationFormat) !== -1)]; | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.updateMetadataOptions(); | ||||
|     }, | ||||
|     methods: { | ||||
|         getOperationFormat() { | ||||
|             this.telemetryMetadata.valueMetadatas.forEach((value, index) => { | ||||
|                 if (value.key === this.criterion.metadata) { | ||||
|                     let valueMetadata = this.telemetryMetadataOptions[index]; | ||||
|                     if (valueMetadata.enumerations !== undefined) { | ||||
|                         this.operationFormat = 'enum'; | ||||
|                     } else if (valueMetadata.hints.hasOwnProperty('range')) { | ||||
|                         this.operationFormat = 'number'; | ||||
|                     } else if (valueMetadata.hints.hasOwnProperty('domain')) { | ||||
|                         this.operationFormat = 'number'; | ||||
|                     } else if (valueMetadata.key === 'name') { | ||||
|                         this.operationFormat = 'string'; | ||||
|                     } else { | ||||
|                         this.operationFormat = 'string'; | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         updateMetadataOptions(ev) { | ||||
|             if (ev) {this.clearInputs()} | ||||
|             if (this.criterion.telemetry) { | ||||
|                 this.openmct.objects.get(this.criterion.telemetry).then((telemetryObject) => { | ||||
|                     this.telemetryMetadata = this.openmct.telemetry.getMetadata(telemetryObject); | ||||
|                     this.telemetryMetadataOptions = this.telemetryMetadata.values(); | ||||
|                     this.updateOperations(); | ||||
|                     this.updateOperationInputVisibility(); | ||||
|                 }); | ||||
|             } else { | ||||
|                 this.criterion.metadata = ''; | ||||
|             } | ||||
|         }, | ||||
|         updateOperations(ev) { | ||||
|             if (ev) {this.clearInputs()} | ||||
|             this.getOperationFormat(); | ||||
|             this.persist(); | ||||
|         }, | ||||
|         updateOperationInputVisibility(ev) { | ||||
|             if (ev) { | ||||
|                 this.criterion.input = []; | ||||
|                 this.inputCount = 0; | ||||
|             } | ||||
|             for (let i = 0; i < this.filteredOps.length; i++) { | ||||
|                 if (this.criterion.operation === this.filteredOps[i].name) { | ||||
|                     this.inputCount = this.filteredOps[i].inputCount; | ||||
|                     if (!this.inputCount) {this.criterion.input = []} | ||||
|                 } | ||||
|             } | ||||
|             this.persist(); | ||||
|         }, | ||||
|         clearInputs() { | ||||
|             this.criterion.operation = ''; | ||||
|             this.criterion.input = []; | ||||
|             this.inputCount = 0; | ||||
|         }, | ||||
|         updateMetadataSelection() { | ||||
|             this.updateOperationInputVisibility(); | ||||
|         }, | ||||
|         persist() { | ||||
|             this.$emit('persist', this.criterion); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										96
									
								
								src/plugins/condition/components/TestData.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/plugins/condition/components/TestData.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <section v-show="isEditing" | ||||
|          id="test-data" | ||||
|          class="test-data" | ||||
| > | ||||
|     <div class="c-cs__ui__header"> | ||||
|         <span class="c-cs__ui__header-label">Test Data</span> | ||||
|         <span | ||||
|             class="is-enabled flex-elem" | ||||
|             :class="['c-cs__disclosure-triangle', { 'c-cs__disclosure-triangle--expanded': expanded }]" | ||||
|             @click="expanded = !expanded" | ||||
|         ></span> | ||||
|     </div> | ||||
|     <div v-if="expanded" | ||||
|          class="c-cs__ui_content" | ||||
|     > | ||||
|         <label class="c-toggle-switch"> | ||||
|             <input | ||||
|                 type="checkbox" | ||||
|                 :checked="isApplied" | ||||
|                 @change="applyTestData" | ||||
|             > | ||||
|             <span class="c-toggle-switch__slider"></span> | ||||
|             <span>Apply Test Data</span> | ||||
|         </label> | ||||
|         <div class="t-test-data-config"> | ||||
|             <div class="c-cs-editui__conditions widget-condition"> | ||||
|                 <form> | ||||
|                     <label> | ||||
|                         <span>Set</span> | ||||
|                         <select> | ||||
|                             <option>- Select Input -</option> | ||||
|                         </select> | ||||
|                     </label> | ||||
|                     <span class="is-enabled  flex-elem c-cs__duplicate"></span> | ||||
|                     <span class="is-enabled  flex-elem c-cs__trash"></span> | ||||
|                 </form> | ||||
|             </div> | ||||
|             <div class="c-cs-editui__conditions widget-condition"> | ||||
|                 <form> | ||||
|                     <label> | ||||
|                         <span>Set</span> | ||||
|                         <select> | ||||
|                             <option>- Select Input -</option> | ||||
|                         </select> | ||||
|                     </label> | ||||
|                     <span class="is-enabled c-cs__duplicate"></span> | ||||
|                     <span class="is-enabled c-cs__trash"></span> | ||||
|                 </form> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|     inject: ['openmct'], | ||||
|     props: { | ||||
|         isEditing: Boolean | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             expanded: true, | ||||
|             isApplied: true | ||||
|         }; | ||||
|     }, | ||||
|     methods: { | ||||
|         applyTestData(ev) { | ||||
|             this.$emit('change', ev.target.checked); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| </script> | ||||
							
								
								
									
										155
									
								
								src/plugins/condition/components/condition-set.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/plugins/condition/components/condition-set.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| .c-cs-edit { | ||||
|     padding: 0; | ||||
| } | ||||
|  | ||||
| section { | ||||
|     padding-bottom: 5px; | ||||
| } | ||||
|  | ||||
| .c-cs__ui__header { | ||||
|     background-color: #D0D1D3; | ||||
|     padding: 0.4em 0.6em; | ||||
|     text-transform: uppercase; | ||||
|     font-size: 0.8em; | ||||
|     font-weight: bold; | ||||
|     color: #7C7D80; | ||||
|     display: flex; | ||||
|     justify-content: stretch; | ||||
|     align-items: center; | ||||
| } | ||||
|  | ||||
| .c-cs__ui__header-label { | ||||
|     display: inline-block; | ||||
|     width: 100%; | ||||
| } | ||||
|  | ||||
| .c-cs__ui_content { | ||||
|     padding: 0.4em; | ||||
| } | ||||
|  | ||||
| .c-cs-ui__label { | ||||
|     color: #333; | ||||
| } | ||||
|  | ||||
| .c-cs__ui_content .help { | ||||
|     font-style: italic; | ||||
|     padding: 0.4em 0; | ||||
| } | ||||
|  | ||||
| .current-output { | ||||
|     text-transform: uppercase; | ||||
|     font-weight: bold; | ||||
|     margin: 0.4em 0.6em; | ||||
| } | ||||
|  | ||||
| .condition-output { | ||||
|     color: #999; | ||||
| } | ||||
|  | ||||
| .condition-description { | ||||
|     color: #333; | ||||
| } | ||||
|  | ||||
| .checkbox.custom { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     margin-left: 0.6em; | ||||
| } | ||||
| .checkbox.custom span { | ||||
|     display: inline-block; | ||||
|     margin-left: 0.6em; | ||||
| } | ||||
|  | ||||
| .t-test-data-config { | ||||
|     margin-top: 5px; | ||||
| } | ||||
|  | ||||
| .c-c__condition-collection.is-disabled { | ||||
|     opacity: 0.5; | ||||
| } | ||||
|  | ||||
| .widget-condition form { | ||||
|     padding: 0.5em; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: stretch; | ||||
| } | ||||
|  | ||||
| .widget-condition form label { | ||||
|     flex-grow: 1; | ||||
|     margin-left: 0; | ||||
| } | ||||
|  | ||||
| .widget-condition form input { | ||||
|     min-height: 24px; | ||||
| } | ||||
|  | ||||
| .c-cs-button[class*="--major"], | ||||
| .c-cs-button[class*='is-active'], | ||||
| .c-cs-button--menu[class*="--major"], | ||||
| .c-cs-button--menu[class*='is-active'] { | ||||
|     border: solid 1px #0B427C; | ||||
|     background-color: #4778A3; | ||||
|     padding: 0.2em 0.6em; | ||||
|     margin: 0.4em; | ||||
|     font-weight: bold; | ||||
|     color: #eee; | ||||
|     border-radius: 6px; | ||||
|  | ||||
|     &.is-disabled { | ||||
|         opacity: 0.5; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-cs__disclosure-triangle, | ||||
| .c-cs__menu-hamburger, | ||||
| .c-cs__duplicate, | ||||
| .c-cs__trash { | ||||
|     $d: 8px; | ||||
|     color: $colorDisclosureCtrl; | ||||
|     width: $d; | ||||
|     visibility: hidden; | ||||
|  | ||||
|     &.is-enabled { | ||||
|         cursor: pointer; | ||||
|         visibility: visible; | ||||
|  | ||||
|         &:hover { | ||||
|             color: $colorDisclosureCtrlHov; | ||||
|         } | ||||
|  | ||||
|         &:before { | ||||
|             $s: .5; | ||||
|             display: block; | ||||
|             font-family: symbolsfont; | ||||
|             font-size: 1rem * $s; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-cs__disclosure-triangle { | ||||
|     &:before { | ||||
|         content: $glyph-icon-arrow-right; | ||||
|     } | ||||
|  | ||||
|     &--expanded { | ||||
|         &:before { | ||||
|             transform: rotate(90deg); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-cs__duplicate { | ||||
|     margin-right: 0.3em; | ||||
|     &:before { | ||||
|         content: $glyph-icon-duplicate; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-cs__trash { | ||||
|     &:before { | ||||
|         content: $glyph-icon-trash; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										208
									
								
								src/plugins/condition/components/condition.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								src/plugins/condition/components/condition.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,208 @@ | ||||
| .widget-condition { | ||||
|     background-color: #eee; | ||||
|     margin: 0 0 0.33em; | ||||
|     border-radius: 3px; | ||||
|  | ||||
|     &--current { | ||||
|         background-color: #DEECFA; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| .c-c-editui__conditions.widget-condition { | ||||
|     margin: 0; | ||||
| } | ||||
|  | ||||
| .c-c-button-wrapper { | ||||
|     border-top: solid 1px #ccc; | ||||
|     padding: 2px; | ||||
| } | ||||
|  | ||||
| .c-c-label-spacer { | ||||
|     display: inline-block; | ||||
|     width: 90px; | ||||
| } | ||||
|  | ||||
| .c-c-button[class*="--minor"], | ||||
| .c-c-button[class*='is-active'], | ||||
| .c-c-button--menu[class*="--minor"], | ||||
| .c-c-button--menu[class*='is-active'] { | ||||
|     border: solid 1px #666; | ||||
|     background-color: #fff; | ||||
|     padding: 0.1em 0.4em; | ||||
|     margin: 0.4em; | ||||
|     font-weight: normal; | ||||
|     color: #666; | ||||
|     border-radius: 6px; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| .title-bar { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: stretch; | ||||
|     padding: 0.4em 0; | ||||
| } | ||||
|  | ||||
| .title-bar span { | ||||
|     margin-right: 0.6em; | ||||
| } | ||||
|  | ||||
| .title-bar span.c-c__duplicate, | ||||
| .title-bar span.c-c__trash{ | ||||
|     margin-right: 0; | ||||
|     margin-left: 0.3em; | ||||
| } | ||||
|  | ||||
| .widget-condition > div { | ||||
|     margin: 0 0.4em; | ||||
| } | ||||
|  | ||||
| .condition-name { | ||||
|     font-weight: bold; | ||||
| } | ||||
|  | ||||
| .condition-summary .condition-description { | ||||
|     color: #999; | ||||
| } | ||||
|  | ||||
| .condition-summary { | ||||
|     flex-grow: 1; | ||||
| } | ||||
|  | ||||
| .condition-config { | ||||
|     padding: 0.3em 0; | ||||
| } | ||||
|  | ||||
| .widget-condition form label { | ||||
|     flex-grow: 1; | ||||
|     margin-left: 0; | ||||
| } | ||||
|  | ||||
| .l-widget-condition { | ||||
|     padding: 0; | ||||
| } | ||||
|  | ||||
| .l-compact-form ul li { | ||||
|     padding: 0; | ||||
| } | ||||
|  | ||||
| .widget-condition-content.expanded { | ||||
|     margin: 0 3px; | ||||
| } | ||||
|  | ||||
| .widget-condition-content.expanded ul li { | ||||
|     border-top: solid 1px #ccc; | ||||
|     padding: 2px; | ||||
| } | ||||
|  | ||||
| .l-compact-form ul li .controls { | ||||
|     display: inline-flex; | ||||
|     flex-grow: inherit; | ||||
|     padding: 2px 0; | ||||
| } | ||||
|  | ||||
| .l-compact-form ul li > label { | ||||
|     display: block; | ||||
|     width: 90px; | ||||
|     min-width: 90px; | ||||
|     text-align: right; | ||||
|     line-height: 20px; | ||||
| } | ||||
|  | ||||
| .l-compact-form ul li .controls input[type="text"], | ||||
| .l-compact-form ul li .controls input[type="search"], | ||||
| .l-compact-form ul li .controls input[type="number"], | ||||
| .l-compact-form ul li .controls button, | ||||
| .l-compact-form ul li .controls select { | ||||
|     min-height: 20px; | ||||
| } | ||||
|  | ||||
| .condition-config-edit { | ||||
|     padding: 3px 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| .c-c__disclosure-triangle, | ||||
| .c-c__menu-hamburger, | ||||
| .c-c__duplicate, | ||||
| .c-c__trash { | ||||
|     $d: 8px; | ||||
|     color: $colorDisclosureCtrl; | ||||
|     width: $d; | ||||
|     visibility: hidden; | ||||
|  | ||||
|     &.is-enabled { | ||||
|         cursor: pointer; | ||||
|         visibility: visible; | ||||
|  | ||||
|         &:hover { | ||||
|             color: $colorDisclosureCtrlHov; | ||||
|         } | ||||
|  | ||||
|         &:before { | ||||
|             $s: .5; | ||||
|             display: block; | ||||
|             font-family: symbolsfont; | ||||
|             font-size: 1rem * $s; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-c__disclosure-triangle { | ||||
|     &:before { | ||||
|         content: $glyph-icon-arrow-right; | ||||
|     } | ||||
|  | ||||
|     &--expanded { | ||||
|         &:before { | ||||
|             transform: rotate(90deg); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| .c-c__menu-hamburger { | ||||
|     &:active { | ||||
|         cursor: grabbing; | ||||
|         cursor: -moz-grabbing; | ||||
|         cursor: -webkit-grabbing; | ||||
|     } | ||||
|  | ||||
|     &:before { | ||||
|         content: $glyph-icon-menu-hamburger; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-c__duplicate { | ||||
|     &:before { | ||||
|         content: $glyph-icon-duplicate; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-c__trash { | ||||
|     &:before { | ||||
|         content: $glyph-icon-trash; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-c__drag-ghost { | ||||
|     width: 100%; | ||||
|     min-height: 0.33em; | ||||
|     &.dragging { | ||||
|         min-height: 2em; | ||||
|         border: solid 1px blue; | ||||
|         background-color: lightblue; | ||||
|         border-radius: 2px; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-c__criterion-controls { | ||||
|     width: 28px; | ||||
|  | ||||
|     .c-c__duplicate, | ||||
|     .c-c__trash { | ||||
|         display: inline-block; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,14 @@ | ||||
| <template> | ||||
| <div>Conditional Styles inspector view</div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|     components: { | ||||
|     }, | ||||
|     inject: [ | ||||
|         'openmct' | ||||
|     ] | ||||
| } | ||||
| </script> | ||||
							
								
								
									
										138
									
								
								src/plugins/condition/criterion/TelemetryCriterion.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/plugins/condition/criterion/TelemetryCriterion.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import * as EventEmitter from 'eventemitter3'; | ||||
| import {OPERATIONS} from '../utils/operations'; | ||||
|  | ||||
| export default class TelemetryCriterion extends EventEmitter { | ||||
|  | ||||
|     /** | ||||
|      * Subscribes/Unsubscribes to telemetry and emits the result | ||||
|      * of operations performed on the telemetry data returned and a given input value. | ||||
|      * @constructor | ||||
|      * @param telemetryDomainObjectDefinition {id: uuid, operation: enum, input: Array, metadata: string, key: {domainObject.identifier} } | ||||
|      * @param openmct | ||||
|      */ | ||||
|     constructor(telemetryDomainObjectDefinition, openmct) { | ||||
|         super(); | ||||
|  | ||||
|         this.openmct = openmct; | ||||
|         this.objectAPI = this.openmct.objects; | ||||
|         this.telemetryAPI = this.openmct.telemetry; | ||||
|         this.timeAPI = this.openmct.time; | ||||
|         this.id = telemetryDomainObjectDefinition.id; | ||||
|         this.telemetry = telemetryDomainObjectDefinition.telemetry; | ||||
|         this.operation = telemetryDomainObjectDefinition.operation; | ||||
|         this.input = telemetryDomainObjectDefinition.input; | ||||
|         this.metadata = telemetryDomainObjectDefinition.metadata; | ||||
|         this.subscription = null; | ||||
|         this.telemetryObjectIdAsString = null; | ||||
|         this.objectAPI.get(this.objectAPI.makeKeyString(this.telemetry)).then((obj) => this.initialize(obj)); | ||||
|     } | ||||
|  | ||||
|     initialize(obj) { | ||||
|         this.telemetryObject = obj; | ||||
|         this.telemetryObjectIdAsString = this.objectAPI.makeKeyString(this.telemetryObject.identifier); | ||||
|         this.emitEvent('criterionUpdated', this); | ||||
|     } | ||||
|  | ||||
|     handleSubscription(data) { | ||||
|         const datum = {}; | ||||
|         const timeSystemKey = this.timeAPI.timeSystem().key; | ||||
|  | ||||
|         datum.result = this.computeResult(data); | ||||
|         if (data && data[timeSystemKey]) { | ||||
|             datum[timeSystemKey] = data[timeSystemKey] | ||||
|         } | ||||
|  | ||||
|         this.emitEvent('criterionResultUpdated', datum); | ||||
|     } | ||||
|  | ||||
|     findOperation(operation) { | ||||
|         for (let i=0, ii=OPERATIONS.length; i < ii; i++) { | ||||
|             if (operation === OPERATIONS[i].name) { | ||||
|                 return OPERATIONS[i].operation; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     computeResult(data) { | ||||
|         let result = false; | ||||
|         if (data) { | ||||
|             let comparator = this.findOperation(this.operation); | ||||
|             let params = []; | ||||
|             params.push(data[this.metadata]); | ||||
|             if (this.input instanceof Array && this.input.length) { | ||||
|                 this.input.forEach(input => params.push(input)); | ||||
|             } | ||||
|             if (typeof comparator === 'function') { | ||||
|                 result = comparator(params); | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     emitEvent(eventName, data) { | ||||
|         this.emit(eventName, { | ||||
|             id: this.id, | ||||
|             data: data | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     isValid() { | ||||
|         return this.telemetryObject && this.metadata && this.operation; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      *  Subscribes to the telemetry object and returns an unsubscribe function | ||||
|      *  If the telemetry is not valid, returns nothing | ||||
|      */ | ||||
|     subscribe() { | ||||
|         if (this.isValid()) { | ||||
|             this.unsubscribe(); | ||||
|             this.subscription = this.telemetryAPI.subscribe(this.telemetryObject, (datum) => { | ||||
|                 this.handleSubscription(datum); | ||||
|             }); | ||||
|         } else { | ||||
|             this.handleSubscription(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      *  Calls an unsubscribe function returned by subscribe() and deletes any initialized data | ||||
|      */ | ||||
|     unsubscribe() { | ||||
|         //unsubscribe from telemetry source | ||||
|         if (typeof this.subscription === 'function') { | ||||
|             this.subscription(); | ||||
|         } | ||||
|         delete this.subscription; | ||||
|     } | ||||
|  | ||||
|     destroy() { | ||||
|         this.unsubscribe(); | ||||
|         this.emitEvent('criterionRemoved'); | ||||
|         delete this.telemetryObjectIdAsString; | ||||
|         delete this.telemetryObject; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										122
									
								
								src/plugins/condition/criterion/TelemetryCriterionSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								src/plugins/condition/criterion/TelemetryCriterionSpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import TelemetryCriterion from "./TelemetryCriterion"; | ||||
|  | ||||
| let openmct = {}, | ||||
|     mockListener, | ||||
|     mockListener2, | ||||
|     testCriterionDefinition, | ||||
|     testTelemetryObject, | ||||
|     telemetryCriterion; | ||||
|  | ||||
| describe("The telemetry criterion", function () { | ||||
|  | ||||
|     beforeEach (() => { | ||||
|         testTelemetryObject = { | ||||
|             identifier:{ namespace: "", key: "test-object"}, | ||||
|             type: "test-object", | ||||
|             name: "Test Object", | ||||
|             telemetry: { | ||||
|                 values: [{ | ||||
|                     key: "some-key", | ||||
|                     name: "Some attribute", | ||||
|                     hints: { | ||||
|                         domain: 1 | ||||
|                     } | ||||
|                 }, { | ||||
|                     key: "some-other-key", | ||||
|                     name: "Another attribute", | ||||
|                     hints: { | ||||
|                         range: 1 | ||||
|                     } | ||||
|                 }] | ||||
|             } | ||||
|         }; | ||||
|         openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']); | ||||
|         openmct.objects.get.and.returnValue(new Promise(function (resolve, reject) { | ||||
|             resolve(testTelemetryObject); | ||||
|         })); | ||||
|         openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key); | ||||
|         openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', "subscribe", "getMetadata"]); | ||||
|         openmct.telemetry.isTelemetryObject.and.returnValue(true); | ||||
|         openmct.telemetry.subscribe.and.returnValue(function () {}); | ||||
|         openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry.values); | ||||
|  | ||||
|         openmct.time = jasmine.createSpyObj('timeAPI', | ||||
|             ['timeSystem', 'bounds'] | ||||
|         ); | ||||
|         openmct.time.timeSystem.and.returnValue({key: 'system'}); | ||||
|         openmct.time.bounds.and.returnValue({start: 0, end: 1}); | ||||
|  | ||||
|         testCriterionDefinition = { | ||||
|             id: 'test-criterion-id', | ||||
|             telemetry: openmct.objects.makeKeyString(testTelemetryObject.identifier) | ||||
|         }; | ||||
|  | ||||
|         mockListener = jasmine.createSpy('listener'); | ||||
|         mockListener2 = jasmine.createSpy('updatedListener', (data) => { | ||||
|             console.log(data); | ||||
|         }); | ||||
|  | ||||
|         telemetryCriterion = new TelemetryCriterion( | ||||
|             testCriterionDefinition, | ||||
|             openmct | ||||
|         ); | ||||
|  | ||||
|         telemetryCriterion.on('criterionResultUpdated', mockListener); | ||||
|         telemetryCriterion.on('criterionUpdated', mockListener2); | ||||
|  | ||||
|     }); | ||||
|  | ||||
|     it("initializes with a telemetry objectId as string", function () { | ||||
|         telemetryCriterion.initialize(testTelemetryObject); | ||||
|         expect(telemetryCriterion.telemetryObjectIdAsString).toEqual(testTelemetryObject.identifier.key); | ||||
|         expect(mockListener2).toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it("subscribes to telemetry providers", function () { | ||||
|         telemetryCriterion.subscribe(); | ||||
|         expect(telemetryCriterion.subscription).toBeDefined(); | ||||
|     }); | ||||
|  | ||||
|     it("emits update event on new data from telemetry providers", function () { | ||||
|         spyOn(telemetryCriterion, 'emitEvent').and.callThrough(); | ||||
|         telemetryCriterion.handleSubscription({ | ||||
|             key: 'some-key', | ||||
|             source: 'testSource', | ||||
|             testSource: 'Hello' | ||||
|         }); | ||||
|         expect(telemetryCriterion.emitEvent).toHaveBeenCalled(); | ||||
|         expect(mockListener).toHaveBeenCalled(); | ||||
|     }); | ||||
|  | ||||
|     it("un-subscribes from telemetry providers", function () { | ||||
|         telemetryCriterion.subscribe(); | ||||
|         expect(telemetryCriterion.subscription).toBeDefined(); | ||||
|         telemetryCriterion.destroy(); | ||||
|         expect(telemetryCriterion.subscription).toBeUndefined(); | ||||
|         expect(telemetryCriterion.telemetryObjectIdAsString).toBeUndefined(); | ||||
|         expect(telemetryCriterion.telemetryObject).toBeUndefined(); | ||||
|     }); | ||||
|  | ||||
| }); | ||||
							
								
								
									
										61
									
								
								src/plugins/condition/plugin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/plugins/condition/plugin.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
| import ConditionSetViewProvider from './ConditionSetViewProvider.js'; | ||||
| import ConditionSetCompositionPolicy from "./ConditionSetCompositionPolicy"; | ||||
| import ConditionSetMetadataProvider from './ConditionSetMetadataProvider'; | ||||
| import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider'; | ||||
|  | ||||
| export default function ConditionPlugin() { | ||||
|  | ||||
|     return function install(openmct) { | ||||
|         openmct.types.addType('condition', { | ||||
|             name: 'Condition', | ||||
|             key: 'condition', | ||||
|             description: 'A list of criteria which will be evaluated based on a trigger', | ||||
|             creatable: false, | ||||
|             initialize: function (domainObject) { | ||||
|                 domainObject.composition = []; | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         openmct.types.addType('conditionSet', { | ||||
|             name: 'Condition Set', | ||||
|             key: 'conditionSet', | ||||
|             description: 'A set of one or more conditions based on user-specified criteria.', | ||||
|             creatable: true, | ||||
|             cssClass: 'icon-conditional',  // TODO: replace with class for new icon | ||||
|             initialize: function (domainObject) { | ||||
|                 domainObject.configuration = { | ||||
|                     conditionCollection: [] | ||||
|                 }; | ||||
|                 domainObject.composition = []; | ||||
|                 domainObject.telemetry = {}; | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         openmct.composition.addPolicy(new ConditionSetCompositionPolicy(openmct).allow); | ||||
|         openmct.telemetry.addProvider(new ConditionSetMetadataProvider(openmct)); | ||||
|         openmct.telemetry.addProvider(new ConditionSetTelemetryProvider(openmct)); | ||||
|         openmct.objectViews.addProvider(new ConditionSetViewProvider(openmct)); | ||||
|  | ||||
|     } | ||||
| } | ||||
							
								
								
									
										128
									
								
								src/plugins/condition/pluginSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/plugins/condition/pluginSpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import { createOpenMct } from "testTools"; | ||||
| import ConditionPlugin from "./plugin"; | ||||
|  | ||||
| let openmct = createOpenMct(); | ||||
| openmct.install(new ConditionPlugin()); | ||||
|  | ||||
| let conditionDefinition; | ||||
| let conditionSetDefinition; | ||||
| let mockDomainObject; | ||||
| let mockDomainObject2; | ||||
| let element; | ||||
| let child; | ||||
|  | ||||
| describe('the plugin', function () { | ||||
|  | ||||
|     beforeAll((done) => { | ||||
|         conditionDefinition = openmct.types.get('condition').definition; | ||||
|         mockDomainObject = { | ||||
|             identifier: { | ||||
|                 key: 'testConditionKey', | ||||
|                 namespace: '' | ||||
|             }, | ||||
|             type: 'condition' | ||||
|         }; | ||||
|  | ||||
|         conditionDefinition.initialize(mockDomainObject); | ||||
|  | ||||
|         conditionSetDefinition = openmct.types.get('conditionSet').definition; | ||||
|         const appHolder = document.createElement('div'); | ||||
|         appHolder.style.width = '640px'; | ||||
|         appHolder.style.height = '480px'; | ||||
|  | ||||
|         element = document.createElement('div'); | ||||
|         child = document.createElement('div'); | ||||
|         element.appendChild(child); | ||||
|  | ||||
|         mockDomainObject2 = { | ||||
|             identifier: { | ||||
|                 key: 'testConditionSetKey', | ||||
|                 namespace: '' | ||||
|             }, | ||||
|             type: 'conditionSet' | ||||
|         }; | ||||
|  | ||||
|         conditionSetDefinition.initialize(mockDomainObject2); | ||||
|  | ||||
|         openmct.on('start', done); | ||||
|         openmct.start(appHolder); | ||||
|     }); | ||||
|  | ||||
|     let mockConditionObject = { | ||||
|         name: 'Condition', | ||||
|         key: 'condition', | ||||
|         creatable: false | ||||
|     }; | ||||
|  | ||||
|     it('defines a condition object type with the correct key', () => { | ||||
|         expect(conditionDefinition.key).toEqual(mockConditionObject.key); | ||||
|     }); | ||||
|  | ||||
|     let mockConditionSetObject = { | ||||
|         name: 'Condition Set', | ||||
|         key: 'conditionSet', | ||||
|         creatable: true | ||||
|     }; | ||||
|  | ||||
|     it('defines a conditionSet object type with the correct key', () => { | ||||
|         expect(conditionSetDefinition.key).toEqual(mockConditionSetObject.key); | ||||
|     }); | ||||
|  | ||||
|     describe('the condition object', () => { | ||||
|  | ||||
|         it('is not creatable', () => { | ||||
|             expect(conditionDefinition.creatable).toEqual(mockConditionObject.creatable); | ||||
|         }); | ||||
|  | ||||
|         it('initializes with an empty composition list', () => { | ||||
|             expect(mockDomainObject.composition instanceof Array).toBeTrue(); | ||||
|             expect(mockDomainObject.composition.length).toEqual(0); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('the conditionSet object', () => { | ||||
|  | ||||
|         it('is creatable', () => { | ||||
|             expect(conditionSetDefinition.creatable).toEqual(mockConditionSetObject.creatable); | ||||
|         }); | ||||
|  | ||||
|         it('initializes with an empty composition list', () => { | ||||
|             expect(mockDomainObject2.composition instanceof Array).toBeTrue(); | ||||
|             expect(mockDomainObject2.composition.length).toEqual(0); | ||||
|         }); | ||||
|  | ||||
|         it('provides a view', () => { | ||||
|             const testViewObject = { | ||||
|                 id:"test-object", | ||||
|                 type: "conditionSet" | ||||
|             }; | ||||
|  | ||||
|             const applicableViews = openmct.objectViews.get(testViewObject); | ||||
|             let conditionSetView = applicableViews.find((viewProvider) => viewProvider.key === 'conditionSet.view'); | ||||
|             expect(conditionSetView).toBeDefined(); | ||||
|         }); | ||||
|  | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										4
									
								
								src/plugins/condition/utils/constants.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/plugins/condition/utils/constants.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| export const TRIGGER = { | ||||
|     ANY: 'any', | ||||
|     ALL: 'all' | ||||
| }; | ||||
							
								
								
									
										16
									
								
								src/plugins/condition/utils/evaluator.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/plugins/condition/utils/evaluator.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| export const computeCondition = (resultMap, allMustBeTrue) => { | ||||
|     let result = false; | ||||
|     for (let key in resultMap) { | ||||
|         if (resultMap.hasOwnProperty(key)) { | ||||
|             result = resultMap[key]; | ||||
|             if (allMustBeTrue && !result) { | ||||
|                 //If we want all conditions to be true, then even one negative result should break. | ||||
|                 break; | ||||
|             } else if (!allMustBeTrue && result) { | ||||
|                 //If we want at least one condition to be true, then even one positive result should break. | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return result; | ||||
| }; | ||||
							
								
								
									
										206
									
								
								src/plugins/condition/utils/operations.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								src/plugins/condition/utils/operations.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,206 @@ | ||||
| export const OPERATIONS = [ | ||||
|     { | ||||
|         name: 'equalTo', | ||||
|         operation: function (input) { | ||||
|             return input[0] === input[1]; | ||||
|         }, | ||||
|         text: 'is equal to', | ||||
|         appliesTo: ['number'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' == ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'notEqualTo', | ||||
|         operation: function (input) { | ||||
|             return input[0] !== input[1]; | ||||
|         }, | ||||
|         text: 'is not equal to', | ||||
|         appliesTo: ['number'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' != ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'greaterThan', | ||||
|         operation: function (input) { | ||||
|             return input[0] > input[1]; | ||||
|         }, | ||||
|         text: 'is greater than', | ||||
|         appliesTo: ['number'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' > ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'lessThan', | ||||
|         operation: function (input) { | ||||
|             return input[0] < input[1]; | ||||
|         }, | ||||
|         text: 'is less than', | ||||
|         appliesTo: ['number'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' < ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'greaterThanOrEq', | ||||
|         operation: function (input) { | ||||
|             return input[0] >= input[1]; | ||||
|         }, | ||||
|         text: 'is greater than or equal to', | ||||
|         appliesTo: ['number'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' >= ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'lessThanOrEq', | ||||
|         operation: function (input) { | ||||
|             return input[0] <= input[1]; | ||||
|         }, | ||||
|         text: 'is less than or equal to', | ||||
|         appliesTo: ['number'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' <= ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'between', | ||||
|         operation: function (input) { | ||||
|             return input[0] > input[1] && input[0] < input[2]; | ||||
|         }, | ||||
|         text: 'is between', | ||||
|         appliesTo: ['number'], | ||||
|         inputCount: 2, | ||||
|         getDescription: function (values) { | ||||
|             return ' between ' + values[0] + ' and ' + values[1]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'notBetween', | ||||
|         operation: function (input) { | ||||
|             return input[0] < input[1] || input[0] > input[2]; | ||||
|         }, | ||||
|         text: 'is not between', | ||||
|         appliesTo: ['number'], | ||||
|         inputCount: 2, | ||||
|         getDescription: function (values) { | ||||
|             return ' not between ' + values[0] + ' and ' + values[1]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'textContains', | ||||
|         operation: function (input) { | ||||
|             return input[0] && input[1] && input[0].includes(input[1]); | ||||
|         }, | ||||
|         text: 'text contains', | ||||
|         appliesTo: ['string'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' contains ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'textDoesNotContain', | ||||
|         operation: function (input) { | ||||
|             return input[0] && input[1] && !input[0].includes(input[1]); | ||||
|         }, | ||||
|         text: 'text does not contain', | ||||
|         appliesTo: ['string'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' does not contain ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'textStartsWith', | ||||
|         operation: function (input) { | ||||
|             return input[0].startsWith(input[1]); | ||||
|         }, | ||||
|         text: 'text starts with', | ||||
|         appliesTo: ['string'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' starts with ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'textEndsWith', | ||||
|         operation: function (input) { | ||||
|             return input[0].endsWith(input[1]); | ||||
|         }, | ||||
|         text: 'text ends with', | ||||
|         appliesTo: ['string'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' ends with ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'textIsExactly', | ||||
|         operation: function (input) { | ||||
|             return input[0] === input[1]; | ||||
|         }, | ||||
|         text: 'text is exactly', | ||||
|         appliesTo: ['string'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' is exactly ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'isUndefined', | ||||
|         operation: function (input) { | ||||
|             return typeof input[0] === 'undefined'; | ||||
|         }, | ||||
|         text: 'is undefined', | ||||
|         appliesTo: ['string', 'number', 'enum'], | ||||
|         inputCount: 0, | ||||
|         getDescription: function () { | ||||
|             return ' is undefined'; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'isDefined', | ||||
|         operation: function (input) { | ||||
|             return typeof input[0] !== 'undefined'; | ||||
|         }, | ||||
|         text: 'is defined', | ||||
|         appliesTo: ['string', 'number', 'enum'], | ||||
|         inputCount: 0, | ||||
|         getDescription: function () { | ||||
|             return ' is defined'; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'enumValueIs', | ||||
|         operation: function (input) { | ||||
|             return input[0] === input[1]; | ||||
|         }, | ||||
|         text: 'is', | ||||
|         appliesTo: ['enum'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' == ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'enumValueIsNot', | ||||
|         operation: function (input) { | ||||
|             return input[0] !== input[1]; | ||||
|         }, | ||||
|         text: 'is not', | ||||
|         appliesTo: ['enum'], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ' != ' + values[0]; | ||||
|         } | ||||
|     } | ||||
| ]; | ||||
| @@ -232,16 +232,18 @@ export default { | ||||
|             this.newFrameLocation = [containerIndex, insertFrameIndex]; | ||||
|         }, | ||||
|         addFrame(domainObject) { | ||||
|             let containerIndex = this.newFrameLocation.length ? this.newFrameLocation[0] : 0; | ||||
|             let container = this.containers[containerIndex]; | ||||
|             let frameIndex = this.newFrameLocation.length ? this.newFrameLocation[1] : container.frames.length; | ||||
|             let frame = new Frame(domainObject.identifier); | ||||
|             if (this.newFrameLocation.length) { | ||||
|                 let containerIndex = this.newFrameLocation[0], | ||||
|                     frameIndex = this.newFrameLocation[1], | ||||
|                     frame = new Frame(domainObject.identifier), | ||||
|                     container = this.containers[containerIndex]; | ||||
|  | ||||
|             container.frames.splice(frameIndex + 1, 0, frame); | ||||
|             sizeItems(container.frames, frame); | ||||
|                 container.frames.splice(frameIndex + 1, 0, frame); | ||||
|                 sizeItems(container.frames, frame); | ||||
|  | ||||
|             this.newFrameLocation = []; | ||||
|             this.persist(containerIndex); | ||||
|                 this.newFrameLocation = []; | ||||
|                 this.persist(containerIndex); | ||||
|             } | ||||
|         }, | ||||
|         deleteFrame(frameId) { | ||||
|             let container = this.containers | ||||
|   | ||||
| @@ -377,17 +377,13 @@ define([ | ||||
|          * @public | ||||
|          */ | ||||
|         updateFiltersAndRefresh: function (updatedFilters) { | ||||
|             if (this.filters) { | ||||
|                 this.filters = updatedFilters; | ||||
|                 this.reset(); | ||||
|                 if (this.unsubscribe) { | ||||
|                     this.unsubscribe(); | ||||
|                     delete this.unsubscribe; | ||||
|                 } | ||||
|                 this.fetch(); | ||||
|             } else { | ||||
|                 this.filters = updatedFilters; | ||||
|             this.filters = updatedFilters; | ||||
|             this.reset(); | ||||
|             if (this.unsubscribe) { | ||||
|                 this.unsubscribe(); | ||||
|                 delete this.unsubscribe; | ||||
|             } | ||||
|             this.fetch(); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2018, United States Government | ||||
|  * Open MCT, Copyright (c) 2014-2019, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
| @@ -47,6 +47,7 @@ define([ | ||||
|     './goToOriginalAction/plugin', | ||||
|     './clearData/plugin', | ||||
|     './webPage/plugin', | ||||
|     './condition/plugin', | ||||
|     './themes/espresso', | ||||
|     './themes/maelstrom', | ||||
|     './themes/snow' | ||||
| @@ -77,6 +78,7 @@ define([ | ||||
|     GoToOriginalAction, | ||||
|     ClearData, | ||||
|     WebPagePlugin, | ||||
|     ConditionPlugin, | ||||
|     Espresso, | ||||
|     Maelstrom, | ||||
|     Snow | ||||
| @@ -185,6 +187,7 @@ define([ | ||||
|     plugins.Espresso = Espresso.default; | ||||
|     plugins.Maelstrom = Maelstrom.default; | ||||
|     plugins.Snow = Snow.default; | ||||
|     plugins.Condition = ConditionPlugin.default; | ||||
|  | ||||
|     return plugins; | ||||
| }); | ||||
|   | ||||
							
								
								
									
										3
									
								
								src/styles/_constants.scss
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										3
									
								
								src/styles/_constants.scss
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -147,6 +147,7 @@ $glyph-icon-filter: '\e926'; | ||||
| $glyph-icon-filter-outline: '\e927'; | ||||
| $glyph-icon-suitcase: '\e928'; | ||||
| $glyph-icon-cursor-lock: '\e929'; | ||||
| $glyph-icon-flag: '\e92a'; | ||||
| $glyph-icon-arrows-right-left: '\ea00'; | ||||
| $glyph-icon-arrows-up-down: '\ea01'; | ||||
| $glyph-icon-bullet: '\ea02'; | ||||
| @@ -236,6 +237,7 @@ $glyph-icon-gauge: '\eb23'; | ||||
| $glyph-icon-spectra: '\eb24'; | ||||
| $glyph-icon-spectra-telemetry: '\eb25'; | ||||
| $glyph-icon-command: '\eb26'; | ||||
| $glyph-icon-conditional: '\eb27'; | ||||
|  | ||||
| /************************** GLYPHS AS DATA URI */ | ||||
| // Only objects have been converted, for use in Create menu and folder views | ||||
| @@ -285,3 +287,4 @@ $bg-icon-gauge: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w | ||||
| $bg-icon-spectra: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23000000' d='M384 352H128l51.2-89.6L0 288v127c0 53.3 43.7 97 97 97h318c53.4 0 97-43.7 97-97v-31l-162.9-93.1zM415 0H97C43.7 0 0 43.6 0 97v159l200-30.1 56-97.9 54.9 96H512V97a97.2 97.2 0 00-97-97zM512 320v-32l-192-32 192 64z'/%3e%3c/svg%3e"); | ||||
| $bg-icon-spectra-telemetry: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23000000' d='M256 128l54.9 96H510C494.3 97.7 386.5 0 256 0 114.6 0 0 114.6 0 256l200-30.1zM384 352H128l51.2-89.6L2 287.7C17.6 414.1 125.4 512 256 512c100.8 0 188-58.3 229.8-143l-136.7-78.1zM320 256l192 64v-32l-192-32z'/%3e%3c/svg%3e"); | ||||
| $bg-icon-command: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23000000' d='M185.1 229.7a96.5 96.5 0 0015.8 11.7A68.5 68.5 0 01192 208c0-19.8 8.9-38.8 25.1-53.7 18.5-17 43.7-26.3 70.9-26.3 20.1 0 39.1 5.1 55.1 14.6a81.3 81.3 0 00-16.2-20.3C308.4 105.3 283.2 96 256 96s-52.4 9.3-70.9 26.3C168.9 137.2 160 156.2 160 176s8.9 38.8 25.1 53.7z'/%3e%3cpath d='M442.7 134.8C422.4 57.5 346.5 0 256 0S89.6 57.5 69.3 134.8C26.3 174.8 0 228.7 0 288c0 123.7 114.6 224 256 224s256-100.3 256-224c0-59.3-26.3-113.2-69.3-153.2zM256 64c70.6 0 128 50.2 128 112s-57.4 112-128 112-128-50.2-128-112S185.4 64 256 64zm0 352c-87.7 0-159.2-63.9-160-142.7 34.4 47.4 93.2 78.7 160 78.7s125.6-31.3 160-78.7c-.8 78.8-72.3 142.7-160 142.7z'/%3e%3c/svg%3e"); | ||||
| $bg-icon-conditional: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath d='M256 0C114.62 0 0 114.62 0 256s114.62 256 256 256 256-114.62 256-256S397.38 0 256 0zm0 384L64 256l192-128 192 128z' fill='%23000000'/%3e%3c/svg%3e"); | ||||
|   | ||||
							
								
								
									
										3
									
								
								src/styles/_glyphs.scss
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										3
									
								
								src/styles/_glyphs.scss
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -81,6 +81,7 @@ | ||||
| .icon-filter-outline {  @include glyphBefore($glyph-icon-filter-outline); } | ||||
| .icon-suitcase {  @include glyphBefore($glyph-icon-suitcase); } | ||||
| .icon-cursor-lock {  @include glyphBefore($glyph-icon-cursor-lock); } | ||||
| .icon-flag {  @include glyphBefore($glyph-icon-flag); } | ||||
| .icon-arrows-right-left {  @include glyphBefore($glyph-icon-arrows-right-left); } | ||||
| .icon-arrows-up-down {  @include glyphBefore($glyph-icon-arrows-up-down); } | ||||
| .icon-bullet {  @include glyphBefore($glyph-icon-bullet); } | ||||
| @@ -170,6 +171,7 @@ | ||||
| .icon-spectra {  @include glyphBefore($glyph-icon-spectra); } | ||||
| .icon-spectra-telemetry {  @include glyphBefore($glyph-icon-spectra-telemetry); } | ||||
| .icon-command {  @include glyphBefore($glyph-icon-command); } | ||||
| .icon-conditional {  @include glyphBefore($glyph-icon-conditional); } | ||||
|  | ||||
| /************************** 12 PX CLASSES */ | ||||
| // TODO: sync with 16px redo as of 10/25/18 | ||||
| @@ -227,3 +229,4 @@ | ||||
| .bg-icon-spectra { @include glyphBg($bg-icon-spectra); } | ||||
| .bg-icon-spectra-telemetry { @include glyphBg($bg-icon-spectra-telemetry); } | ||||
| .bg-icon-command { @include glyphBg($bg-icon-command); } | ||||
| .bg-icon-conditional { @include glyphBg($bg-icon-conditional); } | ||||
|   | ||||
							
								
								
									
										0
									
								
								src/styles/fonts/Open MCT Symbols 12px.json
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								src/styles/fonts/Open MCT Symbols 12px.json
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
								
								
									
										226
									
								
								src/styles/fonts/Open MCT Symbols 16px.json
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										226
									
								
								src/styles/fonts/Open MCT Symbols 16px.json
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -2,7 +2,7 @@ | ||||
|   "metadata": { | ||||
|     "name": "Open MCT Symbols 16px", | ||||
|     "lastOpened": 0, | ||||
|     "created": 1574106570211 | ||||
|     "created": 1581619121103 | ||||
|   }, | ||||
|   "iconSets": [ | ||||
|     { | ||||
| @@ -343,13 +343,21 @@ | ||||
|           "code": 59689, | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 176, | ||||
|           "id": 150, | ||||
|           "name": "icon-flag", | ||||
|           "prevSize": 24, | ||||
|           "code": 59690, | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 27, | ||||
|           "id": 105, | ||||
|           "name": "icon-arrows-right-left", | ||||
|           "prevSize": 24, | ||||
|           "code": 59904, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 26, | ||||
| @@ -357,7 +365,7 @@ | ||||
|           "name": "icon-arrows-up-down", | ||||
|           "prevSize": 24, | ||||
|           "code": 59905, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 68, | ||||
| @@ -365,7 +373,7 @@ | ||||
|           "name": "icon-bullet", | ||||
|           "prevSize": 24, | ||||
|           "code": 59906, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 150, | ||||
| @@ -373,7 +381,7 @@ | ||||
|           "prevSize": 24, | ||||
|           "code": 59907, | ||||
|           "name": "icon-calendar", | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 45, | ||||
| @@ -381,7 +389,7 @@ | ||||
|           "name": "icon-chain-links", | ||||
|           "prevSize": 24, | ||||
|           "code": 59908, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 73, | ||||
| @@ -389,7 +397,7 @@ | ||||
|           "name": "icon-download", | ||||
|           "prevSize": 24, | ||||
|           "code": 59909, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 39, | ||||
| @@ -397,7 +405,7 @@ | ||||
|           "name": "icon-duplicate", | ||||
|           "prevSize": 24, | ||||
|           "code": 59910, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 50, | ||||
| @@ -405,7 +413,7 @@ | ||||
|           "name": "icon-folder-new", | ||||
|           "prevSize": 24, | ||||
|           "code": 59911, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 138, | ||||
| @@ -413,7 +421,7 @@ | ||||
|           "name": "icon-fullscreen-collapse", | ||||
|           "prevSize": 24, | ||||
|           "code": 59912, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 139, | ||||
| @@ -421,7 +429,7 @@ | ||||
|           "name": "icon-fullscreen-expand", | ||||
|           "prevSize": 24, | ||||
|           "code": 59913, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 122, | ||||
| @@ -429,7 +437,7 @@ | ||||
|           "name": "icon-layers", | ||||
|           "prevSize": 24, | ||||
|           "code": 59914, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 151, | ||||
| @@ -437,7 +445,7 @@ | ||||
|           "name": "icon-line-horz", | ||||
|           "prevSize": 24, | ||||
|           "code": 59915, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 100, | ||||
| @@ -445,7 +453,7 @@ | ||||
|           "name": "icon-magnify", | ||||
|           "prevSize": 24, | ||||
|           "code": 59916, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 99, | ||||
| @@ -453,7 +461,7 @@ | ||||
|           "name": "icon-magnify-in", | ||||
|           "prevSize": 24, | ||||
|           "code": 59917, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 101, | ||||
| @@ -461,7 +469,7 @@ | ||||
|           "name": "icon-magnify-out-v2", | ||||
|           "prevSize": 24, | ||||
|           "code": 59918, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 103, | ||||
| @@ -469,7 +477,7 @@ | ||||
|           "name": "icon-menu", | ||||
|           "prevSize": 24, | ||||
|           "code": 59919, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 124, | ||||
| @@ -477,7 +485,7 @@ | ||||
|           "name": "icon-move", | ||||
|           "prevSize": 24, | ||||
|           "code": 59920, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 7, | ||||
| @@ -485,7 +493,7 @@ | ||||
|           "name": "icon-new-window", | ||||
|           "prevSize": 24, | ||||
|           "code": 59921, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 63, | ||||
| @@ -493,7 +501,7 @@ | ||||
|           "name": "icon-paint-bucket-v2", | ||||
|           "prevSize": 24, | ||||
|           "code": 59922, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 15, | ||||
| @@ -501,7 +509,7 @@ | ||||
|           "name": "icon-pencil", | ||||
|           "prevSize": 24, | ||||
|           "code": 59923, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 54, | ||||
| @@ -509,7 +517,7 @@ | ||||
|           "name": "icon-pencil-edit-in-place", | ||||
|           "prevSize": 24, | ||||
|           "code": 59924, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 40, | ||||
| @@ -517,7 +525,7 @@ | ||||
|           "name": "icon-play", | ||||
|           "prevSize": 24, | ||||
|           "code": 59925, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 125, | ||||
| @@ -525,7 +533,7 @@ | ||||
|           "name": "icon-pause", | ||||
|           "prevSize": 24, | ||||
|           "code": 59926, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 119, | ||||
| @@ -533,7 +541,7 @@ | ||||
|           "name": "icon-plot-resource", | ||||
|           "prevSize": 24, | ||||
|           "code": 59927, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 48, | ||||
| @@ -541,7 +549,7 @@ | ||||
|           "name": "icon-pointer-left", | ||||
|           "prevSize": 24, | ||||
|           "code": 59928, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 47, | ||||
| @@ -549,7 +557,7 @@ | ||||
|           "name": "icon-pointer-right", | ||||
|           "prevSize": 24, | ||||
|           "code": 59929, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 85, | ||||
| @@ -557,7 +565,7 @@ | ||||
|           "name": "icon-refresh", | ||||
|           "prevSize": 24, | ||||
|           "code": 59930, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 55, | ||||
| @@ -565,7 +573,7 @@ | ||||
|           "name": "icon-save", | ||||
|           "prevSize": 24, | ||||
|           "code": 59931, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 56, | ||||
| @@ -573,7 +581,7 @@ | ||||
|           "name": "icon-save-as", | ||||
|           "prevSize": 24, | ||||
|           "code": 59932, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 58, | ||||
| @@ -581,7 +589,7 @@ | ||||
|           "name": "icon-sine", | ||||
|           "prevSize": 24, | ||||
|           "code": 59933, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 113, | ||||
| @@ -589,7 +597,7 @@ | ||||
|           "name": "icon-font", | ||||
|           "prevSize": 24, | ||||
|           "code": 59934, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 41, | ||||
| @@ -597,7 +605,7 @@ | ||||
|           "name": "icon-thumbs-strip", | ||||
|           "prevSize": 24, | ||||
|           "code": 59935, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 146, | ||||
| @@ -605,7 +613,7 @@ | ||||
|           "name": "icon-two-parts-both", | ||||
|           "prevSize": 24, | ||||
|           "code": 59936, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 145, | ||||
| @@ -613,7 +621,7 @@ | ||||
|           "name": "icon-two-parts-one-only", | ||||
|           "prevSize": 24, | ||||
|           "code": 59937, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 82, | ||||
| @@ -621,7 +629,7 @@ | ||||
|           "name": "icon-resync", | ||||
|           "prevSize": 24, | ||||
|           "code": 59938, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 86, | ||||
| @@ -629,7 +637,7 @@ | ||||
|           "name": "icon-reset", | ||||
|           "prevSize": 24, | ||||
|           "code": 59939, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 61, | ||||
| @@ -637,7 +645,7 @@ | ||||
|           "name": "icon-x-in-circle", | ||||
|           "prevSize": 24, | ||||
|           "code": 59940, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 84, | ||||
| @@ -645,7 +653,7 @@ | ||||
|           "name": "icon-brightness", | ||||
|           "prevSize": 24, | ||||
|           "code": 59941, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 83, | ||||
| @@ -653,7 +661,7 @@ | ||||
|           "name": "icon-contrast", | ||||
|           "prevSize": 24, | ||||
|           "code": 59942, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 87, | ||||
| @@ -661,7 +669,7 @@ | ||||
|           "name": "icon-expand", | ||||
|           "prevSize": 24, | ||||
|           "code": 59943, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 89, | ||||
| @@ -669,7 +677,7 @@ | ||||
|           "name": "icon-list-view", | ||||
|           "prevSize": 24, | ||||
|           "code": 59944, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 133, | ||||
| @@ -677,7 +685,7 @@ | ||||
|           "name": "icon-grid-snap-to", | ||||
|           "prevSize": 24, | ||||
|           "code": 59945, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 132, | ||||
| @@ -685,7 +693,7 @@ | ||||
|           "name": "icon-grid-snap-no", | ||||
|           "prevSize": 24, | ||||
|           "code": 59946, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 94, | ||||
| @@ -693,7 +701,7 @@ | ||||
|           "name": "icon-frame-show", | ||||
|           "prevSize": 24, | ||||
|           "code": 59947, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 95, | ||||
| @@ -701,7 +709,7 @@ | ||||
|           "name": "icon-frame-hide", | ||||
|           "prevSize": 24, | ||||
|           "code": 59948, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 97, | ||||
| @@ -709,7 +717,7 @@ | ||||
|           "name": "icon-import", | ||||
|           "prevSize": 24, | ||||
|           "code": 59949, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 96, | ||||
| @@ -717,7 +725,7 @@ | ||||
|           "name": "icon-export", | ||||
|           "prevSize": 24, | ||||
|           "code": 59950, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 114, | ||||
| @@ -725,7 +733,7 @@ | ||||
|           "name": "icon-font-size", | ||||
|           "prevSize": 24, | ||||
|           "code": 59951, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 163, | ||||
| @@ -733,7 +741,7 @@ | ||||
|           "name": "icon-clear-data", | ||||
|           "prevSize": 24, | ||||
|           "code": 59952, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 173, | ||||
| @@ -741,7 +749,7 @@ | ||||
|           "name": "icon-history", | ||||
|           "prevSize": 24, | ||||
|           "code": 59953, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 144, | ||||
| @@ -749,7 +757,7 @@ | ||||
|           "name": "icon-activity", | ||||
|           "prevSize": 24, | ||||
|           "code": 60160, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 104, | ||||
| @@ -757,7 +765,7 @@ | ||||
|           "name": "icon-activity-mode", | ||||
|           "prevSize": 24, | ||||
|           "code": 60161, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 137, | ||||
| @@ -765,7 +773,7 @@ | ||||
|           "name": "icon-autoflow-tabular", | ||||
|           "prevSize": 24, | ||||
|           "code": 60162, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 115, | ||||
| @@ -773,7 +781,7 @@ | ||||
|           "name": "icon-clock", | ||||
|           "prevSize": 24, | ||||
|           "code": 60163, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 2, | ||||
| @@ -781,7 +789,7 @@ | ||||
|           "name": "icon-database", | ||||
|           "prevSize": 24, | ||||
|           "code": 60164, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 3, | ||||
| @@ -789,7 +797,7 @@ | ||||
|           "name": "icon-database-query", | ||||
|           "prevSize": 24, | ||||
|           "code": 60165, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 67, | ||||
| @@ -797,7 +805,7 @@ | ||||
|           "name": "icon-dataset", | ||||
|           "prevSize": 24, | ||||
|           "code": 60166, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 59, | ||||
| @@ -805,7 +813,7 @@ | ||||
|           "name": "icon-datatable", | ||||
|           "prevSize": 24, | ||||
|           "code": 60167, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 136, | ||||
| @@ -813,7 +821,7 @@ | ||||
|           "name": "icon-dictionary", | ||||
|           "prevSize": 24, | ||||
|           "code": 60168, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 51, | ||||
| @@ -821,7 +829,7 @@ | ||||
|           "name": "icon-folder", | ||||
|           "prevSize": 24, | ||||
|           "code": 60169, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 147, | ||||
| @@ -829,7 +837,7 @@ | ||||
|           "name": "icon-image", | ||||
|           "prevSize": 24, | ||||
|           "code": 60170, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 4, | ||||
| @@ -837,7 +845,7 @@ | ||||
|           "name": "icon-layout", | ||||
|           "prevSize": 24, | ||||
|           "code": 60171, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 24, | ||||
| @@ -845,7 +853,7 @@ | ||||
|           "name": "icon-object", | ||||
|           "prevSize": 24, | ||||
|           "code": 60172, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 52, | ||||
| @@ -853,7 +861,7 @@ | ||||
|           "name": "icon-object-unknown", | ||||
|           "prevSize": 24, | ||||
|           "code": 60173, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 105, | ||||
| @@ -861,7 +869,7 @@ | ||||
|           "name": "icon-packet", | ||||
|           "prevSize": 24, | ||||
|           "code": 60174, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 126, | ||||
| @@ -869,7 +877,7 @@ | ||||
|           "name": "icon-page", | ||||
|           "prevSize": 24, | ||||
|           "code": 60175, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 130, | ||||
| @@ -877,7 +885,7 @@ | ||||
|           "name": "icon-plot-overlay", | ||||
|           "prevSize": 24, | ||||
|           "code": 60176, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 80, | ||||
| @@ -885,7 +893,7 @@ | ||||
|           "name": "icon-plot-stacked", | ||||
|           "prevSize": 24, | ||||
|           "code": 60177, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 134, | ||||
| @@ -893,7 +901,7 @@ | ||||
|           "name": "icon-session", | ||||
|           "prevSize": 24, | ||||
|           "code": 60178, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 109, | ||||
| @@ -901,7 +909,7 @@ | ||||
|           "name": "icon-tabular", | ||||
|           "prevSize": 24, | ||||
|           "code": 60179, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 107, | ||||
| @@ -909,7 +917,7 @@ | ||||
|           "name": "icon-tabular-lad", | ||||
|           "prevSize": 24, | ||||
|           "code": 60180, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 106, | ||||
| @@ -917,7 +925,7 @@ | ||||
|           "name": "icon-tabular-lad-set", | ||||
|           "prevSize": 24, | ||||
|           "code": 60181, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 70, | ||||
| @@ -925,7 +933,7 @@ | ||||
|           "name": "icon-tabular-realtime", | ||||
|           "prevSize": 24, | ||||
|           "code": 60182, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 60, | ||||
| @@ -933,7 +941,7 @@ | ||||
|           "name": "icon-tabular-scrolling", | ||||
|           "prevSize": 24, | ||||
|           "code": 60183, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 131, | ||||
| @@ -941,7 +949,7 @@ | ||||
|           "name": "icon-telemetry", | ||||
|           "prevSize": 24, | ||||
|           "code": 60184, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 108, | ||||
| @@ -949,7 +957,7 @@ | ||||
|           "name": "icon-timeline", | ||||
|           "prevSize": 24, | ||||
|           "code": 60185, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 81, | ||||
| @@ -957,7 +965,7 @@ | ||||
|           "name": "icon-timer", | ||||
|           "prevSize": 24, | ||||
|           "code": 60186, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 69, | ||||
| @@ -965,7 +973,7 @@ | ||||
|           "name": "icon-topic", | ||||
|           "prevSize": 24, | ||||
|           "code": 60187, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 79, | ||||
| @@ -973,7 +981,7 @@ | ||||
|           "name": "icon-box-with-dashed-lines-v2", | ||||
|           "prevSize": 24, | ||||
|           "code": 60188, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 90, | ||||
| @@ -981,7 +989,7 @@ | ||||
|           "name": "icon-summary-widget", | ||||
|           "prevSize": 24, | ||||
|           "code": 60189, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 92, | ||||
| @@ -989,7 +997,7 @@ | ||||
|           "name": "icon-notebook", | ||||
|           "prevSize": 24, | ||||
|           "code": 60190, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 168, | ||||
| @@ -997,7 +1005,7 @@ | ||||
|           "name": "icon-tabs-view", | ||||
|           "prevSize": 24, | ||||
|           "code": 60191, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 117, | ||||
| @@ -1005,7 +1013,7 @@ | ||||
|           "name": "icon-flexible-layout", | ||||
|           "prevSize": 24, | ||||
|           "code": 60192, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 166, | ||||
| @@ -1013,7 +1021,7 @@ | ||||
|           "name": "icon-generator-sine", | ||||
|           "prevSize": 24, | ||||
|           "code": 60193, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 167, | ||||
| @@ -1021,7 +1029,7 @@ | ||||
|           "name": "icon-generator-event", | ||||
|           "prevSize": 24, | ||||
|           "code": 60194, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 165, | ||||
| @@ -1029,7 +1037,7 @@ | ||||
|           "name": "icon-gauge-v2", | ||||
|           "prevSize": 24, | ||||
|           "code": 60195, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 170, | ||||
| @@ -1037,7 +1045,7 @@ | ||||
|           "name": "icon-spectra", | ||||
|           "prevSize": 24, | ||||
|           "code": 60196, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 171, | ||||
| @@ -1045,7 +1053,7 @@ | ||||
|           "name": "icon-telemetry-spectra", | ||||
|           "prevSize": 24, | ||||
|           "code": 60197, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 172, | ||||
| @@ -1053,7 +1061,15 @@ | ||||
|           "name": "icon-pushbutton", | ||||
|           "prevSize": 24, | ||||
|           "code": 60198, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 174, | ||||
|           "id": 151, | ||||
|           "name": "icon-conditional", | ||||
|           "prevSize": 24, | ||||
|           "code": 60199, | ||||
|           "tempChar": "" | ||||
|         } | ||||
|       ], | ||||
|       "id": 0, | ||||
| @@ -1613,6 +1629,21 @@ | ||||
|             "icon-cursor-locked" | ||||
|           ] | ||||
|         }, | ||||
|         { | ||||
|           "id": 150, | ||||
|           "paths": [ | ||||
|             "M192 640h832l-192-320 192-320h-896c-70.606 0.215-127.785 57.394-128 127.979l-0 0.021v896h192z" | ||||
|           ], | ||||
|           "attrs": [ | ||||
|             {} | ||||
|           ], | ||||
|           "grid": 16, | ||||
|           "tags": [ | ||||
|             "icon-flag" | ||||
|           ], | ||||
|           "isMulticolor": false, | ||||
|           "isMulticolor2": false | ||||
|         }, | ||||
|         { | ||||
|           "id": 105, | ||||
|           "paths": [ | ||||
| @@ -2771,6 +2802,21 @@ | ||||
|           "tags": [ | ||||
|             "icon-pushbutton" | ||||
|           ] | ||||
|         }, | ||||
|         { | ||||
|           "id": 151, | ||||
|           "paths": [ | ||||
|             "M512 0c-282.76 0-512 229.24-512 512s229.24 512 512 512 512-229.24 512-512-229.24-512-512-512zM512 768l-384-256 384-256 384 256z" | ||||
|           ], | ||||
|           "attrs": [ | ||||
|             {} | ||||
|           ], | ||||
|           "isMulticolor": false, | ||||
|           "isMulticolor2": false, | ||||
|           "grid": 16, | ||||
|           "tags": [ | ||||
|             "icon-conditional" | ||||
|           ] | ||||
|         } | ||||
|       ], | ||||
|       "invisible": false, | ||||
|   | ||||
							
								
								
									
										0
									
								
								src/styles/fonts/Open-MCT-Symbols-12px.ttf
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								src/styles/fonts/Open-MCT-Symbols-12px.ttf
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
								
								
									
										0
									
								
								src/styles/fonts/Open-MCT-Symbols-12px.woff
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								src/styles/fonts/Open-MCT-Symbols-12px.woff
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -49,6 +49,7 @@ | ||||
| <glyph unicode="" glyph-name="icon-filter-outline" d="M896 832h-768c-70.601-0.227-127.773-57.399-128-127.978v-768.022c0.227-70.601 57.399-127.773 127.978-128h768.022c70.601 0.227 127.773 57.399 128 127.978v768.022c-0.227 70.601-57.399 127.773-127.978 128h-0.022zM896-63.8h-256v383.8l192 192h-640l192-192v-384h-256v767.8h768z" /> | ||||
| <glyph unicode="" glyph-name="icon-suitcase" d="M768 704c-0.080 70.66-57.34 127.92-127.993 128h-256.007c-70.66-0.080-127.92-57.34-128-127.993v-128.007h-64v-768h640v768h-64zM384 703.88l0.12 0.12 255.88-0.12v-127.88h-256zM0 512v-640c0.102-35.305 28.695-63.898 63.99-64h64.010v768h-64c-35.305-0.102-63.898-28.695-64-63.99v-0.010zM960 576h-64v-768h64c35.305 0.102 63.898 28.695 64 63.99v640.010c-0.102 35.305-28.695 63.898-63.99 64h-0.010z" /> | ||||
| <glyph unicode="" glyph-name="icon-cursor-locked" horiz-adv-x="768" d="M704 512h-64v64c0 141.385-114.615 256-256 256s-256-114.615-256-256v0-64h-64c-35.301-0.113-63.887-28.699-64-63.989v-576.011c0.113-35.301 28.699-63.887 63.989-64h640.011c35.301 0.113 63.887 28.699 64 63.989v576.011c-0.113 35.301-28.699 63.887-63.989 64h-0.011zM256 576c0 70.692 57.308 128 128 128s128-57.308 128-128v0-64h-256zM533.4-64l-128 128-43-85-170.4 383.6 383.6-170.2-85-43 128-128z" /> | ||||
| <glyph unicode="" glyph-name="icon-flag" d="M192 192h832l-192 320 192 320h-896c-70.606-0.215-127.785-57.394-128-127.979v-896.021h192z" /> | ||||
| <glyph unicode="" glyph-name="icon-arrows-right-left" d="M1024 320l-448-512v1024zM448 832l-448-512 448-512z" /> | ||||
| <glyph unicode="" glyph-name="icon-arrows-up-down" d="M512 832l512-448h-1024zM0 256l512-448 512 448z" /> | ||||
| <glyph unicode="" glyph-name="icon-bullet" d="M832 80c0-44-36-80-80-80h-480c-44 0-80 36-80 80v480c0 44 36 80 80 80h480c44 0 80-36 80-80v-480z" /> | ||||
| @@ -138,4 +139,5 @@ | ||||
| <glyph unicode="" glyph-name="icon-spectra" d="M768 128h-512l102.4 179.2-358.4-51.2v-254c0-106.6 87.4-194 194-194h636c106.8 0 194 87.4 194 194v62l-325.8 186.2zM830 832h-636c-106.6 0-194-87.2-194-194v-318l400 60.2 112 195.8 109.8-192h402.2v254c-0.227 107.052-86.948 193.773-193.978 194h-0.022zM1024 192v64l-384 64 384-128z" /> | ||||
| <glyph unicode="" glyph-name="icon-telemetry-spectra" d="M512 576l109.8-192h398.2c-31.4 252.6-247 448-508 448-282.8 0-512-229.2-512-512l400 60.2zM768 128h-512l102.4 179.2-354.4-50.6c31.2-252.8 246.8-448.6 508-448.6 201.6 0 376 116.6 459.6 286l-273.4 156.2zM640 320l384-128v64l-384 64z" /> | ||||
| <glyph unicode="" glyph-name="icon-pushbutton" d="M370.2 372.6c9.326-8.53 19.666-16.261 30.729-22.914l0.871-0.486c-11.077 19.209-17.664 42.221-17.8 66.76v0.040c0 39.6 17.8 77.6 50.2 107.4 37 34 87.4 52.6 141.8 52.6 40.2 0 78.2-10.2 110.2-29.2-8.918 15.653-19.693 29.040-32.268 40.482l-0.132 0.118c-37 34-87.4 52.6-141.8 52.6s-104.8-18.6-141.8-52.6c-32.4-29.8-50.2-67.8-50.2-107.4s17.8-77.6 50.2-107.4zM885.4 562.4c-40.6 154.6-192.4 269.6-373.4 269.6s-332.8-115-373.4-269.6c-86-80-138.6-187.8-138.6-306.4 0-247.4 229.2-448 512-448s512 200.6 512 448c0 118.6-52.6 226.4-138.6 306.4zM512 704c141.2 0 256-100.4 256-224s-114.8-224-256-224-256 100.4-256 224 114.8 224 256 224zM512 0c-175.4 0-318.4 127.8-320 285.4 68.8-94.8 186.4-157.4 320-157.4s251.2 62.6 320 157.4c-1.6-157.6-144.6-285.4-320-285.4z" /> | ||||
| <glyph unicode="" glyph-name="icon-conditional" d="M512 832c-282.76 0-512-229.24-512-512s229.24-512 512-512 512 229.24 512 512-229.24 512-512 512zM512 64l-384 256 384 256 384-256z" /> | ||||
| </font></defs></svg> | ||||
| Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB | 
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,5 +1,7 @@ | ||||
| @import "../api/overlays/components/dialog-component.scss"; | ||||
| @import "../api/overlays/components/overlay-component.scss"; | ||||
| @import "../plugins/condition/components/condition.scss"; | ||||
| @import "../plugins/condition/components/condition-set.scss"; | ||||
| @import "../plugins/displayLayout/components/box-view.scss"; | ||||
| @import "../plugins/displayLayout/components/display-layout.scss"; | ||||
| @import "../plugins/displayLayout/components/edit-marquee.scss"; | ||||
|   | ||||
| @@ -1,22 +1,46 @@ | ||||
| <template> | ||||
| <multipane | ||||
|     class="c-inspector" | ||||
|     type="vertical" | ||||
| > | ||||
|     <pane class="c-inspector__properties"> | ||||
|         <properties /> | ||||
|         <location /> | ||||
|         <inspector-views /> | ||||
|     </pane> | ||||
|     <pane | ||||
|         v-if="isEditing && hasComposition" | ||||
|         class="c-inspector__elements" | ||||
|         handle="before" | ||||
|         label="Elements" | ||||
|     > | ||||
|         <elements /> | ||||
|     </pane> | ||||
| </multipane> | ||||
| <div class="c-inspector"> | ||||
|     <div class="c-inspector__tabs"> | ||||
|         <div v-if="showStyles" | ||||
|              class="c-inspector__tabs__holder" | ||||
|         > | ||||
|             <div v-for="tabbedView in tabbedViews" | ||||
|                  :key="tabbedView.key" | ||||
|                  class="c-inspector__tabs__header" | ||||
|                  @click="updateCurrentTab(tabbedView)" | ||||
|             > | ||||
|                 <span class="c-inspector__tabs__label c-tab" | ||||
|                       :class="{'is-current': isCurrent(tabbedView)}" | ||||
|                 >{{ tabbedView.name }}</span> | ||||
|             </div> | ||||
|         </div> | ||||
|         <div class="c-inspector__tabs__contents"> | ||||
|             <multipane v-if="currentTabbedView.key === '__properties'" | ||||
|                        class="c-inspector" | ||||
|                        type="vertical" | ||||
|             > | ||||
|                 <pane class="c-inspector__properties"> | ||||
|                     <properties /> | ||||
|                     <location /> | ||||
|                     <inspector-views /> | ||||
|                 </pane> | ||||
|                 <pane | ||||
|                     v-if="isEditing && hasComposition" | ||||
|                     class="c-inspector__elements" | ||||
|                     handle="before" | ||||
|                     label="Elements" | ||||
|                 > | ||||
|                     <elements /> | ||||
|                 </pane> | ||||
|             </multipane> | ||||
|             <pane v-else | ||||
|                   class="c-inspector__styles" | ||||
|             > | ||||
|                 <styles-inspector-view /> | ||||
|             </pane> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| @@ -26,10 +50,14 @@ import Elements from './Elements.vue'; | ||||
| import Location from './Location.vue'; | ||||
| import Properties from './Properties.vue'; | ||||
| import InspectorViews from './InspectorViews.vue'; | ||||
| import _ from "lodash"; | ||||
| import StylesInspectorView from "./StylesInspectorView.vue"; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct'], | ||||
|     components: { | ||||
|         StylesInspectorView, | ||||
|         // StylesInspectorView, | ||||
|         multipane, | ||||
|         pane, | ||||
|         Elements, | ||||
| @@ -42,23 +70,56 @@ export default { | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             hasComposition: false | ||||
|             hasComposition: false, | ||||
|             showStyles: false, | ||||
|             tabbedViews: [{ | ||||
|                 key: '__properties', | ||||
|                 name: 'Properties' | ||||
|             },{ | ||||
|                 key: '__styles', | ||||
|                 name: 'Styles' | ||||
|             }], | ||||
|             currentTabbedView: {} | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.openmct.selection.on('change', this.refreshComposition); | ||||
|         this.refreshComposition(this.openmct.selection.get()); | ||||
|         this.excludeObjectTypes = ['folder', 'webPage', 'conditionSet']; | ||||
|         this.openmct.selection.on('change', this.updateInspectorViews); | ||||
|     }, | ||||
|     destroyed() { | ||||
|         this.openmct.selection.off('change', this.refreshComposition); | ||||
|         this.openmct.selection.off('change', this.updateInspectorViews); | ||||
|     }, | ||||
|     methods: { | ||||
|         updateInspectorViews(selection) { | ||||
|             this.refreshComposition(selection); | ||||
|             if (this.openmct.types.get('conditionSet')) { | ||||
|                 this.refreshTabs(selection); | ||||
|             } | ||||
|         }, | ||||
|         refreshComposition(selection) { | ||||
|             if (selection.length > 0 && selection[0].length > 0) { | ||||
|                 let parentObject = selection[0][0].context.item; | ||||
|  | ||||
|                 this.hasComposition = !!(parentObject && this.openmct.composition.get(parentObject)); | ||||
|             } | ||||
|         }, | ||||
|         refreshTabs(selection) { | ||||
|             if (selection.length > 0 && selection[0].length > 0) { | ||||
|                 //layout items are not domain objects but should allow conditional styles | ||||
|                 this.showStyles = selection[0][0].context.layoutItem; | ||||
|                 let object = selection[0][0].context.item; | ||||
|                 if (object) { | ||||
|                     let type = this.openmct.types.get(object.type); | ||||
|                     this.showStyles = (this.excludeObjectTypes.indexOf(object.type) < 0) && type.definition.creatable; | ||||
|                 } | ||||
|                 this.updateCurrentTab(this.tabbedViews[0]); | ||||
|             } | ||||
|         }, | ||||
|         updateCurrentTab(view) { | ||||
|             this.currentTabbedView = view; | ||||
|         }, | ||||
|         isCurrent(view) { | ||||
|             return _.isEqual(this.currentTabbedView, view) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -30,11 +30,10 @@ export default { | ||||
|                 }); | ||||
|                 this.$el.innerHTML = ''; | ||||
|             } | ||||
|  | ||||
|             this.selectedViews = this.openmct.inspectorViews.get(selection); | ||||
|             this.selectedViews.forEach(selectedView => { | ||||
|                 let viewContainer = document.createElement('div'); | ||||
|                 this.$el.append(viewContainer) | ||||
|                 this.$el.append(viewContainer); | ||||
|                 selectedView.show(viewContainer); | ||||
|             }); | ||||
|         } | ||||
|   | ||||
							
								
								
									
										52
									
								
								src/ui/inspector/StylesInspectorView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/ui/inspector/StylesInspectorView.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| <template> | ||||
| <div></div> | ||||
| </template> | ||||
|  | ||||
| <style> | ||||
| </style> | ||||
|  | ||||
| <script> | ||||
| import ConditionalStylesView from '../../plugins/condition/components/inspector/ConditionalStylesView.vue'; | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct'], | ||||
|     data() { | ||||
|         return { | ||||
|             selection: [] | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.openmct.selection.on('change', this.updateSelection); | ||||
|         this.updateSelection(this.openmct.selection.get()); | ||||
|     }, | ||||
|     destroyed() { | ||||
|         this.openmct.selection.off('change', this.updateSelection); | ||||
|     }, | ||||
|     methods: { | ||||
|         updateSelection(selection) { | ||||
|             this.selection = selection; | ||||
|  | ||||
|             if (this.component) { | ||||
|                 this.component.$destroy(); | ||||
|                 this.component = undefined; | ||||
|                 this.$el.innerHTML = ''; | ||||
|             } | ||||
|  | ||||
|             let viewContainer = document.createElement('div'); | ||||
|             this.$el.append(viewContainer); | ||||
|             this.component = new Vue({ | ||||
|                 provide: { | ||||
|                     openmct: this.openmct | ||||
|                 }, | ||||
|                 el: viewContainer, | ||||
|                 components: { | ||||
|                     ConditionalStylesView | ||||
|                 }, | ||||
|                 template: '<conditional-styles-view></conditional-styles-view>' | ||||
|             }); | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
| </script> | ||||
| @@ -1,4 +1,6 @@ | ||||
| .c-inspector { | ||||
|     height: 100%; | ||||
|  | ||||
|     > [class*="__"] { | ||||
|         min-height: 50px; | ||||
|  | ||||
| @@ -55,6 +57,44 @@ | ||||
|     .c-tree .grid-properties { | ||||
|         margin-left: $treeItemIndent; | ||||
|     } | ||||
|  | ||||
|     &__tabs { | ||||
|         $h: 20px; | ||||
|         @include abs(); | ||||
|         display: flex; | ||||
|         flex-flow: column nowrap; | ||||
|  | ||||
|         > * + * { | ||||
|             margin-top: $interiorMargin; | ||||
|         } | ||||
|  | ||||
|         &__holder { | ||||
|             display: flex; | ||||
|             min-height: $h; | ||||
|  | ||||
|             &__header { | ||||
|  | ||||
|                 &:before { | ||||
|                     margin-right: $interiorMarginSm; | ||||
|                     opacity: 0.7; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         &__contents { | ||||
|             flex: 1 1 auto; | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
|  | ||||
|             &--hidden { | ||||
|                 height: 1000px; | ||||
|                 width: 1000px; | ||||
|                 position: absolute; | ||||
|                 left: -9999px; | ||||
|                 top: -9999px; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-properties { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user