Compare commits
	
		
			11 Commits
		
	
	
		
			fix-stacke
			...
			fix-gha-pl
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					91cf387dff | ||
| 
						 | 
					482d8f392c | ||
| 
						 | 
					bb0d3c2201 | ||
| 
						 | 
					67234c70a4 | ||
| 
						 | 
					d849b18e63 | ||
| 
						 | 
					3c33395c2c | ||
| 
						 | 
					e9680e975f | ||
| 
						 | 
					e9e5f4aeca | ||
| 
						 | 
					1086ccfd58 | ||
| 
						 | 
					ee7f5a3c2f | ||
| 
						 | 
					e691a89682 | 
							
								
								
									
										2
									
								
								.github/workflows/e2e-pr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/e2e-pr.yml
									
									
									
									
										vendored
									
									
								
							@@ -30,7 +30,7 @@ jobs:
 | 
			
		||||
      - uses: actions/setup-node@v3
 | 
			
		||||
        with:
 | 
			
		||||
          node-version: '16'
 | 
			
		||||
      - run: npx playwright install-deps
 | 
			
		||||
      - run: npx playwright@1.19.2 install
 | 
			
		||||
      - run: npm install
 | 
			
		||||
      - run: npm run test:e2e:full
 | 
			
		||||
      - name: Archive test results
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/e2e-visual.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/e2e-visual.yml
									
									
									
									
										vendored
									
									
								
							@@ -17,7 +17,7 @@ jobs:
 | 
			
		||||
      - uses: actions/setup-node@v3
 | 
			
		||||
        with:
 | 
			
		||||
          node-version: '16'
 | 
			
		||||
      - run: npx playwright install-deps
 | 
			
		||||
      - run: npx playwright@1.19.2 install
 | 
			
		||||
      - run: npm install
 | 
			
		||||
      - name: Run the e2e visual tests
 | 
			
		||||
        run: npm run test:e2e:visual
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										161
									
								
								e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								e2e/tests/example/generator/SinewaveLimitProvider.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
This test suite is dedicated to tests which verify the basic operations surrounding conditionSets.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const { test, expect } = require('@playwright/test');
 | 
			
		||||
 | 
			
		||||
