Compare commits
13 Commits
bugfix/iss
...
release/2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
484226b229 | ||
|
|
abfa971dd6 | ||
|
|
6d50dd571a | ||
|
|
b58e38ee15 | ||
|
|
d2923a672c | ||
|
|
bcd668594d | ||
|
|
5471e13d9e | ||
|
|
dae446808e | ||
|
|
ee9e47f487 | ||
|
|
003b1ffede | ||
|
|
16cb5f3911 | ||
|
|
74b83903c9 | ||
|
|
6a470fba1a |
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
4
.github/workflows/e2e-pr.yml
vendored
4
.github/workflows/e2e-pr.yml
vendored
@@ -26,8 +26,8 @@ jobs:
|
||||
repo: "openmct",
|
||||
body: 'Started e2e Run. Follow along: https://github.com/nasa/openmct/actions/runs/' + context.runId
|
||||
})
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
- run: npx playwright install-deps
|
||||
|
||||
4
.github/workflows/e2e-visual.yml
vendored
4
.github/workflows/e2e-visual.yml
vendored
@@ -13,8 +13,8 @@ jobs:
|
||||
if: ${{ github.event.label.name == 'pr:visual' }} || ${{ github.event.workflow_dispatch }} || ${{ github.event.schedule }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
- run: npx playwright install-deps
|
||||
|
||||
4
.github/workflows/e2e.yml
vendored
4
.github/workflows/e2e.yml
vendored
@@ -10,10 +10,10 @@ jobs:
|
||||
e2e:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version }}
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
- run: npm install
|
||||
|
||||
16
.github/workflows/lighthouse.yml
vendored
16
.github/workflows/lighthouse.yml
vendored
@@ -17,11 +17,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Master for Baseline
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: master #explicitly checkout master for baseline
|
||||
- name: Install Node 14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '14'
|
||||
- name: Cache node modules
|
||||
@@ -38,11 +38,11 @@ jobs:
|
||||
- name: Run lhci against master to generate baseline and ignore exit codes
|
||||
run: lhci autorun || true
|
||||
- name: Perform clean checkout of PR
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
clean: true
|
||||
- name: Install Node version which is compatible with PR
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
- name: npm install with lighthouse cli
|
||||
run: npm install && npm install -g @lhci/cli
|
||||
- name: Run lhci with PR
|
||||
@@ -53,9 +53,9 @@ jobs:
|
||||
if: ${{ github.event.schedule }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Node 14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '14'
|
||||
- name: Cache node modules
|
||||
@@ -77,11 +77,11 @@ jobs:
|
||||
if: ${{ github.event.workflow_dispatch }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version }}
|
||||
- name: Install Node 14
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '14'
|
||||
- name: Cache node modules
|
||||
|
||||
8
.github/workflows/npm-prerelease.yml
vendored
8
.github/workflows/npm-prerelease.yml
vendored
@@ -11,8 +11,8 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- run: npm install
|
||||
@@ -22,8 +22,8 @@ jobs:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://registry.npmjs.org/
|
||||
|
||||
6
.github/workflows/pr-platform.yml
vendored
6
.github/workflows/pr-platform.yml
vendored
@@ -23,12 +23,12 @@ jobs:
|
||||
- x64
|
||||
name: Node ${{ matrix.node_version }} - ${{ matrix.architecture }} on ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
architecture: ${{ matrix.architecture }}
|
||||
- run: npm install
|
||||
- run: npm test
|
||||
- run: npm run lint
|
||||
- run: npm run lint -- --quiet
|
||||
|
||||
@@ -26,8 +26,8 @@ This test suite is dedicated to tests which verify the basic operations surround
|
||||
|
||||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
test.describe('condition set', () => {
|
||||
test('create new button `condition set` creates new condition object', async ({ page }) => {
|
||||
test.describe('Condition Set Operations', () => {
|
||||
test('Create new button `condition set` creates new condition object', async ({ page }) => {
|
||||
//Go to baseURL
|
||||
await page.goto('/', { waitUntil: 'networkidle' });
|
||||
|
||||
@@ -45,4 +45,21 @@ test.describe('condition set', () => {
|
||||
|
||||
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set');
|
||||
});
|
||||
test.fixme('condition set object properties exist', async ({ page }) => {
|
||||
//Go to object created in step one
|
||||
//Verify the Condition Set properties persist on Save
|
||||
//Verify the Condition Set properties persist on page.reload()
|
||||
});
|
||||
test.fixme('condition set object can be modified', async ({ page }) => {
|
||||
//Go to object created in step one
|
||||
//Update the Condition Set properties
|
||||
//Verify the Condition Set properties persist on Save
|
||||
//Verify the Condition Set properties persist on page.reload()
|
||||
});
|
||||
test.fixme('condition set object can be deleted', async ({ page }) => {
|
||||
//Go to object created in step one
|
||||
//Verify that Condition Set object can be deleted
|
||||
//Verify the Condition Set object does not exist in Tree
|
||||
//Verify the Condition Set object does not exist with direct navigation to object's URL
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
|
||||
/*
|
||||
Collection of Visual Tests set to run in a default context. The tests within this suite
|
||||
are only meant to run against openmct's app.js started by `npm run start` within the
|
||||
are only meant to run against openmct's app.js started by `npm run start` within the
|
||||
`./e2e/playwright-visual.config.js` file.
|
||||
|
||||
These should only use functional expect statements to verify assumptions about the state
|
||||
These should only use functional expect statements to verify assumptions about the state
|
||||
in a test and not for functional verification of correctness. Visual tests are not supposed
|
||||
to "fail" on assertions. Instead, they should be used to detect changes between builds or branches.
|
||||
|
||||
Note: Larger testsuite sizes are OK due to the setup time associated with these tests.
|
||||
Note: Larger testsuite sizes are OK due to the setup time associated with these tests.
|
||||
*/
|
||||
|
||||
const { test, expect } = require('@playwright/test');
|
||||
@@ -111,3 +111,50 @@ test('Visual - Default Condition Widget', async ({ page }) => {
|
||||
await page.waitForTimeout(VISUAL_GRACE_PERIOD);
|
||||
await percySnapshot(page, 'Default Condition Widget');
|
||||
});
|
||||
|
||||
test.skip('Visual - Display layout items view', async ({ page }) => {
|
||||
//Go to baseURL
|
||||
await page.goto('/', { waitUntil: 'networkidle' });
|
||||
|
||||
//Click the Create button
|
||||
await page.click('button:has-text("Create")');
|
||||
|
||||
// Click text=Display Layout
|
||||
await page.click('text=Display Layout');
|
||||
|
||||
// Click text=OK
|
||||
await page.click('text=OK');
|
||||
|
||||
// Take a snapshot of the newly created Display Layout object
|
||||
await page.waitForTimeout(VISUAL_GRACE_PERIOD);
|
||||
await percySnapshot(page, 'Default Display Layout');
|
||||
|
||||
// Click text=Snapshot Save and Finish Editing Save and Continue Editing >> button >> nth=1
|
||||
await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click();
|
||||
|
||||
// Click text=Save and Finish Editing
|
||||
await page.locator('text=Save and Finish Editing').click();
|
||||
|
||||
//Click the Create button
|
||||
await page.click('button:has-text("Create")');
|
||||
|
||||
// Click text=Sine Wave Generator
|
||||
await page.click('text=Sine Wave Generator');
|
||||
|
||||
// Click text=Save In Open MCT No items >> input[type="search"]
|
||||
await page.locator('text=Save In Open MCT No items >> input[type="search"]').click();
|
||||
|
||||
// Fill text=Save In Open MCT No items >> input[type="search"]
|
||||
await page.locator('text=Save In Open MCT No items >> input[type="search"]').fill('Unnamed Display Layout');
|
||||
|
||||
// Click text=OK Cancel
|
||||
await page.locator('text=OK Cancel').click();
|
||||
|
||||
// Click text=OK
|
||||
await page.click('text=OK');
|
||||
|
||||
// Take a snapshot of the newly created Display Layout object
|
||||
await page.waitForTimeout(VISUAL_GRACE_PERIOD);
|
||||
await percySnapshot(page, 'Default Sine Wave Generator');
|
||||
|
||||
});
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "openmct",
|
||||
"version": "2.0.1-SNAPSHOT",
|
||||
"version": "2.0.1",
|
||||
"description": "The Open MCT core platform",
|
||||
"devDependencies": {
|
||||
"@braintree/sanitize-url": "5.0.2",
|
||||
"@braintree/sanitize-url": "6.0.0",
|
||||
"@percy/cli": "1.0.0-beta.75",
|
||||
"@percy/playwright": "1.0.1",
|
||||
"@playwright/test": "1.19.1",
|
||||
"@playwright/test": "1.19.2",
|
||||
"allure-playwright": "2.0.0-beta.15",
|
||||
"babel-eslint": "10.1.0",
|
||||
"comma-separated-values": "3.6.4",
|
||||
|
||||
@@ -269,7 +269,6 @@ define([
|
||||
this.install(this.plugins.ViewDatumAction());
|
||||
this.install(this.plugins.ViewLargeAction());
|
||||
this.install(this.plugins.ObjectInterceptors());
|
||||
this.install(this.plugins.NonEditableFolder());
|
||||
this.install(this.plugins.DeviceClassifier());
|
||||
this.install(this.plugins.UserIndicator());
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ export default function (folderName, couchPlugin, searchFilter) {
|
||||
return Promise.resolve({
|
||||
identifier,
|
||||
type: 'folder',
|
||||
name: folderName || "CouchDB Documents"
|
||||
name: folderName || "CouchDB Documents",
|
||||
location: 'ROOT'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,8 @@ describe('the plugin', function () {
|
||||
expect(object).toEqual({
|
||||
identifier,
|
||||
type: 'folder',
|
||||
name: "CouchDB Documents"
|
||||
name: 'CouchDB Documents',
|
||||
location: 'ROOT'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -325,16 +325,7 @@ export default {
|
||||
return item && (item.type === type);
|
||||
},
|
||||
canPersistObject(item) {
|
||||
// for now the only way to tell if an object can be persisted is if it is creatable.
|
||||
let creatable = false;
|
||||
if (item) {
|
||||
const type = this.openmct.types.get(item.type);
|
||||
if (type && type.definition) {
|
||||
creatable = (type.definition.creatable !== undefined && (type.definition.creatable === 'true' || type.definition.creatable === true));
|
||||
}
|
||||
}
|
||||
|
||||
return creatable;
|
||||
return this.openmct.objects.isPersistable(item.identifier);
|
||||
},
|
||||
hasConditionalStyle(domainObject, layoutItem) {
|
||||
const id = layoutItem ? layoutItem.id : undefined;
|
||||
|
||||
@@ -166,7 +166,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
gridSize() {
|
||||
return this.domainObject.configuration.layoutGrid;
|
||||
return this.domainObject.configuration.layoutGrid.map(Number);
|
||||
},
|
||||
layoutItems() {
|
||||
return this.domainObject.configuration.items;
|
||||
|
||||
@@ -97,13 +97,16 @@ export default class DuplicateAction {
|
||||
|
||||
validate(currentParent) {
|
||||
return (data) => {
|
||||
const parentCandidatePath = data.value;
|
||||
const parentCandidate = parentCandidatePath[0];
|
||||
const parentCandidate = data.value[0];
|
||||
|
||||
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
||||
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
||||
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||
|
||||
if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parentCandidateKeystring || !currentParentKeystring) {
|
||||
return false;
|
||||
}
|
||||
@@ -122,13 +125,14 @@ export default class DuplicateAction {
|
||||
}
|
||||
|
||||
appliesTo(objectPath) {
|
||||
let parent = objectPath[1];
|
||||
let parentType = parent && this.openmct.types.get(parent.type);
|
||||
let child = objectPath[0];
|
||||
let childType = child && this.openmct.types.get(child.type);
|
||||
let locked = child.locked ? child.locked : parent && parent.locked;
|
||||
const parent = objectPath[1];
|
||||
const parentType = parent && this.openmct.types.get(parent.type);
|
||||
const child = objectPath[0];
|
||||
const childType = child && this.openmct.types.get(child.type);
|
||||
const locked = child.locked ? child.locked : parent && parent.locked;
|
||||
const isPersistable = this.openmct.objects.isPersistable(child.identifier);
|
||||
|
||||
if (locked) {
|
||||
if (locked || !isPersistable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ export default class ExportAsJSONAction {
|
||||
appliesTo(objectPath) {
|
||||
let domainObject = objectPath[0];
|
||||
|
||||
return this._isCreatable(domainObject);
|
||||
return this._isCreatableAndPersistable(domainObject);
|
||||
}
|
||||
/**
|
||||
*
|
||||
@@ -80,10 +80,11 @@ export default class ExportAsJSONAction {
|
||||
* @param {object} domainObject
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isCreatable(domainObject) {
|
||||
_isCreatableAndPersistable(domainObject) {
|
||||
const type = this.openmct.types.get(domainObject.type);
|
||||
const isPersistable = this.openmct.objects.isPersistable(domainObject.identifier);
|
||||
|
||||
return type && type.definition.creatable;
|
||||
return type && type.definition.creatable && isPersistable;
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
@@ -170,7 +171,7 @@ export default class ExportAsJSONAction {
|
||||
.then((children) => {
|
||||
children.forEach((child, index) => {
|
||||
// Only export if object is creatable
|
||||
if (this._isCreatable(child)) {
|
||||
if (this._isCreatableAndPersistable(child)) {
|
||||
// Prevents infinite export of self-contained objs
|
||||
if (!Object.prototype.hasOwnProperty.call(this.tree, this._getId(child))) {
|
||||
// If object is a link to something absent from
|
||||
|
||||
@@ -27,6 +27,10 @@ describe('Export as JSON plugin', () => {
|
||||
|
||||
it('ExportAsJSONAction applies to folder', () => {
|
||||
domainObject = {
|
||||
identifier: {
|
||||
key: 'export-testing',
|
||||
namespace: ''
|
||||
},
|
||||
composition: [],
|
||||
location: 'mine',
|
||||
modified: 1640115501237,
|
||||
@@ -40,6 +44,10 @@ describe('Export as JSON plugin', () => {
|
||||
|
||||
it('ExportAsJSONAction applies to telemetry.plot.overlay', () => {
|
||||
domainObject = {
|
||||
identifier: {
|
||||
key: 'export-testing',
|
||||
namespace: ''
|
||||
},
|
||||
composition: [],
|
||||
location: 'mine',
|
||||
modified: 1640115501237,
|
||||
@@ -53,6 +61,10 @@ describe('Export as JSON plugin', () => {
|
||||
|
||||
it('ExportAsJSONAction applies to telemetry.plot.stacked', () => {
|
||||
domainObject = {
|
||||
identifier: {
|
||||
key: 'export-testing',
|
||||
namespace: ''
|
||||
},
|
||||
composition: [],
|
||||
location: 'mine',
|
||||
modified: 1640115501237,
|
||||
@@ -64,16 +76,24 @@ describe('Export as JSON plugin', () => {
|
||||
expect(exportAsJSONAction.appliesTo([domainObject])).toEqual(true);
|
||||
});
|
||||
|
||||
it('ExportAsJSONAction applies does not applies to non-creatable objects', () => {
|
||||
it('ExportAsJSONAction does not applie to non-persistable objects', () => {
|
||||
domainObject = {
|
||||
identifier: {
|
||||
key: 'export-testing',
|
||||
namespace: ''
|
||||
},
|
||||
composition: [],
|
||||
location: 'mine',
|
||||
modified: 1640115501237,
|
||||
name: 'Non Editable Folder',
|
||||
persisted: 1640115501237,
|
||||
type: 'noneditable.folder'
|
||||
type: 'folder'
|
||||
};
|
||||
|
||||
spyOn(openmct.objects, 'getProvider').and.callFake(() => {
|
||||
return { get: () => domainObject };
|
||||
});
|
||||
|
||||
expect(exportAsJSONAction.appliesTo([domainObject])).toEqual(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<template v-for="(container, index) in containers">
|
||||
<drop-hint
|
||||
v-if="index === 0 && containers.length > 1"
|
||||
:key="index"
|
||||
:key="`hint-top-${container.id}`"
|
||||
class="c-fl-frame__drop-hint"
|
||||
:index="-1"
|
||||
:allow-drop="allowContainerDrop"
|
||||
@@ -51,7 +51,7 @@
|
||||
/>
|
||||
|
||||
<container-component
|
||||
:key="container.id"
|
||||
:key="`component-${container.id}`"
|
||||
class="c-fl__container"
|
||||
:index="index"
|
||||
:container="container"
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
<resize-handle
|
||||
v-if="index !== (containers.length - 1)"
|
||||
:key="index"
|
||||
:key="`handle-${container.id}`"
|
||||
:index="index"
|
||||
:orientation="rowsLayout ? 'vertical' : 'horizontal'"
|
||||
:is-editing="isEditing"
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
<drop-hint
|
||||
v-if="containers.length > 1"
|
||||
:key="index"
|
||||
:key="`hint-bottom-${container.id}`"
|
||||
class="c-fl-frame__drop-hint"
|
||||
:index="index"
|
||||
:allow-drop="allowContainerDrop"
|
||||
|
||||
@@ -101,7 +101,10 @@ export default class CreateWizard {
|
||||
// Ensure there is always a 'save in' section
|
||||
if (includeLocation) {
|
||||
function validateLocation(data) {
|
||||
return self.openmct.composition.checkPolicy(data.value[0], domainObject);
|
||||
const policyCheck = self.openmct.composition.checkPolicy(data.value[0], domainObject);
|
||||
const parentIsPersistable = self.openmct.objects.isPersistable(data.value[0].identifier);
|
||||
|
||||
return policyCheck && parentIsPersistable;
|
||||
}
|
||||
|
||||
sections.push({
|
||||
|
||||
@@ -33,10 +33,7 @@ export default class LinkAction {
|
||||
}
|
||||
|
||||
appliesTo(objectPath) {
|
||||
let domainObject = objectPath[0];
|
||||
let type = domainObject && this.openmct.types.get(domainObject.type);
|
||||
|
||||
return type && type.definition.creatable;
|
||||
return true; // link away!
|
||||
}
|
||||
|
||||
invoke(objectPath) {
|
||||
@@ -77,6 +74,7 @@ export default class LinkAction {
|
||||
{
|
||||
name: "location",
|
||||
control: "locator",
|
||||
parent: parentDomainObject,
|
||||
required: true,
|
||||
validate: this.validate(parentDomainObject),
|
||||
key: 'location'
|
||||
@@ -92,11 +90,26 @@ export default class LinkAction {
|
||||
|
||||
validate(currentParent) {
|
||||
return (data) => {
|
||||
|
||||
// default current parent to ROOT, if it's undefined, then it's a root level item
|
||||
if (currentParent === undefined) {
|
||||
currentParent = {
|
||||
identifier: {
|
||||
key: 'ROOT',
|
||||
namespace: ''
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const parentCandidate = data.value[0];
|
||||
const currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
||||
const parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
||||
const objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||
|
||||
if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parentCandidateKeystring || !currentParentKeystring) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ export default class MoveAction {
|
||||
{
|
||||
name: "Location",
|
||||
control: "locator",
|
||||
parent: parentDomainObject,
|
||||
required: true,
|
||||
validate: this.validate(parentDomainObject),
|
||||
key: 'location'
|
||||
@@ -144,6 +145,10 @@ export default class MoveAction {
|
||||
const parentCandidatePath = data.value;
|
||||
const parentCandidate = parentCandidatePath[0];
|
||||
|
||||
if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
||||
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
||||
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||
@@ -174,8 +179,9 @@ export default class MoveAction {
|
||||
let parentType = parent && this.openmct.types.get(parent.type);
|
||||
let child = objectPath[0];
|
||||
let childType = child && this.openmct.types.get(child.type);
|
||||
let isPersistable = this.openmct.objects.isPersistable(child.identifier);
|
||||
|
||||
if (child.locked || (parent && parent.locked)) {
|
||||
if (child.locked || (parent && parent.locked) || !isPersistable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2022, 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 () {
|
||||
return function (openmct) {
|
||||
openmct.types.addType("noneditable.folder", {
|
||||
name: "Non-Editable Folder",
|
||||
key: "noneditable.folder",
|
||||
description: "Create folders to organize other objects or links to objects without the ability to edit it's properties.",
|
||||
cssClass: "icon-folder",
|
||||
creatable: false
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2022, 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,
|
||||
resetApplicationState
|
||||
} from 'utils/testing';
|
||||
|
||||
describe("the plugin", () => {
|
||||
const NON_EDITABLE_FOLDER_KEY = 'noneditable.folder';
|
||||
let openmct;
|
||||
|
||||
beforeEach((done) => {
|
||||
openmct = createOpenMct();
|
||||
openmct.install(openmct.plugins.NonEditableFolder());
|
||||
|
||||
openmct.on('start', done);
|
||||
openmct.startHeadless();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
return resetApplicationState(openmct);
|
||||
});
|
||||
|
||||
it('adds the new non-editable folder type', () => {
|
||||
const type = openmct.types.get(NON_EDITABLE_FOLDER_KEY);
|
||||
|
||||
expect(type).toBeDefined();
|
||||
expect(type.definition.creatable).toBeFalse();
|
||||
});
|
||||
|
||||
});
|
||||
@@ -21,6 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
export function getValidatedPlan(domainObject) {
|
||||
let sourceMap = domainObject.sourceMap;
|
||||
let body = domainObject.selectFile.body;
|
||||
let json = {};
|
||||
if (typeof body === 'string') {
|
||||
@@ -33,5 +34,33 @@ export function getValidatedPlan(domainObject) {
|
||||
json = body;
|
||||
}
|
||||
|
||||
return json;
|
||||
if (sourceMap !== undefined && sourceMap.activities !== undefined && sourceMap.groupId !== undefined) {
|
||||
let mappedJson = {};
|
||||
json[sourceMap.activities].forEach((activity) => {
|
||||
if (activity[sourceMap.groupId]) {
|
||||
const groupIdKey = activity[sourceMap.groupId];
|
||||
let groupActivity = {
|
||||
...activity
|
||||
};
|
||||
|
||||
if (sourceMap.start) {
|
||||
groupActivity.start = activity[sourceMap.start];
|
||||
}
|
||||
|
||||
if (sourceMap.end) {
|
||||
groupActivity.end = activity[sourceMap.end];
|
||||
}
|
||||
|
||||
if (!mappedJson[groupIdKey]) {
|
||||
mappedJson[groupIdKey] = [];
|
||||
}
|
||||
|
||||
mappedJson[groupIdKey].push(groupActivity);
|
||||
}
|
||||
});
|
||||
|
||||
return mappedJson;
|
||||
} else {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,6 @@ define([
|
||||
'./URLTimeSettingsSynchronizer/plugin',
|
||||
'./notificationIndicator/plugin',
|
||||
'./newFolderAction/plugin',
|
||||
'./nonEditableFolder/plugin',
|
||||
'./persistence/couch/plugin',
|
||||
'./defaultRootName/plugin',
|
||||
'./plan/plugin',
|
||||
@@ -119,7 +118,6 @@ define([
|
||||
URLTimeSettingsSynchronizer,
|
||||
NotificationIndicator,
|
||||
NewFolderAction,
|
||||
NonEditableFolder,
|
||||
CouchDBPlugin,
|
||||
DefaultRootName,
|
||||
PlanLayout,
|
||||
@@ -151,7 +149,7 @@ define([
|
||||
|
||||
plugins.MyItems = MyItems.default;
|
||||
|
||||
plugins.StaticRootPlugin = StaticRootPlugin;
|
||||
plugins.StaticRootPlugin = StaticRootPlugin.default;
|
||||
|
||||
/**
|
||||
* A tabular view showing the latest values of multiple telemetry points at
|
||||
@@ -197,7 +195,6 @@ define([
|
||||
plugins.URLTimeSettingsSynchronizer = URLTimeSettingsSynchronizer.default;
|
||||
plugins.NotificationIndicator = NotificationIndicator.default;
|
||||
plugins.NewFolderAction = NewFolderAction.default;
|
||||
plugins.NonEditableFolder = NonEditableFolder.default;
|
||||
plugins.ISOTimeFormat = ISOTimeFormat.default;
|
||||
plugins.DefaultRootName = DefaultRootName.default;
|
||||
plugins.PlanLayout = PlanLayout.default;
|
||||
|
||||
@@ -92,20 +92,35 @@ export default class RemoveAction {
|
||||
this.openmct.editor.save();
|
||||
}
|
||||
|
||||
const parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
|
||||
const isAlias = parentKeyString !== child.location;
|
||||
|
||||
if (!isAlias) {
|
||||
if (!this.isAlias(child, parent)) {
|
||||
this.openmct.objects.mutate(child, 'location', null);
|
||||
}
|
||||
}
|
||||
|
||||
isAlias(child, parent) {
|
||||
if (parent === undefined) {
|
||||
// then it's a root item, not an alias
|
||||
return false;
|
||||
}
|
||||
|
||||
const parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
|
||||
const childLocation = child.location;
|
||||
|
||||
return childLocation !== parentKeyString;
|
||||
}
|
||||
|
||||
appliesTo(objectPath) {
|
||||
let parent = objectPath[1];
|
||||
let parentType = parent && this.openmct.types.get(parent.type);
|
||||
let child = objectPath[0];
|
||||
let locked = child.locked ? child.locked : parent && parent.locked;
|
||||
let isEditing = this.openmct.editor.isEditing();
|
||||
const parent = objectPath[1];
|
||||
const parentType = parent && this.openmct.types.get(parent.type);
|
||||
const child = objectPath[0];
|
||||
const locked = child.locked ? child.locked : parent && parent.locked;
|
||||
const isEditing = this.openmct.editor.isEditing();
|
||||
const isPersistable = this.openmct.objects.isPersistable(child.identifier);
|
||||
const isAlias = this.isAlias(child, parent);
|
||||
|
||||
if (locked || (!isPersistable && !isAlias)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isEditing) {
|
||||
let currentItemInView = this.openmct.router.path[0];
|
||||
@@ -116,10 +131,6 @@ export default class RemoveAction {
|
||||
}
|
||||
}
|
||||
|
||||
if (locked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parentType
|
||||
&& parentType.definition.creatable
|
||||
&& Array.isArray(parent.composition);
|
||||
|
||||
@@ -1,45 +1,139 @@
|
||||
define([
|
||||
'objectUtils'
|
||||
], function (
|
||||
objectUtils
|
||||
) {
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2022, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Transforms an import json blob into a object map that can be used to
|
||||
* provide objects. Rewrites root identifier in import data with provided
|
||||
* rootIdentifier, and rewrites all child object identifiers so that they
|
||||
* exist in the same namespace as the rootIdentifier.
|
||||
*/
|
||||
import objectUtils from 'objectUtils';
|
||||
|
||||
class StaticModelProvider {
|
||||
constructor(importData, rootIdentifier) {
|
||||
this.objectMap = {};
|
||||
this.rewriteModel(importData, rootIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an import json blob into a object map that can be used to
|
||||
* provide objects. Rewrites root identifier in import data with provided
|
||||
* rootIdentifier, and rewrites all child object identifiers so that they
|
||||
* exist in the same namespace as the rootIdentifier.
|
||||
* Standard "Get".
|
||||
*/
|
||||
function rewriteObjectIdentifiers(importData, rootIdentifier) {
|
||||
const rootId = importData.rootId;
|
||||
let objectString = JSON.stringify(importData.openmct);
|
||||
get(identifier) {
|
||||
const keyString = objectUtils.makeKeyString(identifier);
|
||||
if (this.objectMap[keyString]) {
|
||||
return this.objectMap[keyString];
|
||||
}
|
||||
|
||||
Object.keys(importData.openmct).forEach(function (originalId, i) {
|
||||
let newId;
|
||||
if (originalId === rootId) {
|
||||
newId = objectUtils.makeKeyString(rootIdentifier);
|
||||
} else {
|
||||
newId = objectUtils.makeKeyString({
|
||||
namespace: rootIdentifier.namespace,
|
||||
key: i
|
||||
throw new Error(keyString + ' not found in import models.');
|
||||
}
|
||||
|
||||
parseObjectLeaf(objectLeaf, idMap, namespace) {
|
||||
Object.keys(objectLeaf).forEach((nodeKey) => {
|
||||
if (idMap.get(nodeKey)) {
|
||||
const newIdentifier = objectUtils.makeKeyString({
|
||||
namespace,
|
||||
key: idMap.get(nodeKey)
|
||||
});
|
||||
}
|
||||
|
||||
while (objectString.indexOf(originalId) !== -1) {
|
||||
objectString = objectString.replace(
|
||||
'"' + originalId + '"',
|
||||
'"' + newId + '"'
|
||||
);
|
||||
objectLeaf[newIdentifier] = { ...objectLeaf[nodeKey] };
|
||||
delete objectLeaf[nodeKey];
|
||||
objectLeaf[newIdentifier] = this.parseTreeLeaf(newIdentifier, objectLeaf[newIdentifier], idMap, namespace);
|
||||
} else {
|
||||
objectLeaf[nodeKey] = this.parseTreeLeaf(nodeKey, objectLeaf[nodeKey], idMap, namespace);
|
||||
}
|
||||
});
|
||||
|
||||
return JSON.parse(objectString);
|
||||
return objectLeaf;
|
||||
}
|
||||
|
||||
parseArrayLeaf(arrayLeaf, idMap, namespace) {
|
||||
return arrayLeaf.map((leafValue, index) => this.parseTreeLeaf(
|
||||
null, leafValue, idMap, namespace));
|
||||
}
|
||||
|
||||
parseBranchedLeaf(branchedLeafValue, idMap, namespace) {
|
||||
if (Array.isArray(branchedLeafValue)) {
|
||||
return this.parseArrayLeaf(branchedLeafValue, idMap, namespace);
|
||||
} else {
|
||||
return this.parseObjectLeaf(branchedLeafValue, idMap, namespace);
|
||||
}
|
||||
}
|
||||
|
||||
parseTreeLeaf(leafKey, leafValue, idMap, namespace) {
|
||||
const hasChild = typeof leafValue === 'object';
|
||||
if (hasChild) {
|
||||
return this.parseBranchedLeaf(leafValue, idMap, namespace);
|
||||
}
|
||||
|
||||
if (leafKey === 'key') {
|
||||
return idMap.get(leafValue);
|
||||
} else if (leafKey === 'namespace') {
|
||||
return namespace;
|
||||
} else if (leafKey === 'location') {
|
||||
if (idMap.get(leafValue)) {
|
||||
const newLocationIdentifier = objectUtils.makeKeyString({
|
||||
namespace,
|
||||
key: idMap.get(leafValue)
|
||||
});
|
||||
|
||||
return newLocationIdentifier;
|
||||
}
|
||||
|
||||
return null;
|
||||
} else if (idMap.get(leafValue)) {
|
||||
const newIdentifier = objectUtils.makeKeyString({
|
||||
namespace,
|
||||
key: idMap.get(leafValue)
|
||||
});
|
||||
|
||||
return newIdentifier;
|
||||
} else {
|
||||
return leafValue;
|
||||
}
|
||||
}
|
||||
|
||||
rewriteObjectIdentifiers(importData, rootIdentifier) {
|
||||
const namespace = rootIdentifier.namespace;
|
||||
const idMap = new Map();
|
||||
const objectTree = importData.openmct;
|
||||
|
||||
Object.keys(objectTree).forEach((originalId, index) => {
|
||||
let newId = index.toString();
|
||||
if (originalId === importData.rootId) {
|
||||
newId = rootIdentifier.key;
|
||||
}
|
||||
|
||||
idMap.set(originalId, newId);
|
||||
});
|
||||
|
||||
const newTree = this.parseTreeLeaf(null, objectTree, idMap, namespace);
|
||||
|
||||
return newTree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all objects in an object make from old format objects to new
|
||||
* format objects.
|
||||
*/
|
||||
function convertToNewObjects(oldObjectMap) {
|
||||
convertToNewObjects(oldObjectMap) {
|
||||
return Object.keys(oldObjectMap)
|
||||
.reduce(function (newObjectMap, key) {
|
||||
newObjectMap[key] = objectUtils.toNewFormat(oldObjectMap[key], key);
|
||||
@@ -49,7 +143,7 @@ define([
|
||||
}
|
||||
|
||||
/* Set the root location correctly for a top-level object */
|
||||
function setRootLocation(objectMap, rootIdentifier) {
|
||||
setRootLocation(objectMap, rootIdentifier) {
|
||||
objectMap[objectUtils.makeKeyString(rootIdentifier)].location = 'ROOT';
|
||||
|
||||
return objectMap;
|
||||
@@ -59,24 +153,11 @@ define([
|
||||
* Takes importData (as provided by the ImportExport plugin) and exposes
|
||||
* an object provider to fetch those objects.
|
||||
*/
|
||||
function StaticModelProvider(importData, rootIdentifier) {
|
||||
const oldFormatObjectMap = rewriteObjectIdentifiers(importData, rootIdentifier);
|
||||
const newFormatObjectMap = convertToNewObjects(oldFormatObjectMap);
|
||||
this.objectMap = setRootLocation(newFormatObjectMap, rootIdentifier);
|
||||
rewriteModel(importData, rootIdentifier) {
|
||||
const oldFormatObjectMap = this.rewriteObjectIdentifiers(importData, rootIdentifier);
|
||||
const newFormatObjectMap = this.convertToNewObjects(oldFormatObjectMap);
|
||||
this.objectMap = this.setRootLocation(newFormatObjectMap, rootIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard "Get".
|
||||
*/
|
||||
StaticModelProvider.prototype.get = function (identifier) {
|
||||
const keyString = objectUtils.makeKeyString(identifier);
|
||||
if (this.objectMap[keyString]) {
|
||||
return this.objectMap[keyString];
|
||||
}
|
||||
|
||||
throw new Error(keyString + ' not found in import models.');
|
||||
};
|
||||
|
||||
return StaticModelProvider;
|
||||
|
||||
});
|
||||
export default StaticModelProvider;
|
||||
|
||||
@@ -1,133 +1,149 @@
|
||||
define([
|
||||
'./StaticModelProvider',
|
||||
'./static-provider-test.json'
|
||||
], function (
|
||||
StaticModelProvider,
|
||||
testStaticData
|
||||
) {
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2022, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
describe('StaticModelProvider', function () {
|
||||
import testStaticData from './static-provider-test.json';
|
||||
import StaticModelProvider from './StaticModelProvider';
|
||||
|
||||
let staticProvider;
|
||||
describe('StaticModelProvider', function () {
|
||||
|
||||
let staticProvider;
|
||||
|
||||
beforeEach(function () {
|
||||
const staticData = JSON.parse(JSON.stringify(testStaticData));
|
||||
staticProvider = new StaticModelProvider(staticData, {
|
||||
namespace: 'my-import',
|
||||
key: 'root'
|
||||
});
|
||||
});
|
||||
|
||||
describe('rootObject', function () {
|
||||
let rootModel;
|
||||
|
||||
beforeEach(function () {
|
||||
const staticData = JSON.parse(JSON.stringify(testStaticData));
|
||||
staticProvider = new StaticModelProvider(staticData, {
|
||||
rootModel = staticProvider.get({
|
||||
namespace: 'my-import',
|
||||
key: 'root'
|
||||
});
|
||||
});
|
||||
|
||||
describe('rootObject', function () {
|
||||
let rootModel;
|
||||
it('is located at top level', function () {
|
||||
expect(rootModel.location).toBe('ROOT');
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
rootModel = staticProvider.get({
|
||||
namespace: 'my-import',
|
||||
key: 'root'
|
||||
});
|
||||
});
|
||||
|
||||
it('is located at top level', function () {
|
||||
expect(rootModel.location).toBe('ROOT');
|
||||
});
|
||||
|
||||
it('has new-format identifier', function () {
|
||||
expect(rootModel.identifier).toEqual({
|
||||
namespace: 'my-import',
|
||||
key: 'root'
|
||||
});
|
||||
});
|
||||
|
||||
it('has new-format composition', function () {
|
||||
expect(rootModel.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
expect(rootModel.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '2'
|
||||
});
|
||||
it('has new-format identifier', function () {
|
||||
expect(rootModel.identifier).toEqual({
|
||||
namespace: 'my-import',
|
||||
key: 'root'
|
||||
});
|
||||
});
|
||||
|
||||
describe('childObjects', function () {
|
||||
let swg;
|
||||
let layout;
|
||||
let fixed;
|
||||
|
||||
beforeEach(function () {
|
||||
swg = staticProvider.get({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
layout = staticProvider.get({
|
||||
namespace: 'my-import',
|
||||
key: '2'
|
||||
});
|
||||
fixed = staticProvider.get({
|
||||
namespace: 'my-import',
|
||||
key: '3'
|
||||
});
|
||||
it('has new-format composition', function () {
|
||||
expect(rootModel.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
|
||||
it('match expected ordering', function () {
|
||||
// this is a sanity check to make sure the identifiers map in
|
||||
// the correct order.
|
||||
expect(swg.type).toBe('generator');
|
||||
expect(layout.type).toBe('layout');
|
||||
expect(fixed.type).toBe('telemetry.fixed');
|
||||
expect(rootModel.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '2'
|
||||
});
|
||||
|
||||
it('have new-style identifiers', function () {
|
||||
expect(swg.identifier).toEqual({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
expect(layout.identifier).toEqual({
|
||||
namespace: 'my-import',
|
||||
key: '2'
|
||||
});
|
||||
expect(fixed.identifier).toEqual({
|
||||
namespace: 'my-import',
|
||||
key: '3'
|
||||
});
|
||||
});
|
||||
|
||||
it('have new-style composition', function () {
|
||||
expect(layout.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
expect(layout.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '3'
|
||||
});
|
||||
expect(fixed.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
});
|
||||
|
||||
it('rewrites locations', function () {
|
||||
expect(swg.location).toBe('my-import:root');
|
||||
expect(layout.location).toBe('my-import:root');
|
||||
expect(fixed.location).toBe('my-import:2');
|
||||
});
|
||||
|
||||
it('rewrites matched identifiers in objects', function () {
|
||||
expect(layout.configuration.layout.panels['my-import:1'])
|
||||
.toBeDefined();
|
||||
expect(layout.configuration.layout.panels['my-import:3'])
|
||||
.toBeDefined();
|
||||
expect(layout.configuration.layout.panels['483c00d4-bb1d-4b42-b29a-c58e06b322a0'])
|
||||
.not.toBeDefined();
|
||||
expect(layout.configuration.layout.panels['20273193-f069-49e9-b4f7-b97a87ed755d'])
|
||||
.not.toBeDefined();
|
||||
expect(fixed.configuration['fixed-display'].elements[0].id)
|
||||
.toBe('my-import:1');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('childObjects', function () {
|
||||
let swg;
|
||||
let layout;
|
||||
let fixed;
|
||||
|
||||
beforeEach(function () {
|
||||
swg = staticProvider.get({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
layout = staticProvider.get({
|
||||
namespace: 'my-import',
|
||||
key: '2'
|
||||
});
|
||||
fixed = staticProvider.get({
|
||||
namespace: 'my-import',
|
||||
key: '3'
|
||||
});
|
||||
});
|
||||
|
||||
it('match expected ordering', function () {
|
||||
// this is a sanity check to make sure the identifiers map in
|
||||
// the correct order.
|
||||
expect(swg.type).toBe('generator');
|
||||
expect(layout.type).toBe('layout');
|
||||
expect(fixed.type).toBe('telemetry.fixed');
|
||||
});
|
||||
|
||||
it('have new-style identifiers', function () {
|
||||
expect(swg.identifier).toEqual({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
expect(layout.identifier).toEqual({
|
||||
namespace: 'my-import',
|
||||
key: '2'
|
||||
});
|
||||
expect(fixed.identifier).toEqual({
|
||||
namespace: 'my-import',
|
||||
key: '3'
|
||||
});
|
||||
});
|
||||
|
||||
it('have new-style composition', function () {
|
||||
expect(layout.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
expect(layout.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '3'
|
||||
});
|
||||
expect(fixed.composition).toContain({
|
||||
namespace: 'my-import',
|
||||
key: '1'
|
||||
});
|
||||
});
|
||||
|
||||
it('rewrites locations', function () {
|
||||
expect(swg.location).toBe('my-import:root');
|
||||
expect(layout.location).toBe('my-import:root');
|
||||
expect(fixed.location).toBe('my-import:2');
|
||||
});
|
||||
|
||||
it('rewrites matched identifiers in objects', function () {
|
||||
expect(layout.configuration.layout.panels['my-import:1'])
|
||||
.toBeDefined();
|
||||
expect(layout.configuration.layout.panels['my-import:3'])
|
||||
.toBeDefined();
|
||||
expect(layout.configuration.layout.panels['483c00d4-bb1d-4b42-b29a-c58e06b322a0'])
|
||||
.not.toBeDefined();
|
||||
expect(layout.configuration.layout.panels['20273193-f069-49e9-b4f7-b97a87ed755d'])
|
||||
.not.toBeDefined();
|
||||
expect(fixed.configuration['fixed-display'].elements[0].id)
|
||||
.toBe('my-import:1');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,52 +1,63 @@
|
||||
define([
|
||||
'./StaticModelProvider'
|
||||
], function (
|
||||
StaticModelProvider
|
||||
) {
|
||||
/**
|
||||
* Static Root Plugin: takes an export file and exposes it as a new root
|
||||
* object.
|
||||
*/
|
||||
function StaticRootPlugin(namespace, exportUrl) {
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2022, 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.
|
||||
*****************************************************************************/
|
||||
|
||||
const rootIdentifier = {
|
||||
namespace: namespace,
|
||||
key: 'root'
|
||||
};
|
||||
import StaticModelProvider from './StaticModelProvider';
|
||||
|
||||
let cachedProvider;
|
||||
export default function StaticRootPlugin(options) {
|
||||
const rootIdentifier = {
|
||||
namespace: options.namespace,
|
||||
key: 'root'
|
||||
};
|
||||
|
||||
function loadProvider() {
|
||||
return fetch(exportUrl)
|
||||
.then(function (response) {
|
||||
return response.json();
|
||||
})
|
||||
.then(function (importData) {
|
||||
cachedProvider = new StaticModelProvider(importData, rootIdentifier);
|
||||
let cachedProvider;
|
||||
|
||||
return cachedProvider;
|
||||
});
|
||||
}
|
||||
function loadProvider() {
|
||||
return fetch(options.exportUrl)
|
||||
.then(function (response) {
|
||||
return response.json();
|
||||
})
|
||||
.then(function (importData) {
|
||||
cachedProvider = new StaticModelProvider(importData, rootIdentifier);
|
||||
|
||||
function getProvider() {
|
||||
if (!cachedProvider) {
|
||||
cachedProvider = loadProvider();
|
||||
}
|
||||
|
||||
return Promise.resolve(cachedProvider);
|
||||
}
|
||||
|
||||
return function install(openmct) {
|
||||
openmct.objects.addRoot(rootIdentifier);
|
||||
openmct.objects.addProvider(namespace, {
|
||||
get: function (identifier) {
|
||||
return getProvider().then(function (provider) {
|
||||
return provider.get(identifier);
|
||||
});
|
||||
}
|
||||
return cachedProvider;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return StaticRootPlugin;
|
||||
});
|
||||
function getProvider() {
|
||||
if (!cachedProvider) {
|
||||
cachedProvider = loadProvider();
|
||||
}
|
||||
|
||||
return Promise.resolve(cachedProvider);
|
||||
}
|
||||
|
||||
return function install(openmct) {
|
||||
openmct.objects.addRoot(rootIdentifier);
|
||||
openmct.objects.addProvider(options.namespace, {
|
||||
get: function (identifier) {
|
||||
return getProvider().then(function (provider) {
|
||||
return provider.get(identifier);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,9 +31,11 @@
|
||||
>
|
||||
<div class="c-conductor__time-bounds">
|
||||
<conductor-inputs-fixed v-if="isFixed"
|
||||
:input-bounds="viewBounds"
|
||||
@updated="saveFixedOffsets"
|
||||
/>
|
||||
<conductor-inputs-realtime v-else
|
||||
:input-bounds="viewBounds"
|
||||
@updated="saveClockOffsets"
|
||||
/>
|
||||
<ConductorModeIcon class="c-conductor__mode-icon" />
|
||||
|
||||
@@ -71,6 +71,12 @@ export default {
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
inputBounds: {
|
||||
type: Object,
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -98,6 +104,12 @@ export default {
|
||||
watch: {
|
||||
keyString() {
|
||||
this.setTimeContext();
|
||||
},
|
||||
inputBounds: {
|
||||
handler(newBounds) {
|
||||
this.handleNewBounds(newBounds);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
ref="startOffset"
|
||||
class="c-button c-conductor__delta-button"
|
||||
title="Set the time offset after now"
|
||||
@click.prevent="showTimePopupStart"
|
||||
@click.prevent.stop="showTimePopupStart"
|
||||
>
|
||||
{{ offsets.start }}
|
||||
</button>
|
||||
@@ -60,7 +60,7 @@
|
||||
ref="endOffset"
|
||||
class="c-button c-conductor__delta-button"
|
||||
title="Set the time offset preceding now"
|
||||
@click.prevent="showTimePopupEnd"
|
||||
@click.prevent.stop="showTimePopupEnd"
|
||||
>
|
||||
{{ offsets.end }}
|
||||
</button>
|
||||
@@ -86,6 +86,12 @@ export default {
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
inputBounds: {
|
||||
type: Object,
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -118,6 +124,12 @@ export default {
|
||||
watch: {
|
||||
keyString() {
|
||||
this.setTimeContext();
|
||||
},
|
||||
inputBounds: {
|
||||
handler(newBounds) {
|
||||
this.handleNewBounds(newBounds);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -122,6 +122,9 @@
|
||||
flex: 1 1 auto;
|
||||
height: 0; // Chrome 73 overflow bug fix
|
||||
overflow: auto;
|
||||
//To accommodate independent time conductor controls
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.u-fills-container {
|
||||
// Expand component types that fill a container
|
||||
|
||||
@@ -258,10 +258,12 @@ export default {
|
||||
if (!this.isSelectorTree) {
|
||||
await this.syncTreeOpenItems();
|
||||
} else {
|
||||
const objectPath = await this.openmct.objects.getOriginalPath(this.initialSelection.identifier);
|
||||
const navigationPath = this.buildNavigationPath(objectPath);
|
||||
if (this.initialSelection.identifier) {
|
||||
const objectPath = await this.openmct.objects.getOriginalPath(this.initialSelection.identifier);
|
||||
const navigationPath = this.buildNavigationPath(objectPath);
|
||||
|
||||
this.openAndScrollTo(navigationPath);
|
||||
this.openAndScrollTo(navigationPath);
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
Reference in New Issue
Block a user