Compare commits
25 Commits
stacked-pl
...
v1.4.2-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a397fb2cb5 | ||
|
|
41783d8939 | ||
|
|
441ad58fe7 | ||
|
|
06a6a3f773 | ||
|
|
52fab78625 | ||
|
|
5eb6c15959 | ||
|
|
ce8c31cfa4 | ||
|
|
cb8e906f93 | ||
|
|
be746db774 | ||
|
|
de9d972cf6 | ||
|
|
5ac43ccf6a | ||
|
|
d29b4d3b83 | ||
|
|
541e96a20a | ||
|
|
1554823416 | ||
|
|
674a888d80 | ||
|
|
ec9dbabc46 | ||
|
|
c148160fa8 | ||
|
|
8b45dae1f1 | ||
|
|
1ec0274984 | ||
|
|
9de1927834 | ||
|
|
df3991cbd5 | ||
|
|
528a2aad8c | ||
|
|
c9a29d0854 | ||
|
|
d28c4e8711 | ||
|
|
ac04983c5b |
@@ -182,7 +182,7 @@ The following guidelines are provided for anyone contributing source code to the
|
||||
1. Avoid the use of "magic" values.
|
||||
eg.
|
||||
```JavaScript
|
||||
Const UNAUTHORIZED = 401
|
||||
const UNAUTHORIZED = 401;
|
||||
if (responseCode === UNAUTHORIZED)
|
||||
```
|
||||
is preferable to
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openmct",
|
||||
"version": "1.4.1-SNAPSHOT",
|
||||
"version": "1.5.0-SNAPSHOT",
|
||||
"description": "The Open MCT core platform",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
import { createOpenMct, resetApplicationState } from "utils/testing";
|
||||
import ConditionPlugin from "./plugin";
|
||||
import stylesManager from '@/ui/inspector/styles/StylesManager';
|
||||
import StylesView from "./components/inspector/StylesView.vue";
|
||||
import Vue from 'vue';
|
||||
import {getApplicableStylesForItem} from "./utils/styleUtils";
|
||||
@@ -402,7 +403,8 @@ describe('the plugin', function () {
|
||||
component = new Vue({
|
||||
provide: {
|
||||
openmct: openmct,
|
||||
selection: selection
|
||||
selection: selection,
|
||||
stylesManager
|
||||
},
|
||||
el: viewContainer,
|
||||
components: {
|
||||
|
||||
@@ -79,8 +79,9 @@ export default class DuplicateTask {
|
||||
*/
|
||||
async buildDuplicationPlan() {
|
||||
let domainObjectClone = await this.duplicateObject(this.domainObject);
|
||||
|
||||
if (domainObjectClone !== this.domainObject) {
|
||||
domainObjectClone.location = this.getId(this.parent);
|
||||
domainObjectClone.location = this.getKeyString(this.parent);
|
||||
}
|
||||
|
||||
this.firstClone = domainObjectClone;
|
||||
@@ -159,36 +160,6 @@ export default class DuplicateTask {
|
||||
return originalObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update identifiers in a cloned object model (or part of
|
||||
* a cloned object model) to reflect new identifiers after
|
||||
* duplicating.
|
||||
* @private
|
||||
*/
|
||||
rewriteIdentifiers(obj, idMap) {
|
||||
function lookupValue(value) {
|
||||
return (typeof value === 'string' && idMap[value]) || value;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
obj.forEach((value, index) => {
|
||||
obj[index] = lookupValue(value);
|
||||
this.rewriteIdentifiers(obj[index], idMap);
|
||||
});
|
||||
} else if (obj && typeof obj === 'object') {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
let value = obj[key];
|
||||
obj[key] = lookupValue(value);
|
||||
if (idMap[key]) {
|
||||
delete obj[key];
|
||||
obj[idMap[key]] = value;
|
||||
}
|
||||
|
||||
this.rewriteIdentifiers(value, idMap);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of objects composed by a parent, clone them, then
|
||||
* add them to the parent.
|
||||
@@ -196,31 +167,67 @@ export default class DuplicateTask {
|
||||
* @returns {*}
|
||||
*/
|
||||
async duplicateComposees(clonedParent, composees = []) {
|
||||
let idMap = {};
|
||||
let idMappings = [];
|
||||
let allComposeesDuplicated = composees.reduce(async (previousPromise, nextComposee) => {
|
||||
await previousPromise;
|
||||
|
||||
let clonedComposee = await this.duplicateObject(nextComposee);
|
||||
idMap[this.getId(nextComposee)] = this.getId(clonedComposee);
|
||||
this.composeChild(clonedComposee, clonedParent, clonedComposee !== nextComposee);
|
||||
|
||||
if (clonedComposee) {
|
||||
idMappings.push({
|
||||
newId: clonedComposee.identifier,
|
||||
oldId: nextComposee.identifier
|
||||
});
|
||||
this.composeChild(clonedComposee, clonedParent, clonedComposee !== nextComposee);
|
||||
}
|
||||
|
||||
return;
|
||||
}, Promise.resolve());
|
||||
|
||||
await allComposeesDuplicated;
|
||||
|
||||
this.rewriteIdentifiers(clonedParent, idMap);
|
||||
clonedParent = this.rewriteIdentifiers(clonedParent, idMappings);
|
||||
this.clones.push(clonedParent);
|
||||
|
||||
return clonedParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update identifiers in a cloned object model (or part of
|
||||
* a cloned object model) to reflect new identifiers after
|
||||
* duplicating.
|
||||
* @private
|
||||
*/
|
||||
rewriteIdentifiers(clonedParent, childIdMappings) {
|
||||
for (let { newId, oldId } of childIdMappings) {
|
||||
let newIdKeyString = this.openmct.objects.makeKeyString(newId);
|
||||
let oldIdKeyString = this.openmct.objects.makeKeyString(oldId);
|
||||
|
||||
// regex replace keystrings
|
||||
clonedParent = JSON.stringify(clonedParent).replace(new RegExp(oldIdKeyString, 'g'), newIdKeyString);
|
||||
|
||||
// parse reviver to replace identifiers
|
||||
clonedParent = JSON.parse(clonedParent, (key, value) => {
|
||||
if (Object.prototype.hasOwnProperty.call(value, 'key')
|
||||
&& Object.prototype.hasOwnProperty.call(value, 'namespace')
|
||||
&& value.key === oldId.key
|
||||
&& value.namespace === oldId.namespace) {
|
||||
return newId;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return clonedParent;
|
||||
}
|
||||
|
||||
composeChild(child, parent, setLocation) {
|
||||
let childKeyString = this.openmct.objects.makeKeyString(child.identifier);
|
||||
parent.composition.push(childKeyString);
|
||||
parent.composition.push(child.identifier);
|
||||
|
||||
//If a location is not specified, set it.
|
||||
if (setLocation && child.location === undefined) {
|
||||
let parentKeyString = this.getId(parent);
|
||||
let parentKeyString = this.getKeyString(parent);
|
||||
child.location = parentKeyString;
|
||||
}
|
||||
}
|
||||
@@ -256,7 +263,7 @@ export default class DuplicateTask {
|
||||
return clone;
|
||||
}
|
||||
|
||||
getId(domainObject) {
|
||||
getKeyString(domainObject) {
|
||||
return this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,9 @@ export default {
|
||||
this.openmct.notifications.alert(message);
|
||||
}
|
||||
|
||||
window.location.hash = hash;
|
||||
const relativeHash = hash.slice(hash.indexOf('#'));
|
||||
const url = new URL(relativeHash, `${location.protocol}//${location.host}${location.pathname}`);
|
||||
window.location.hash = url.hash;
|
||||
},
|
||||
formatTime(unixTime, timeFormat) {
|
||||
return Moment.utc(unixTime).format(timeFormat);
|
||||
|
||||
@@ -7,15 +7,14 @@ export default class Snapshot {
|
||||
constructor(openmct) {
|
||||
this.openmct = openmct;
|
||||
this.snapshotContainer = new SnapshotContainer(openmct);
|
||||
this.exportImageService = openmct.$injector.get('exportImageService');
|
||||
this.dialogService = openmct.$injector.get('dialogService');
|
||||
|
||||
this.capture = this.capture.bind(this);
|
||||
this._saveSnapShot = this._saveSnapShot.bind(this);
|
||||
}
|
||||
|
||||
capture(snapshotMeta, notebookType, domElement) {
|
||||
this.exportImageService.exportPNGtoSRC(domElement, 's-status-taking-snapshot')
|
||||
const exportImageService = this.openmct.$injector.get('exportImageService');
|
||||
exportImageService.exportPNGtoSRC(domElement, 's-status-taking-snapshot')
|
||||
.then(function (blob) {
|
||||
const reader = new window.FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
|
||||
@@ -46,6 +46,7 @@ define(
|
||||
filter = filter.trim().toLowerCase();
|
||||
|
||||
let rowsToFilter = this.getRowsToFilter(columnKey, filter);
|
||||
|
||||
if (filter.length === 0) {
|
||||
delete this.columnFilters[columnKey];
|
||||
} else {
|
||||
@@ -56,6 +57,16 @@ define(
|
||||
this.emit('filter');
|
||||
}
|
||||
|
||||
setColumnRegexFilter(columnKey, filter) {
|
||||
filter = filter.trim();
|
||||
|
||||
let rowsToFilter = this.masterCollection.getRows();
|
||||
|
||||
this.columnFilters[columnKey] = new RegExp(filter);
|
||||
this.rows = rowsToFilter.filter(this.matchesFilters, this);
|
||||
this.emit('filter');
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -71,6 +82,10 @@ define(
|
||||
* @private
|
||||
*/
|
||||
isSubsetOfCurrentFilter(columnKey, filter) {
|
||||
if (this.columnFilters[columnKey] instanceof RegExp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.columnFilters[columnKey]
|
||||
&& filter.startsWith(this.columnFilters[columnKey])
|
||||
// startsWith check will otherwise fail when filter cleared
|
||||
@@ -97,7 +112,11 @@ define(
|
||||
return false;
|
||||
}
|
||||
|
||||
doesMatchFilters = formattedValue.toLowerCase().indexOf(this.columnFilters[key]) !== -1;
|
||||
if (this.columnFilters[key] instanceof RegExp) {
|
||||
doesMatchFilters = this.columnFilters[key].test(formattedValue);
|
||||
} else {
|
||||
doesMatchFilters = formattedValue.toLowerCase().indexOf(this.columnFilters[key]) !== -1;
|
||||
}
|
||||
});
|
||||
|
||||
return doesMatchFilters;
|
||||
|
||||
@@ -188,7 +188,17 @@
|
||||
class="c-table__search"
|
||||
@input="filterChanged(key)"
|
||||
@clear="clearFilter(key)"
|
||||
/>
|
||||
>
|
||||
|
||||
<button
|
||||
class="c-search__use-regex"
|
||||
:class="{ 'is-active': enableRegexSearch[key] }"
|
||||
title="Click to enable regex: enter a string with slashes, like this: /regex_exp/"
|
||||
@click="toggleRegex(key)"
|
||||
>
|
||||
/R/
|
||||
</button>
|
||||
</search>
|
||||
</table-column-header>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -361,6 +371,7 @@ export default {
|
||||
paused: false,
|
||||
markedRows: [],
|
||||
isShowingMarkedRowsOnly: false,
|
||||
enableRegexSearch: {},
|
||||
hideHeaders: configuration.hideHeaders,
|
||||
totalNumberOfRows: 0
|
||||
};
|
||||
@@ -618,7 +629,16 @@ export default {
|
||||
this.headersHolderEl.scrollLeft = this.scrollable.scrollLeft;
|
||||
},
|
||||
filterChanged(columnKey) {
|
||||
this.table.filteredRows.setColumnFilter(columnKey, this.filters[columnKey]);
|
||||
if (this.enableRegexSearch[columnKey]) {
|
||||
if (this.isCompleteRegex(this.filters[columnKey])) {
|
||||
this.table.filteredRows.setColumnRegexFilter(columnKey, this.filters[columnKey].slice(1, -1));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.table.filteredRows.setColumnFilter(columnKey, this.filters[columnKey]);
|
||||
}
|
||||
|
||||
this.setHeight();
|
||||
},
|
||||
clearFilter(columnKey) {
|
||||
@@ -956,6 +976,18 @@ export default {
|
||||
|
||||
this.$nextTick().then(this.calculateColumnWidths);
|
||||
},
|
||||
toggleRegex(key) {
|
||||
this.$set(this.filters, key, '');
|
||||
|
||||
if (this.enableRegexSearch[key] === undefined) {
|
||||
this.$set(this.enableRegexSearch, key, true);
|
||||
} else {
|
||||
this.$set(this.enableRegexSearch, key, !this.enableRegexSearch[key]);
|
||||
}
|
||||
},
|
||||
isCompleteRegex(string) {
|
||||
return (string.length > 2 && string[0] === '/' && string[string.length - 1] === '/');
|
||||
},
|
||||
getViewContext() {
|
||||
return {
|
||||
type: 'telemetry-table',
|
||||
|
||||
@@ -98,6 +98,10 @@ describe('the plugin', function () {
|
||||
|
||||
beforeEach((done) => {
|
||||
planDomainObject = {
|
||||
identifier: {
|
||||
key: 'test-object',
|
||||
namespace: ''
|
||||
},
|
||||
type: 'plan',
|
||||
id: "test-object",
|
||||
selectFile: {
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
@mixin visibleRegexButton {
|
||||
opacity: 1;
|
||||
padding: 1px 3px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.c-search {
|
||||
@include wrappedInput();
|
||||
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
|
||||
@@ -9,11 +14,46 @@
|
||||
content: $glyph-icon-magnify;
|
||||
}
|
||||
|
||||
&__use-regex {
|
||||
// Button
|
||||
$c: $colorBodyFg;
|
||||
background: rgba($c, 0.2);
|
||||
border: 1px solid rgba($c, 0.3);
|
||||
color: $c;
|
||||
border-radius: $controlCr;
|
||||
font-weight: bold;
|
||||
letter-spacing: 1px;
|
||||
font-size: 0.8em;
|
||||
margin-left: $interiorMarginSm;
|
||||
min-width: 0;
|
||||
opacity: 0;
|
||||
order: 2;
|
||||
overflow: hidden;
|
||||
padding: 1px 0;
|
||||
transform-origin: left;
|
||||
transition: $transOut;
|
||||
width: 0;
|
||||
|
||||
&.is-active {
|
||||
$c: $colorBtnActiveBg;
|
||||
@include visibleRegexButton();
|
||||
background: rgba($c, 0.3);
|
||||
border-color: $c;
|
||||
color: $c;
|
||||
}
|
||||
}
|
||||
|
||||
&__clear-input {
|
||||
display: none;
|
||||
order: 99;
|
||||
padding: 1px 0;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
.c-search__use-regex {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.c-search__clear-input {
|
||||
display: block;
|
||||
}
|
||||
@@ -21,6 +61,15 @@
|
||||
|
||||
input[type='text'],
|
||||
input[type='search'] {
|
||||
margin-left: $interiorMargin;
|
||||
order: 3;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.c-search__use-regex {
|
||||
@include visibleRegexButton();
|
||||
transition: $transIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
class="c-search__clear-input icon-x-in-circle"
|
||||
@click="clearInput"
|
||||
></a>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user