test.describe('Sine Wave Generator', () => {
 | 
			
		||||
    test('Create new Sine Wave Generator Object and validate create Form Logic', async ({ page }) => {
 | 
			
		||||
        //Go to baseURL
 | 
			
		||||
        await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
 | 
			
		||||
        //Click the Create button
 | 
			
		||||
        await page.click('button:has-text("Create")');
 | 
			
		||||
 | 
			
		||||
        // Click Sine Wave Generator
 | 
			
		||||
        await page.click('text=Sine Wave Generator');
 | 
			
		||||
 | 
			
		||||
        // Verify that the each required field has required indicator
 | 
			
		||||
        // Title
 | 
			
		||||
        await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(['c-form-row__state-indicator  req']);
 | 
			
		||||
 | 
			
		||||
        // Verify that the Notes row does not have a required indicator
 | 
			
		||||
        await expect(page.locator('.c-form__section div:nth-child(3) .form-row .c-form-row__state-indicator')).not.toContain('.req');
 | 
			
		||||
 | 
			
		||||
        // Period
 | 
			
		||||
        await expect(page.locator('.c-form__section div:nth-child(4) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']);
 | 
			
		||||
 | 
			
		||||
        // Amplitude
 | 
			
		||||
        await expect(page.locator('.c-form__section div:nth-child(5) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']);
 | 
			
		||||
 | 
			
		||||
        // Offset
 | 
			
		||||
        await expect(page.locator('.c-form__section div:nth-child(6) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']);
 | 
			
		||||
 | 
			
		||||
        // Data Rate
 | 
			
		||||
        await expect(page.locator('.c-form__section div:nth-child(7) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']);
 | 
			
		||||
 | 
			
		||||
        // Phase
 | 
			
		||||
        await expect(page.locator('.c-form__section div:nth-child(8) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']);
 | 
			
		||||
 | 
			
		||||
        // Randomness
 | 
			
		||||
        await expect(page.locator('.c-form__section div:nth-child(9) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req']);
 | 
			
		||||
 | 
			
		||||
        // Verify that by removing value from required text field shows invalid indicator
 | 
			
		||||
        await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill('');
 | 
			
		||||
        await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(['c-form-row__state-indicator  req invalid']);
 | 
			
		||||
 | 
			
		||||
        // Verify that by adding value to empty required text field changes invalid to valid indicator
 | 
			
		||||
        await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill('non empty');
 | 
			
		||||
        await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(['c-form-row__state-indicator  req valid']);
 | 
			
		||||
 | 
			
		||||
        // Verify that by removing value from required number field shows invalid indicator
 | 
			
		||||
        await page.locator('.field.control.l-input-sm input').first().fill('');
 | 
			
		||||
        await expect(page.locator('.c-form__section div:nth-child(4) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req invalid']);
 | 
			
		||||
 | 
			
		||||
        // Verify that by adding value to empty required number field changes invalid to valid indicator
 | 
			
		||||
        await page.locator('.field.control.l-input-sm input').first().fill('3');
 | 
			
		||||
        await expect(page.locator('.c-form__section div:nth-child(4) .form-row .c-form-row__state-indicator')).toHaveClass(['c-form-row__state-indicator  req valid']);
 | 
			
		||||
 | 
			
		||||
        // Verify that can change value of number field by up/down arrows keys
 | 
			
		||||
        // Click .field.control.l-input-sm input >> nth=0
 | 
			
		||||
        await page.locator('.field.control.l-input-sm input').first().click();
 | 
			
		||||
        // Press ArrowUp 3 times to change value from 3 to 6
 | 
			
		||||
        await page.locator('.field.control.l-input-sm input').first().press('ArrowUp');
 | 
			
		||||
        await page.locator('.field.control.l-input-sm input').first().press('ArrowUp');
 | 
			
		||||
        await page.locator('.field.control.l-input-sm input').first().press('ArrowUp');
 | 
			
		||||
 | 
			
		||||
        const value = await page.locator('.field.control.l-input-sm input').first().inputValue();
 | 
			
		||||
        await expect(value).toBe('6');
 | 
			
		||||
 | 
			
		||||
        // Click .c-form-row__state-indicator.grows
 | 
			
		||||
        await page.locator('.c-form-row__state-indicator.grows').click();
 | 
			
		||||
 | 
			
		||||
        // Click text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]
 | 
			
		||||
        await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').click();
 | 
			
		||||
 | 
			
		||||
        // Click .c-form-row__state-indicator >> nth=0
 | 
			
		||||
        await page.locator('.c-form-row__state-indicator').first().click();
 | 
			
		||||
 | 
			
		||||
        // Fill text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]
 | 
			
		||||
        await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill('New Sine Wave Generator');
 | 
			
		||||
 | 
			
		||||
        // Double click div:nth-child(4) .form-row .c-form-row__controls
 | 
			
		||||
        await page.locator('div:nth-child(4) .form-row .c-form-row__controls').dblclick();
 | 
			
		||||
 | 
			
		||||
        // Click .field.control.l-input-sm input >> nth=0
 | 
			
		||||
        await page.locator('.field.control.l-input-sm input').first().click();
 | 
			
		||||
 | 
			
		||||
        // Click div:nth-child(4) .form-row .c-form-row__state-indicator
 | 
			
		||||
        await page.locator('div:nth-child(4) .form-row .c-form-row__state-indicator').click();
 | 
			
		||||
 | 
			
		||||
        // Click .field.control.l-input-sm input >> nth=0
 | 
			
		||||
        await page.locator('.field.control.l-input-sm input').first().click();
 | 
			
		||||
 | 
			
		||||
        // Click .field.control.l-input-sm input >> nth=0
 | 
			
		||||
        await page.locator('.field.control.l-input-sm input').first().click();
 | 
			
		||||
 | 
			
		||||
        // Click div:nth-child(5) .form-row .c-form-row__controls .form-control .field input
 | 
			
		||||
        await page.locator('div:nth-child(5) .form-row .c-form-row__controls .form-control .field input').click();
 | 
			
		||||
 | 
			
		||||
        // Click div:nth-child(5) .form-row .c-form-row__controls .form-control .field input
 | 
			
		||||
        await page.locator('div:nth-child(5) .form-row .c-form-row__controls .form-control .field input').click();
 | 
			
		||||
 | 
			
		||||
        // Click div:nth-child(5) .form-row .c-form-row__controls .form-control .field input
 | 
			
		||||
        await page.locator('div:nth-child(5) .form-row .c-form-row__controls .form-control .field input').click();
 | 
			
		||||
 | 
			
		||||
        // Click div:nth-child(6) .form-row .c-form-row__controls .form-control .field input
 | 
			
		||||
        await page.locator('div:nth-child(6) .form-row .c-form-row__controls .form-control .field input').click();
 | 
			
		||||
 | 
			
		||||
        // Double click div:nth-child(7) .form-row .c-form-row__controls .form-control .field input
 | 
			
		||||
        await page.locator('div:nth-child(7) .form-row .c-form-row__controls .form-control .field input').dblclick();
 | 
			
		||||
 | 
			
		||||
        // Click div:nth-child(7) .form-row .c-form-row__state-indicator
 | 
			
		||||
        await page.locator('div:nth-child(7) .form-row .c-form-row__state-indicator').click();
 | 
			
		||||
 | 
			
		||||
        // Click div:nth-child(7) .form-row .c-form-row__controls .form-control .field input
 | 
			
		||||
        await page.locator('div:nth-child(7) .form-row .c-form-row__controls .form-control .field input').click();
 | 
			
		||||
 | 
			
		||||
        // Fill div:nth-child(7) .form-row .c-form-row__controls .form-control .field input
 | 
			
		||||
        await page.locator('div:nth-child(7) .form-row .c-form-row__controls .form-control .field input').fill('3');
 | 
			
		||||
 | 
			
		||||
        //Click text=OK
 | 
			
		||||
        await Promise.all([
 | 
			
		||||
            page.waitForNavigation(),
 | 
			
		||||
            page.click('text=OK')
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        // Verify that the Sine Wave Generator is displayed and correct
 | 
			
		||||
        // Verify object properties
 | 
			
		||||
        await expect(page.locator('.l-browse-bar__object-name')).toContainText('New Sine Wave Generator');
 | 
			
		||||
 | 
			
		||||
        // Verify canvas rendered
 | 
			
		||||
        await page.locator('canvas').nth(1).click({
 | 
			
		||||
            position: {
 | 
			
		||||
                x: 341,
 | 
			
		||||
                y: 28
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										69
									
								
								e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								e2e/tests/plugins/timeConductor/timeConductor.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 { test, expect } = require('@playwright/test');
 | 
			
		||||
 | 
			
		||||
test.describe('Time counductor operations', () => {
 | 
			
		||||
    test('validate start time does not exceeds end time', async ({ page }) => {
 | 
			
		||||
        //Go to baseURL
 | 
			
		||||
        await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
        const year = new Date().getFullYear();
 | 
			
		||||
 | 
			
		||||
        let startDate = 'xxxx-01-01 01:00:00.000Z';
 | 
			
		||||
        startDate = year + startDate.substring(4);
 | 
			
		||||
 | 
			
		||||
        let endDate = 'xxxx-01-01 02:00:00.000Z';
 | 
			
		||||
        endDate = year + endDate.substring(4);
 | 
			
		||||
 | 
			
		||||
        const startTimeLocator = page.locator('input[type="text"]').first();
 | 
			
		||||
        const endTimeLocator = page.locator('input[type="text"]').nth(1);
 | 
			
		||||
 | 
			
		||||
        // Click start time
 | 
			
		||||
        await startTimeLocator.click();
 | 
			
		||||
 | 
			
		||||
        // Click end time
 | 
			
		||||
        await endTimeLocator.click();
 | 
			
		||||
 | 
			
		||||
        await endTimeLocator.fill(endDate.toString());
 | 
			
		||||
        await startTimeLocator.fill(startDate.toString());
 | 
			
		||||
 | 
			
		||||
        // invalid start date
 | 
			
		||||
        startDate = (year + 1) + startDate.substring(4);
 | 
			
		||||
        await startTimeLocator.fill(startDate.toString());
 | 
			
		||||
        await endTimeLocator.click();
 | 
			
		||||
 | 
			
		||||
        const startDateValidityStatus = await startTimeLocator.evaluate((element) => element.checkValidity());
 | 
			
		||||
        expect(startDateValidityStatus).not.toBeTruthy();
 | 
			
		||||
 | 
			
		||||
        // fix to valid start date
 | 
			
		||||
        startDate = (year - 1) + startDate.substring(4);
 | 
			
		||||
        await startTimeLocator.fill(startDate.toString());
 | 
			
		||||
 | 
			
		||||
        // invalid end date
 | 
			
		||||
        endDate = (year - 2) + endDate.substring(4);
 | 
			
		||||
        await endTimeLocator.fill(endDate.toString());
 | 
			
		||||
        await startTimeLocator.click();
 | 
			
		||||
 | 
			
		||||
        const endDateValidityStatus = await endTimeLocator.evaluate((element) => element.checkValidity());
 | 
			
		||||
        expect(endDateValidityStatus).not.toBeTruthy();
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -111,3 +111,63 @@ test('Visual - Default Condition Widget', async ({ page }) => {
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'Default Condition Widget');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Visual - Time Conductor start time is less than end time', async ({ page }) => {
 | 
			
		||||
    //Go to baseURL
 | 
			
		||||
    await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
    const year = new Date().getFullYear();
 | 
			
		||||
 | 
			
		||||
    let startDate = 'xxxx-01-01 01:00:00.000Z';
 | 
			
		||||
    startDate = year + startDate.substring(4);
 | 
			
		||||
 | 
			
		||||
    let endDate = 'xxxx-01-01 02:00:00.000Z';
 | 
			
		||||
    endDate = year + endDate.substring(4);
 | 
			
		||||
 | 
			
		||||
    await page.locator('input[type="text"]').nth(1).fill(endDate.toString());
 | 
			
		||||
    await page.locator('input[type="text"]').first().fill(startDate.toString());
 | 
			
		||||
 | 
			
		||||
    //  verify no error msg
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'Default Time conductor');
 | 
			
		||||
 | 
			
		||||
    startDate = (year + 1) + startDate.substring(4);
 | 
			
		||||
    await page.locator('input[type="text"]').first().fill(startDate.toString());
 | 
			
		||||
    await page.locator('input[type="text"]').nth(1).click();
 | 
			
		||||
 | 
			
		||||
    //  verify error msg for start time (unable to capture snapshot of popup)
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'Start time error');
 | 
			
		||||
 | 
			
		||||
    startDate = (year - 1) + startDate.substring(4);
 | 
			
		||||
    await page.locator('input[type="text"]').first().fill(startDate.toString());
 | 
			
		||||
 | 
			
		||||
    endDate = (year - 2) + endDate.substring(4);
 | 
			
		||||
    await page.locator('input[type="text"]').nth(1).fill(endDate.toString());
 | 
			
		||||
 | 
			
		||||
    await page.locator('input[type="text"]').first().click();
 | 
			
		||||
 | 
			
		||||
    //  verify error msg for end time (unable to capture snapshot of popup)
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'End time error');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Visual - Sine Wave Generator Form', async ({ page }) => {
 | 
			
		||||
    //Go to baseURL
 | 
			
		||||
    await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
 | 
			
		||||
    //Click the Create button
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
 | 
			
		||||
    // Click text=Sine Wave Generator
 | 
			
		||||
    await page.click('text=Sine Wave Generator');
 | 
			
		||||
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'Default Sine Wave Generator Form');
 | 
			
		||||
 | 
			
		||||
    await page.locator('.field.control.l-input-sm input').first().click();
 | 
			
		||||
    await page.locator('.field.control.l-input-sm input').first().fill('');
 | 
			
		||||
 | 
			
		||||
    // Validate red x mark
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'removed amplitude property value');
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								package.json
									
									
									
									
									
								
							@@ -30,7 +30,7 @@
 | 
			
		||||
    "html-loader": "0.5.5",
 | 
			
		||||
    "html2canvas": "1.4.1",
 | 
			
		||||
    "imports-loader": "0.8.0",
 | 
			
		||||
    "istanbul-instrumenter-loader": "^3.0.1",
 | 
			
		||||
    "istanbul-instrumenter-loader": "3.0.1",
 | 
			
		||||
    "jasmine-core": "4.0.0",
 | 
			
		||||
    "jsdoc": "3.5.5",
 | 
			
		||||
    "karma": "6.3.15",
 | 
			
		||||
@@ -43,36 +43,36 @@
 | 
			
		||||
    "karma-junit-reporter": "2.0.1",
 | 
			
		||||
    "karma-sourcemap-loader": "0.3.8",
 | 
			
		||||
    "karma-spec-reporter": "0.0.33",
 | 
			
		||||
    "karma-webpack": "^5.0.0",
 | 
			
		||||
    "location-bar": "^3.0.1",
 | 
			
		||||
    "lodash": "^4.17.12",
 | 
			
		||||
    "karma-webpack": "5.0.0",
 | 
			
		||||
    "location-bar": "3.0.1",
 | 
			
		||||
    "lodash": "4.17.12",
 | 
			
		||||
    "mini-css-extract-plugin": "2.4.5",
 | 
			
		||||
    "moment": "2.29.1",
 | 
			
		||||
    "moment-duration-format": "^2.2.2",
 | 
			
		||||
    "moment-duration-format": "2.2.2",
 | 
			
		||||
    "moment-timezone": "0.5.28",
 | 
			
		||||
    "node-bourbon": "^4.2.3",
 | 
			
		||||
    "painterro": "^1.2.56",
 | 
			
		||||
    "plotly.js-basic-dist": "^2.5.0",
 | 
			
		||||
    "plotly.js-gl2d-dist": "^2.5.0",
 | 
			
		||||
    "printj": "^1.2.1",
 | 
			
		||||
    "raw-loader": "^0.5.1",
 | 
			
		||||
    "request": "^2.69.0",
 | 
			
		||||
    "node-bourbon": "4.2.3",
 | 
			
		||||
    "painterro": "1.2.56",
 | 
			
		||||
    "plotly.js-basic-dist": "2.5.0",
 | 
			
		||||
    "plotly.js-gl2d-dist": "2.5.0",
 | 
			
		||||
    "printj": "1.2.1",
 | 
			
		||||
    "raw-loader": "0.5.1",
 | 
			
		||||
    "request": "2.69.0",
 | 
			
		||||
    "resolve-url-loader": "4.0.0",
 | 
			
		||||
    "sass": "1.49.0",
 | 
			
		||||
    "sass-loader": "12.4.0",
 | 
			
		||||
    "sinon": "13.0.1",
 | 
			
		||||
    "style-loader": "^1.0.1",
 | 
			
		||||
    "uuid": "^3.3.3",
 | 
			
		||||
    "uuid": "3.3.3",
 | 
			
		||||
    "vue": "2.6.14",
 | 
			
		||||
    "vue-eslint-parser": "8.2.0",
 | 
			
		||||
    "vue-loader": "15.9.8",
 | 
			
		||||
    "vue-template-compiler": "2.6.14",
 | 
			
		||||
    "webpack": "5.68.0",
 | 
			
		||||
    "webpack-cli": "4.9.2",
 | 
			
		||||
    "webpack-dev-middleware": "^3.1.3",
 | 
			
		||||
    "webpack-hot-middleware": "^2.22.3",
 | 
			
		||||
    "webpack-dev-middleware": "3.7.3",
 | 
			
		||||
    "webpack-hot-middleware": "2.22.3",
 | 
			
		||||
    "webpack-merge": "5.8.0",
 | 
			
		||||
    "zepto": "^1.2.0"
 | 
			
		||||
    "zepto": "1.2.0"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "clean": "rm -rf ./dist ./node_modules; rm package-lock.json",
 | 
			
		||||
@@ -88,8 +88,8 @@
 | 
			
		||||
    "test:debug": "cross-env NODE_ENV=debug karma start --no-single-run",
 | 
			
		||||
    "test:coverage": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" COVERAGE=true karma start --single-run",
 | 
			
		||||
    "test:coverage:firefox": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run --browsers=FirefoxHeadless",
 | 
			
		||||
    "test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke default condition.e2e",
 | 
			
		||||
    "test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js",
 | 
			
		||||
    "test:e2e:ci": "npx playwright test --config=e2e/playwright-ci.config.js --project=chrome smoke default condition timeConductor",
 | 
			
		||||
    "test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js --project=chrome",
 | 
			
		||||
    "test:e2e:visual": "percy exec --config ./e2e/.percy.yml -- npx playwright test --config=e2e/playwright-visual.config.js default",
 | 
			
		||||
    "test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js",
 | 
			
		||||
    "test:watch": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --no-single-run",
 | 
			
		||||
 
 | 
			
		||||
@@ -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());
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -30,13 +30,15 @@
 | 
			
		||||
               :min="model.min"
 | 
			
		||||
               :max="model.max"
 | 
			
		||||
               :step="model.step"
 | 
			
		||||
               @blur="blur()"
 | 
			
		||||
               @input="updateText()"
 | 
			
		||||
        >
 | 
			
		||||
    </span>
 | 
			
		||||
</span>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    props: {
 | 
			
		||||
        model: {
 | 
			
		||||
@@ -49,8 +51,12 @@ export default {
 | 
			
		||||
            field: this.model.value
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.updateText = throttle(this.updateText.bind(this), 200);
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        blur() {
 | 
			
		||||
        updateText() {
 | 
			
		||||
            console.log('updateText', this.field);
 | 
			
		||||
            const data = {
 | 
			
		||||
                model: this.model,
 | 
			
		||||
                value: this.field
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
        <textarea v-model="field"
 | 
			
		||||
                  type="text"
 | 
			
		||||
                  :size="model.size"
 | 
			
		||||
                  @blur="blur()"
 | 
			
		||||
                  @input="updateText()"
 | 
			
		||||
        >
 | 
			
		||||
        </textarea>
 | 
			
		||||
    </span>
 | 
			
		||||
@@ -36,6 +36,8 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    props: {
 | 
			
		||||
        model: {
 | 
			
		||||
@@ -48,8 +50,11 @@ export default {
 | 
			
		||||
            field: this.model.value
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.updateText = throttle(this.updateText.bind(this), 500);
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        blur() {
 | 
			
		||||
        updateText() {
 | 
			
		||||
            const data = {
 | 
			
		||||
                model: this.model,
 | 
			
		||||
                value: this.field
 | 
			
		||||
 
 | 
			
		||||
@@ -28,13 +28,15 @@
 | 
			
		||||
        <input v-model="field"
 | 
			
		||||
               type="text"
 | 
			
		||||
               :size="model.size"
 | 
			
		||||
               @blur="blur()"
 | 
			
		||||
               @input="updateText()"
 | 
			
		||||
        >
 | 
			
		||||
    </span>
 | 
			
		||||
</span>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    props: {
 | 
			
		||||
        model: {
 | 
			
		||||
@@ -47,8 +49,11 @@ export default {
 | 
			
		||||
            field: this.model.value
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.updateText = throttle(this.updateText.bind(this), 500);
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        blur() {
 | 
			
		||||
        updateText() {
 | 
			
		||||
            const data = {
 | 
			
		||||
                model: this.model,
 | 
			
		||||
                value: this.field
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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'
 | 
			
		||||
@@ -97,6 +95,10 @@ export default class LinkAction {
 | 
			
		||||
            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();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
@@ -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,
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -106,6 +106,11 @@ export default class RemoveAction {
 | 
			
		||||
        let child = objectPath[0];
 | 
			
		||||
        let locked = child.locked ? child.locked : parent && parent.locked;
 | 
			
		||||
        let isEditing = this.openmct.editor.isEditing();
 | 
			
		||||
        let isPersistable = this.openmct.objects.isPersistable(child.identifier);
 | 
			
		||||
 | 
			
		||||
        if (locked || !isPersistable) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isEditing) {
 | 
			
		||||
            let currentItemInView = this.openmct.router.path[0];
 | 
			
		||||
@@ -116,10 +121,6 @@ export default class RemoveAction {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (locked) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return parentType
 | 
			
		||||
            && parentType.definition.creatable
 | 
			
		||||
            && Array.isArray(parent.composition);
 | 
			
		||||
 
 | 
			
		||||
@@ -253,6 +253,8 @@ export default {
 | 
			
		||||
                input.title = '';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.$refs.fixedDeltaInput.reportValidity();
 | 
			
		||||
 | 
			
		||||
            return validationResult.valid;
 | 
			
		||||
        },
 | 
			
		||||
        startDateSelected(date) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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