Compare commits
	
		
			8 Commits
		
	
	
		
			snaphot-im
			...
			coverage-f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					18137fe125 | ||
| 
						 | 
					464bb3b885 | ||
| 
						 | 
					4775c88909 | ||
| 
						 | 
					51a6ff7825 | ||
| 
						 | 
					f989733e81 | ||
| 
						 | 
					5a6162eb4c | ||
| 
						 | 
					b0a2f8dd8b | ||
| 
						 | 
					54bed23267 | 
							
								
								
									
										5
									
								
								.npmrc
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								.npmrc
									
									
									
									
									
								
							@@ -1 +1,6 @@
 | 
			
		||||
loglevel=warn
 | 
			
		||||
 | 
			
		||||
# Temporary: istanbul-instrumenter-loader is working with webpack 5, but states
 | 
			
		||||
# webpack 4 being the latest version it supports, so this legacy-peer-deps
 | 
			
		||||
# allows us to install it anyway.
 | 
			
		||||
legacy-peer-deps=true
 | 
			
		||||
							
								
								
									
										20
									
								
								app.js
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								app.js
									
									
									
									
									
								
							@@ -7,7 +7,6 @@
 | 
			
		||||
 * node app.js [options]
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const options = require('minimist')(process.argv.slice(2));
 | 
			
		||||
const express = require('express');
 | 
			
		||||
const app = express();
 | 
			
		||||
@@ -40,10 +39,19 @@ app.use('/proxyUrl', function proxyRequest(req, res, next) {
 | 
			
		||||
    }).on('error', next)).pipe(res);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
class WatchRunPlugin {
 | 
			
		||||
    apply(compiler) {
 | 
			
		||||
        compiler.hooks.emit.tapAsync('WatchRunPlugin', (compilation, callback) => {
 | 
			
		||||
            console.log('Begin compile at ' + new Date());
 | 
			
		||||
            callback();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const webpack = require('webpack');
 | 
			
		||||
const webpackConfig = require('./webpack.config.js');
 | 
			
		||||
const webpackConfig = require('./webpack.dev.js');
 | 
			
		||||
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
 | 
			
		||||
webpackConfig.plugins.push(function() { this.plugin('watch-run', function(watching, callback) { console.log('Begin compile at ' + new Date()); callback(); }) });
 | 
			
		||||
webpackConfig.plugins.push(new WatchRunPlugin());
 | 
			
		||||
 | 
			
		||||
webpackConfig.entry.openmct = [
 | 
			
		||||
    'webpack-hot-middleware/client?reload=true',
 | 
			
		||||
@@ -62,9 +70,7 @@ app.use(require('webpack-dev-middleware')(
 | 
			
		||||
 | 
			
		||||
app.use(require('webpack-hot-middleware')(
 | 
			
		||||
    compiler,
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    {}
 | 
			
		||||
));
 | 
			
		||||
 | 
			
		||||
// Expose index.html for development users.
 | 
			
		||||
@@ -74,5 +80,5 @@ app.get('/', function (req, res) {
 | 
			
		||||
 | 
			
		||||
// Finally, open the HTTP server and log the instance to the console
 | 
			
		||||
app.listen(options.port, options.host, function() {
 | 
			
		||||
    console.log('Open MCT application running at %s:%s', options.host, options.port)
 | 
			
		||||
    console.log('Open MCT application running at %s:%s', options.host, options.port);
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								e2e/localstorage.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								e2e/localstorage.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
{"tcHistory":"{\"utc\":[{\"start\":1640401741152,\"end\":1640403541152}]}","mct":"{\"mine\":{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"fbb74cd3-bc17-4913-a47b-6ec7b620c26d\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"persisted\":1640403542253,\"modified\":1640403542253},\"fbb74cd3-bc17-4913-a47b-6ec7b620c26d\":{\"identifier\":{\"key\":\"fbb74cd3-bc17-4913-a47b-6ec7b620c26d\",\"namespace\":\"\"},\"name\":\"All DomainObjects\",\"type\":\"folder\",\"composition\":[{\"key\":\"cbee96e6-ec97-4059-a5bb-5a81b834ff3d\",\"namespace\":\"\"},{\"key\":\"15631105-127c-44a0-8d54-e3800943a98b\",\"namespace\":\"\"},{\"key\":\"31c2c6e1-55bd-4339-86f9-8cb1693566d0\",\"namespace\":\"\"}],\"modified\":1640403603547,\"location\":\"mine\",\"persisted\":1640403603547},\"cbee96e6-ec97-4059-a5bb-5a81b834ff3d\":{\"identifier\":{\"key\":\"cbee96e6-ec97-4059-a5bb-5a81b834ff3d\",\"namespace\":\"\"},\"name\":\"Unnamed Timer\",\"type\":\"timer\",\"configuration\":{\"timerFormat\":\"long\",\"timezone\":\"UTC\",\"timerState\":\"stopped\"},\"modified\":1640403543115,\"location\":\"fbb74cd3-bc17-4913-a47b-6ec7b620c26d\",\"persisted\":1640403543115},\"15631105-127c-44a0-8d54-e3800943a98b\":{\"identifier\":{\"key\":\"15631105-127c-44a0-8d54-e3800943a98b\",\"namespace\":\"\"},\"name\":\"Notebook\",\"type\":\"notebook\",\"configuration\":{\"defaultSort\":\"oldest\",\"entries\":{},\"imageMigrationVer\":\"v1\",\"pageTitle\":\"Page\",\"sections\":[{\"id\":\"ef4092ba-b6d1-4275-a659-bfae80b6ec9a\",\"isDefault\":false,\"isSelected\":true,\"name\":\"Unnamed Section\",\"pages\":[{\"id\":\"b187e90c-4759-47d5-af16-4a347520c0a6\",\"isDefault\":false,\"isSelected\":true,\"name\":\"Unnamed Page\",\"pageTitle\":\"Page\"}],\"sectionTitle\":\"Section\"}],\"sectionTitle\":\"Section\",\"type\":\"General\"},\"modified\":1640403544367,\"location\":\"fbb74cd3-bc17-4913-a47b-6ec7b620c26d\",\"persisted\":1640403544368},\"31c2c6e1-55bd-4339-86f9-8cb1693566d0\":{\"name\":\"Mega Display Layout\",\"type\":\"layout\",\"identifier\":{\"key\":\"31c2c6e1-55bd-4339-86f9-8cb1693566d0\",\"namespace\":\"\"},\"composition\":[],\"configuration\":{\"items\":[],\"layoutGrid\":[10,10]},\"modified\":1640403603545,\"location\":\"fbb74cd3-bc17-4913-a47b-6ec7b620c26d\",\"persisted\":1640403603545}}","mct-tree-expanded":"[]"}
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
 | 
			
		||||
const config = {
 | 
			
		||||
    retries: 0,
 | 
			
		||||
    testDir: 'tests',
 | 
			
		||||
    testDir: 'tests/visual',
 | 
			
		||||
    timeout: 90 * 1000,
 | 
			
		||||
    workers: 1,
 | 
			
		||||
    webServer: {
 | 
			
		||||
@@ -26,7 +26,6 @@ const config = {
 | 
			
		||||
    reporter: [
 | 
			
		||||
        ['list'],
 | 
			
		||||
        ['junit', { outputFile: 'test-results/results.xml' }],
 | 
			
		||||
        ['allure-playwright']
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										122
									
								
								e2e/tests/generateLocalStorage.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								e2e/tests/generateLocalStorage.e2e.spec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2021, 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 used for generating localStorage artifacts for visual and performance
 | 
			
		||||
tests. This must be generated against app.js
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const { test, expect } = require('@playwright/test');
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
 | 
			
		||||
test('Generate domainObjects and store localstorage as localstorage.json', async ({ page }) => {
 | 
			
		||||
 | 
			
		||||
    //Go to baseURL
 | 
			
		||||
    await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
 | 
			
		||||
    //Click the Create button
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
 | 
			
		||||
    // Click :nth-match(:text("Folder"), 2)
 | 
			
		||||
    await page.click(':nth-match(:text("Folder"), 2)');
 | 
			
		||||
 | 
			
		||||
    // Fill text=Properties Title Notes >> input[type="text"]
 | 
			
		||||
    await page.fill('text=Properties Title Notes >> input[type="text"]', 'All DomainObjects');
 | 
			
		||||
    //await page.fill('input[type="text"]', 'All DomainObjects');
 | 
			
		||||
 | 
			
		||||
    // Click text=OK
 | 
			
		||||
    await Promise.all([
 | 
			
		||||
        page.waitForNavigation(/*{ url: 'http://localhost:8080/#/browse/mine/07fa1bd8-1e7d-4b74-bc40-f561f8c00535?tc.mode=fixed&tc.startBound=1640392618958&tc.endBound=1640394418958&tc.timeSystem=utc&view=grid' }*/),
 | 
			
		||||
        page.click('text=OK')
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Click button:has-text("Create")
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
 | 
			
		||||
    // Click text=Timer
 | 
			
		||||
    await page.click('text=Timer');
 | 
			
		||||
 | 
			
		||||
    // Click text=Save In My Items All DomainObjects >> input[type="search"]
 | 
			
		||||
    await page.click('text=Save In My Items All DomainObjects >> input[type="search"]');
 | 
			
		||||
 | 
			
		||||
    // Fill text=Save In My Items All DomainObjects >> input[type="search"]
 | 
			
		||||
    await page.fill('text=Save In My Items All DomainObjects >> input[type="search"]', 'All DomainObjects');
 | 
			
		||||
 | 
			
		||||
    // Click text=OK
 | 
			
		||||
    await Promise.all([
 | 
			
		||||
        page.waitForNavigation(/*{ url: 'http://localhost:8080/#/browse/mine/07fa1bd8-1e7d-4b74-bc40-f561f8c00535/810cc308-76d6-4e64-ab85-cb543c655698?tc.mode=fixed&tc.startBound=1640392618958&tc.endBound=1640394418958&tc.timeSystem=utc&view=timer.view' }*/),
 | 
			
		||||
        page.click('text=OK')
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Click button:has-text("Create")
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
 | 
			
		||||
    // Click text=Notebook
 | 
			
		||||
    await page.click('text=Notebook');
 | 
			
		||||
 | 
			
		||||
    // Fill text=Properties Title Notes Entry Sorting Newest First Oldest First Note book Type Se >> input[type="text"]
 | 
			
		||||
    await page.fill('text=Properties Title Notes Entry Sorting Newest First Oldest First Note book Type Se >> input[type="text"]', 'Notebook');
 | 
			
		||||
 | 
			
		||||
    // Click text=Save In My Items All DomainObjects Unnamed Timer >> input[type="search"]
 | 
			
		||||
    //await page.click('text=Save In My Items All DomainObjects Unnamed Timer >> input[type="search"]');
 | 
			
		||||
 | 
			
		||||
    // Fill text=Save In My Items All DomainObjects Unnamed Timer >> input[type="search"]
 | 
			
		||||
    await page.fill('text=Save In My Items All DomainObjects Unnamed Timer >> input[type="search"]', 'All DomainObjects');
 | 
			
		||||
 | 
			
		||||
    // Click ul:nth-child(3) .c-tree__item-h .c-tree__item
 | 
			
		||||
    await page.click('ul:nth-child(3) .c-tree__item-h .c-tree__item');
 | 
			
		||||
 | 
			
		||||
    // Click button:has-text("OK")
 | 
			
		||||
    await Promise.all([
 | 
			
		||||
        page.waitForNavigation(/*{ url: 'http://localhost:8080/#/browse/ROOT/mine/07fa1bd8-1e7d-4b74-bc40-f561f8c00535/6b10425e-2d7f-4f65-83de-35317fbc2493?tc.mode=fixed&tc.startBound=1640392618958&tc.endBound=1640394418958&tc.timeSystem=utc&view=notebook-vue&pageId=9ad5b4ea-8dec-4cc0-b303-43a4f50ac7fa§ionId=d298175b-d715-426e-8036-b87056e14525' }*/),
 | 
			
		||||
        page.click('button:has-text("OK")')
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    await page.pause();
 | 
			
		||||
 | 
			
		||||
    const localStorage = await page.evaluate(() => JSON.stringify(window.localStorage));
 | 
			
		||||
    fs.writeFileSync('e2e/localstorage.json', localStorage);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Load localstorage.json and verify contents', async ({ page }) => {
 | 
			
		||||
 | 
			
		||||
    //Go to baseURL
 | 
			
		||||
    await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
 | 
			
		||||
    const localStorage = fs.readFileSync('e2e/localstorage.json', 'utf8')
 | 
			
		||||
 | 
			
		||||
    const deserializedStorage = JSON.parse(localStorage)
 | 
			
		||||
    await page.evaluate(deserializedStorage => {
 | 
			
		||||
        for (const key in deserializedStorage) {
 | 
			
		||||
            localStorage.setItem(key, deserializedStorage[key]);
 | 
			
		||||
        }
 | 
			
		||||
    }, deserializedStorage);
 | 
			
		||||
 | 
			
		||||
    await page.reload();
 | 
			
		||||
    
 | 
			
		||||
    // Expand Default Folder
 | 
			
		||||
    await page.click('a:has-text("All DomainObjects Folder")');
 | 
			
		||||
 | 
			
		||||
    await expect(page.locator('a:has-text("Unnamed Timer Timer")')).toBeEnabled();
 | 
			
		||||
    await expect(page.locator('a:has-text("Notebook Notebook")')).toBeEnabled();
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
@@ -44,6 +44,5 @@ test('Verify that the create button appears and that the Folder Domain Object is
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
 | 
			
		||||
    // Verify that Create Folder appears in the dropdown
 | 
			
		||||
    const locator = page.locator(':nth-match(:text("Folder"), 2)');
 | 
			
		||||
    await expect(locator).toBeEnabled();
 | 
			
		||||
    await expect(page.locator(':nth-match(:text("Folder"), 2)')).toBeEnabled();
 | 
			
		||||
});
 | 
			
		||||
@@ -36,12 +36,13 @@ const { test, expect } = require('@playwright/test');
 | 
			
		||||
const percySnapshot = require('@percy/playwright');
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const sinon = require('sinon');
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
 | 
			
		||||
const VISUAL_GRACE_PERIOD = 5 * 1000; //Lets the application "simmer" before the snapshot is taken
 | 
			
		||||
const VISUAL_GRACE_PERIOD = 1 * 1000; //Lets the application "simmer" before the snapshot is taken
 | 
			
		||||
 | 
			
		||||
// Snippet from https://github.com/microsoft/playwright/issues/6347#issuecomment-965887758
 | 
			
		||||
// Will replace with cy.clock() equivalent
 | 
			
		||||
test.beforeEach(async ({ context }) => {
 | 
			
		||||
test.beforeEach(async ({ context,page }) => {
 | 
			
		||||
    await context.addInitScript({
 | 
			
		||||
        // eslint-disable-next-line no-undef
 | 
			
		||||
        path: path.join(__dirname, '../../..', './node_modules/sinon/pkg/sinon.js')
 | 
			
		||||
@@ -49,11 +50,10 @@ test.beforeEach(async ({ context }) => {
 | 
			
		||||
    await context.addInitScript(() => {
 | 
			
		||||
        window.__clock = sinon.useFakeTimers(); //Set browser clock to UNIX Epoch
 | 
			
		||||
    });
 | 
			
		||||
    await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Visual - Root and About', async ({ page }) => {
 | 
			
		||||
    // Go to baseURL
 | 
			
		||||
    await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
 | 
			
		||||
    // Verify that Create button is actionable
 | 
			
		||||
    const createButtonLocator = page.locator('button:has-text("Create")');
 | 
			
		||||
@@ -77,8 +77,6 @@ test('Visual - Root and About', async ({ page }) => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Visual - Default Condition Set', async ({ page }) => {
 | 
			
		||||
    //Go to baseURL
 | 
			
		||||
    await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
 | 
			
		||||
    //Click the Create button
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
@@ -95,8 +93,6 @@ test('Visual - Default Condition Set', async ({ page }) => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Visual - Default Condition Widget', async ({ page }) => {
 | 
			
		||||
    //Go to baseURL
 | 
			
		||||
    await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
 | 
			
		||||
    //Click the Create button
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
@@ -111,3 +107,35 @@ test('Visual - Default Condition Widget', async ({ page }) => {
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'Default Condition Widget');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Visual - Default Timer', async ({ page }) => {
 | 
			
		||||
 | 
			
		||||
    //Click the Create button
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
 | 
			
		||||
    // Click text=Timer
 | 
			
		||||
    await page.click('text=Timer');
 | 
			
		||||
 | 
			
		||||
    // Click text=OK
 | 
			
		||||
    await page.click('text=OK');
 | 
			
		||||
 | 
			
		||||
    // Take a snapshot of the newly created Condition Widget object
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'Default Timer');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Visual - Default Display Layout', async ({ page }) => {
 | 
			
		||||
 | 
			
		||||
    //Click the Create button
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
 | 
			
		||||
    // Click text=Timer
 | 
			
		||||
    await page.click('text=Display Layout');
 | 
			
		||||
 | 
			
		||||
    // Click text=OK
 | 
			
		||||
    await page.click('text=OK');
 | 
			
		||||
 | 
			
		||||
    // Take a snapshot of the newly created Condition Widget object
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'Default Display Layout');
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										82
									
								
								e2e/tests/visual/localStorage.visual.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								e2e/tests/visual/localStorage.visual.spec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2021, 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Collection of Visual Tests set to run from a pre-generated . The tests within this suite
 | 
			
		||||
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 
 | 
			
		||||
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. 
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const { test, expect } = require('@playwright/test');
 | 
			
		||||
const percySnapshot = require('@percy/playwright');
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const sinon = require('sinon');
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
 | 
			
		||||
const VISUAL_GRACE_PERIOD = 1 * 1000; //Lets the application "simmer" before the snapshot is taken
 | 
			
		||||
 | 
			
		||||
// Snippet from https://github.com/microsoft/playwright/issues/6347#issuecomment-965887758
 | 
			
		||||
// Will replace with cy.clock() equivalent
 | 
			
		||||
test.beforeEach(async ({ context,page }) => {
 | 
			
		||||
    await context.addInitScript({
 | 
			
		||||
        // eslint-disable-next-line no-undef
 | 
			
		||||
        path: path.join(__dirname, '../../..', './node_modules/sinon/pkg/sinon.js')
 | 
			
		||||
    });
 | 
			
		||||
    await context.addInitScript(() => {
 | 
			
		||||
        window.__clock = sinon.useFakeTimers(); //Set browser clock to UNIX Epoch
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    await page.goto('/', { waitUntil: 'networkidle' });
 | 
			
		||||
 | 
			
		||||
    const localStorage = fs.readFileSync('e2e/localstorage.json', 'utf8')
 | 
			
		||||
 | 
			
		||||
    const deserializedStorage = JSON.parse(localStorage)
 | 
			
		||||
    await page.evaluate(deserializedStorage => {
 | 
			
		||||
        for (const key in deserializedStorage) {
 | 
			
		||||
            localStorage.setItem(key, deserializedStorage[key]);
 | 
			
		||||
        }
 | 
			
		||||
    }, deserializedStorage);
 | 
			
		||||
 | 
			
		||||
    await page.reload();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Visual - Combined Display Layout', async ({ page }) => {
 | 
			
		||||
 | 
			
		||||
    //Click the Create button
 | 
			
		||||
    await page.click('button:has-text("Create")');
 | 
			
		||||
 | 
			
		||||
    // Click text=Timer
 | 
			
		||||
    await page.click('text=Display Layout');
 | 
			
		||||
 | 
			
		||||
    // Click text=OK
 | 
			
		||||
    await page.click('text=OK');
 | 
			
		||||
 | 
			
		||||
    // Take a snapshot of the newly created Condition Widget object
 | 
			
		||||
    await page.waitForTimeout(VISUAL_GRACE_PERIOD);
 | 
			
		||||
    await percySnapshot(page, 'Default Display Layout');
 | 
			
		||||
});
 | 
			
		||||
@@ -22,7 +22,6 @@
 | 
			
		||||
 | 
			
		||||
/*global module,process*/
 | 
			
		||||
 | 
			
		||||
const devMode = process.env.NODE_ENV !== 'production';
 | 
			
		||||
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless'];
 | 
			
		||||
const coverageEnabled = process.env.COVERAGE === 'true';
 | 
			
		||||
const reporters = ['spec', 'junit'];
 | 
			
		||||
@@ -32,10 +31,10 @@ if (coverageEnabled) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = (config) => {
 | 
			
		||||
    const webpackConfig = require('./webpack.config.js');
 | 
			
		||||
    const webpackConfig = require('./webpack.dev.js');
 | 
			
		||||
    delete webpackConfig.output;
 | 
			
		||||
 | 
			
		||||
    if (!devMode || coverageEnabled) {
 | 
			
		||||
    if (coverageEnabled) {
 | 
			
		||||
        webpackConfig.module.rules.push({
 | 
			
		||||
            test: /\.js$/,
 | 
			
		||||
            exclude: /node_modules|example|lib|dist/,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								package.json
									
									
									
									
									
								
							@@ -6,16 +6,16 @@
 | 
			
		||||
    "@braintree/sanitize-url": "^5.0.2",
 | 
			
		||||
    "@percy/cli": "^1.0.0-beta.70",
 | 
			
		||||
    "@percy/playwright": "^1.0.1",
 | 
			
		||||
    "@playwright/test": "^1.16.3",
 | 
			
		||||
    "@playwright/test": "^1.17.1",
 | 
			
		||||
    "allure-playwright": "^2.0.0-beta.14",
 | 
			
		||||
    "angular": ">=1.8.0",
 | 
			
		||||
    "angular-route": "1.4.14",
 | 
			
		||||
    "babel-eslint": "10.1.0",
 | 
			
		||||
    "comma-separated-values": "^3.6.4",
 | 
			
		||||
    "concurrently": "^3.6.1",
 | 
			
		||||
    "copy-webpack-plugin": "^4.5.2",
 | 
			
		||||
    "copy-webpack-plugin": "^9.0.0",
 | 
			
		||||
    "cross-env": "^6.0.3",
 | 
			
		||||
    "css-loader": "^1.0.0",
 | 
			
		||||
    "css-loader": "^4.0.0",
 | 
			
		||||
    "d3-axis": "1.0.x",
 | 
			
		||||
    "d3-scale": "1.0.x",
 | 
			
		||||
    "d3-selection": "1.3.x",
 | 
			
		||||
@@ -26,8 +26,7 @@
 | 
			
		||||
    "eventemitter3": "^1.2.0",
 | 
			
		||||
    "exports-loader": "^0.7.0",
 | 
			
		||||
    "express": "^4.13.1",
 | 
			
		||||
    "fast-sass-loader": "1.4.6",
 | 
			
		||||
    "file-loader": "^1.1.11",
 | 
			
		||||
    "file-loader": "^6.1.0",
 | 
			
		||||
    "file-saver": "^1.3.8",
 | 
			
		||||
    "git-rev-sync": "^1.4.0",
 | 
			
		||||
    "glob": ">= 3.0.0",
 | 
			
		||||
@@ -47,25 +46,27 @@
 | 
			
		||||
    "karma-junit-reporter": "2.0.1",
 | 
			
		||||
    "karma-sourcemap-loader": "0.3.8",
 | 
			
		||||
    "karma-spec-reporter": "0.0.32",
 | 
			
		||||
    "karma-webpack": "4.0.2",
 | 
			
		||||
    "karma-webpack": "^5.0.0",
 | 
			
		||||
    "location-bar": "^3.0.1",
 | 
			
		||||
    "lodash": "^4.17.12",
 | 
			
		||||
    "markdown-toc": "^0.11.7",
 | 
			
		||||
    "marked": "^0.3.5",
 | 
			
		||||
    "mini-css-extract-plugin": "^0.4.1",
 | 
			
		||||
    "mini-css-extract-plugin": "^1.6.0",
 | 
			
		||||
    "minimist": "^1.2.5",
 | 
			
		||||
    "moment": "2.25.3",
 | 
			
		||||
    "moment-duration-format": "^2.2.2",
 | 
			
		||||
    "moment-timezone": "0.5.28",
 | 
			
		||||
    "node-bourbon": "^4.2.3",
 | 
			
		||||
    "node-sass": "^4.14.1",
 | 
			
		||||
    "painterro": "^1.2.56",
 | 
			
		||||
    "playwright": "^1.16.3",
 | 
			
		||||
    "playwright": "^1.17.1",
 | 
			
		||||
    "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.42.1",
 | 
			
		||||
    "sass-loader": "^12.1.0",
 | 
			
		||||
    "sinon": "^12.0.1",
 | 
			
		||||
    "split": "^1.0.0",
 | 
			
		||||
    "style-loader": "^1.0.1",
 | 
			
		||||
@@ -75,10 +76,11 @@
 | 
			
		||||
    "vue-eslint-parser": "8.0.1",
 | 
			
		||||
    "vue-loader": "^15.2.6",
 | 
			
		||||
    "vue-template-compiler": "2.5.6",
 | 
			
		||||
    "webpack": "^4.16.2",
 | 
			
		||||
    "webpack-cli": "^3.1.0",
 | 
			
		||||
    "webpack": "^5.53.0",
 | 
			
		||||
    "webpack-cli": "^4.0.0",
 | 
			
		||||
    "webpack-dev-middleware": "^3.1.3",
 | 
			
		||||
    "webpack-hot-middleware": "^2.22.3",
 | 
			
		||||
    "webpack-merge": "^5.8.0",
 | 
			
		||||
    "zepto": "^1.2.0"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
@@ -87,16 +89,17 @@
 | 
			
		||||
    "start": "node app.js",
 | 
			
		||||
    "lint": "eslint platform example src --ext .js,.vue openmct.js",
 | 
			
		||||
    "lint:fix": "eslint platform example src --ext .js,.vue openmct.js --fix",
 | 
			
		||||
    "build:prod": "cross-env NODE_ENV=production webpack",
 | 
			
		||||
    "build:dev": "webpack",
 | 
			
		||||
    "build:watch": "webpack --watch",
 | 
			
		||||
    "build:prod": "cross-env webpack --config webpack.prod.js",
 | 
			
		||||
    "build:dev": "webpack --config webpack.dev.js",
 | 
			
		||||
    "build:watch": "webpack --config webpack.dev.js --watch",
 | 
			
		||||
    "test": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" karma start --single-run",
 | 
			
		||||
    "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 smoke",
 | 
			
		||||
    "test:e2e:generate": "npx playwright test --config=e2e/playwright-local.config.js generateLocalStorage",
 | 
			
		||||
    "test:e2e:local": "npx playwright test --config=e2e/playwright-local.config.js",
 | 
			
		||||
    "test:e2e:visual": "percy exec -- npx playwright test --config=e2e/playwright-visual.config.js default",
 | 
			
		||||
    "test:e2e:visual": "percy exec -- npx playwright test --config=e2e/playwright-visual.config.js",
 | 
			
		||||
    "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",
 | 
			
		||||
    "verify": "concurrently 'npm:test' 'npm:lint'",
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,6 @@
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    'EventEmitter',
 | 
			
		||||
    'uuid',
 | 
			
		||||
    './BundleRegistry',
 | 
			
		||||
    './installDefaultBundles',
 | 
			
		||||
    './api/api',
 | 
			
		||||
@@ -53,7 +52,6 @@ define([
 | 
			
		||||
    'vue'
 | 
			
		||||
], function (
 | 
			
		||||
    EventEmitter,
 | 
			
		||||
    uuid,
 | 
			
		||||
    BundleRegistry,
 | 
			
		||||
    installDefaultBundles,
 | 
			
		||||
    api,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
/******************* FRAME */
 | 
			
		||||
.c-frame {
 | 
			
		||||
    display: flex;
 | 
			
		||||
@@ -89,7 +91,7 @@
 | 
			
		||||
                        &:before {
 | 
			
		||||
                            // Grippy
 | 
			
		||||
                            $h: 4px;
 | 
			
		||||
                            $tbOffset: ($editFrameMovebarH - $h) / 2;
 | 
			
		||||
                            $tbOffset: math.div($editFrameMovebarH - $h, 2);
 | 
			
		||||
                            $lrOffset: 25%;
 | 
			
		||||
                            @include grippy($editFrameMovebarColorFg);
 | 
			
		||||
                            content: '';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
@mixin containerGrippy($headerSize, $dir) {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    $h: 6px;
 | 
			
		||||
    $minorOffset: ($headerSize - $h) / 2;
 | 
			
		||||
    $minorOffset: math.div($headerSize - $h, 2);
 | 
			
		||||
    $majorOffset: 35%;
 | 
			
		||||
    content: '';
 | 
			
		||||
    display: block;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
/******************************* GRID VIEW */
 | 
			
		||||
.l-grid-view {
 | 
			
		||||
    display: flex;
 | 
			
		||||
@@ -42,7 +44,7 @@
 | 
			
		||||
    &__type-icon {
 | 
			
		||||
        filter: $colorKeyFilter;
 | 
			
		||||
        flex: 0 0 $gridItemMobile;
 | 
			
		||||
        font-size: floor($gridItemMobile / 2);
 | 
			
		||||
        font-size: floor(math.div($gridItemMobile, 2));
 | 
			
		||||
        margin-right: $interiorMarginLg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -166,7 +168,7 @@
 | 
			
		||||
 | 
			
		||||
        &__type-icon {
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            font-size: floor($gridItemDesk / 3);
 | 
			
		||||
            font-size: floor(math.div($gridItemDesk, 3));
 | 
			
		||||
            margin: $interiorMargin 22.5% $interiorMargin * 3 22.5%;
 | 
			
		||||
            order: 2;
 | 
			
		||||
            transform-origin: center;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
.c-conductor-axis {
 | 
			
		||||
    $h: 18px;
 | 
			
		||||
    $tickYPos: ($h / 2) + 12px;
 | 
			
		||||
    $tickYPos: math.div($h, 2) + 12px;
 | 
			
		||||
 | 
			
		||||
    @include userSelectNone();
 | 
			
		||||
    @include bgTicks($c: rgba($colorBodyFg, 0.4));
 | 
			
		||||
 
 | 
			
		||||
@@ -21,14 +21,15 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/* REQUIRES /platform/commonUI/general/res/sass/_constants.scss */
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
/************************** MOBILE REPRESENTATION ITEMS DIMENSIONS */
 | 
			
		||||
$mobileListIconSize: 30px;
 | 
			
		||||
$mobileTitleDescH: 35px;
 | 
			
		||||
$mobileOverlayMargin: 20px;
 | 
			
		||||
$mobileMenuIconD: 25px;
 | 
			
		||||
$phoneItemH: floor($gridItemMobile / 4);
 | 
			
		||||
$tabletItemH: floor($gridItemMobile / 3);
 | 
			
		||||
$phoneItemH: floor(math.div($gridItemMobile, 4));
 | 
			
		||||
$tabletItemH: floor(math.div($gridItemMobile, 3));
 | 
			
		||||
 | 
			
		||||
/************************** MOBILE TREE MENU DIMENSIONS */
 | 
			
		||||
$mobileTreeItemH: 35px;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,8 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
/******************************************************** BUTTONS */
 | 
			
		||||
// Optionally can include icon in :before via markup
 | 
			
		||||
button {
 | 
			
		||||
@@ -785,7 +787,7 @@ select {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &--swatched {
 | 
			
		||||
            padding-bottom: floor($pTB / 2);
 | 
			
		||||
            padding-bottom: floor(math.div($pTB, 2));
 | 
			
		||||
            width: 2em; // Standardize the width
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -935,7 +937,7 @@ select {
 | 
			
		||||
 | 
			
		||||
@mixin sliderTrack($bg: $scrollbarTrackColorBg, $knobH: 12px, $trackH: 3px) {
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    $breakPointPx: floor(($knobH - $trackH) / 2);
 | 
			
		||||
    $breakPointPx: floor(math.div($knobH - $trackH, 2));
 | 
			
		||||
    $bp1: $breakPointPx;
 | 
			
		||||
    $bp2: $breakPointPx + $trackH;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,9 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
/******************************************************** RESETS */
 | 
			
		||||
*,
 | 
			
		||||
:before,
 | 
			
		||||
@@ -308,7 +311,7 @@ body.desktop .has-local-controls {
 | 
			
		||||
    }
 | 
			
		||||
    &.c-tree__item {
 | 
			
		||||
        $d: $waitSpinnerTreeD;
 | 
			
		||||
        $spinnerL: 19 + $d/2;
 | 
			
		||||
        $spinnerL: 19 + math.div($d, 2);
 | 
			
		||||
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,9 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
/******************************************************************* MESSAGES */
 | 
			
		||||
.w-message-contents {
 | 
			
		||||
    flex: 1 1 auto;
 | 
			
		||||
@@ -120,7 +123,7 @@ body.desktop .t-message-list {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Alert elements in views
 | 
			
		||||
mixin sUnSynced() {
 | 
			
		||||
@mixin sUnSynced {
 | 
			
		||||
    $c: $colorPausedBg;
 | 
			
		||||
    border: 1px solid $c;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,9 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
/*********************************************************************** CLOCKS AND TIMERS */
 | 
			
		||||
.c-clock,
 | 
			
		||||
.c-timer {
 | 
			
		||||
@@ -788,7 +791,7 @@ body.desktop {
 | 
			
		||||
                //width: $splitterHandleD;
 | 
			
		||||
            }
 | 
			
		||||
            &.flush-right {
 | 
			
		||||
                width: ceil($splitterHandleD / 2);
 | 
			
		||||
                width: ceil(math.div($splitterHandleD, 2));
 | 
			
		||||
                &:after {
 | 
			
		||||
                    width: $splitterHandleD;
 | 
			
		||||
                    left: auto; right: 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,8 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
/************************** GLYPHS */
 | 
			
		||||
@mixin glyphBefore($unicode, $family: 'symbolsfont') {
 | 
			
		||||
    &:before {
 | 
			
		||||
@@ -202,7 +204,7 @@
 | 
			
		||||
 | 
			
		||||
@mixin bgCheckerboard($c: $colorBodyFg, $opacity: 0.3, $size: 32px, $imp: false) {
 | 
			
		||||
    $color: rgba($c, $opacity);
 | 
			
		||||
    $bgPos: floor($size / 2);
 | 
			
		||||
    $bgPos: floor(math.div($size, 2));
 | 
			
		||||
 | 
			
		||||
    $impStr: null;
 | 
			
		||||
    @if $imp {
 | 
			
		||||
@@ -288,7 +290,7 @@
 | 
			
		||||
@mixin triangle($dir: "left", $size: 5px, $ratio: 1, $color: red) {
 | 
			
		||||
    width: 0;
 | 
			
		||||
    height: 0;
 | 
			
		||||
    $slopedB: $size/$ratio solid transparent;
 | 
			
		||||
    $slopedB: math.div($size, $ratio) solid transparent;
 | 
			
		||||
    $straightB: $size solid $color;
 | 
			
		||||
    @if $dir == "up" {
 | 
			
		||||
        border-left: $slopedB;
 | 
			
		||||
@@ -780,7 +782,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@mixin sUnsynced() {
 | 
			
		||||
@mixin sUnsynced {
 | 
			
		||||
    $c: $colorPausedBg;
 | 
			
		||||
    border: 1px solid $c;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
.c-toggle-switch {
 | 
			
		||||
    $d: 12px;
 | 
			
		||||
    $m: 2px;
 | 
			
		||||
    $br: $d/1.5;
 | 
			
		||||
    $br: math.div($d, 1.5);
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    display: inline-flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
.c-tree-and-search {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
@@ -136,7 +138,7 @@
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        > * + * {
 | 
			
		||||
            margin-left: ceil($interiorMarginSm / 2);
 | 
			
		||||
            margin-left: ceil(math.div($interiorMarginSm, 2));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @include hover {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
@use 'sass:math';
 | 
			
		||||
 | 
			
		||||
/**************************** BASE - MOBILE AND DESKTOP */
 | 
			
		||||
.l-multipane {
 | 
			
		||||
    display: flex;
 | 
			
		||||
@@ -234,7 +236,7 @@
 | 
			
		||||
 | 
			
		||||
                > .l-pane__handle {
 | 
			
		||||
                    left: 0;
 | 
			
		||||
                    transform: translateX(floor($splitterHandleD / -2)); // Center over the pane edge
 | 
			
		||||
                    transform: translateX(floor(math.div($splitterHandleD, -2))); // Center over the pane edge
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                [class*="expand-button"] {
 | 
			
		||||
@@ -251,7 +253,7 @@
 | 
			
		||||
 | 
			
		||||
                > .l-pane__handle {
 | 
			
		||||
                    right: 0;
 | 
			
		||||
                    transform: translateX(floor($splitterHandleD / 2));
 | 
			
		||||
                    transform: translateX(floor(math.div($splitterHandleD, 2)));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                [class*="expand-button"] {
 | 
			
		||||
@@ -287,7 +289,7 @@
 | 
			
		||||
                padding-top: $m;
 | 
			
		||||
                > .l-pane__handle {
 | 
			
		||||
                    top: 0;
 | 
			
		||||
                    transform: translateY(floor($splitterHandleD / -1));
 | 
			
		||||
                    transform: translateY(floor(math.div($splitterHandleD, -1)));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                .l-pane__collapse-button:before {
 | 
			
		||||
@@ -306,7 +308,7 @@
 | 
			
		||||
            &[class*="-after"] {
 | 
			
		||||
                > .l-pane__handle {
 | 
			
		||||
                    bottom: 0;
 | 
			
		||||
                    transform: translateY(floor($splitterHandleD / 1));
 | 
			
		||||
                    transform: translateY(floor(math.div($splitterHandleD, 1)));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                &:not(.l-pane--collapsed) > .l-pane__collapse-button {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,25 +1,18 @@
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const packageDefinition = require('./package.json');
 | 
			
		||||
 | 
			
		||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
 | 
			
		||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
 | 
			
		||||
const webpack = require('webpack');
 | 
			
		||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
 | 
			
		||||
 | 
			
		||||
const devMode = process.env.NODE_ENV !== 'production';
 | 
			
		||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
 | 
			
		||||
// TODO: Build Constants w/ git-rev-sync
 | 
			
		||||
const gitRevision = require('child_process')
 | 
			
		||||
    .execSync('git rev-parse HEAD')
 | 
			
		||||
    .toString().trim();
 | 
			
		||||
const gitBranch = require('child_process')
 | 
			
		||||
    .execSync('git rev-parse --abbrev-ref HEAD')
 | 
			
		||||
    .toString().trim();
 | 
			
		||||
const vueFile = devMode
 | 
			
		||||
    ? path.join(__dirname, "node_modules/vue/dist/vue.js")
 | 
			
		||||
    : path.join(__dirname, "node_modules/vue/dist/vue.min.js");
 | 
			
		||||
 | 
			
		||||
const webpackConfig = {
 | 
			
		||||
    mode: devMode ? 'development' : 'production',
 | 
			
		||||
module.exports = {
 | 
			
		||||
    entry: {
 | 
			
		||||
        openmct: './openmct.js',
 | 
			
		||||
        couchDBChangesFeed: './src/plugins/persistence/couch/CouchChangesFeed.js',
 | 
			
		||||
@@ -33,7 +26,8 @@ const webpackConfig = {
 | 
			
		||||
        filename: '[name].js',
 | 
			
		||||
        library: '[name]',
 | 
			
		||||
        libraryTarget: 'umd',
 | 
			
		||||
        path: path.resolve(__dirname, 'dist')
 | 
			
		||||
        publicPath: '',
 | 
			
		||||
        clean: true
 | 
			
		||||
    },
 | 
			
		||||
    resolve: {
 | 
			
		||||
        alias: {
 | 
			
		||||
@@ -45,7 +39,6 @@ const webpackConfig = {
 | 
			
		||||
            "bourbon": "bourbon.scss",
 | 
			
		||||
            "plotly-basic": "plotly.js-basic-dist",
 | 
			
		||||
            "plotly-gl2d": "plotly.js-gl2d-dist",
 | 
			
		||||
            "vue": vueFile,
 | 
			
		||||
            "d3-scale": path.join(__dirname, "node_modules/d3-scale/build/d3-scale.min.js"),
 | 
			
		||||
            "printj": path.join(__dirname, "node_modules/printj/dist/printj.min.js"),
 | 
			
		||||
            "styles": path.join(__dirname, "src/styles"),
 | 
			
		||||
@@ -55,32 +48,32 @@ const webpackConfig = {
 | 
			
		||||
            "utils": path.join(__dirname, "src/utils")
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    devtool: devMode ? 'eval-source-map' : 'source-map',
 | 
			
		||||
    plugins: [
 | 
			
		||||
        new webpack.DefinePlugin({
 | 
			
		||||
            __OPENMCT_VERSION__: `'${packageDefinition.version}'`,
 | 
			
		||||
            __OPENMCT_BUILD_DATE__: `'${new Date()}'`,
 | 
			
		||||
            __OPENMCT_REVISION__: `'${gitRevision}'`,
 | 
			
		||||
            __OPENMCT_BUILD_BRANCH__: `'${gitBranch}'`,
 | 
			
		||||
            __OPENMCT_ROOT_RELATIVE__: `'${devMode ? 'dist/' : ''}'`
 | 
			
		||||
            __OPENMCT_BUILD_BRANCH__: `'${gitBranch}'`
 | 
			
		||||
        }),
 | 
			
		||||
        new VueLoaderPlugin(),
 | 
			
		||||
        new CopyWebpackPlugin({
 | 
			
		||||
            patterns: [
 | 
			
		||||
                {
 | 
			
		||||
                    from: 'src/images/favicons',
 | 
			
		||||
                    to: 'favicons'
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    from: './index.html',
 | 
			
		||||
                    transform: function (content) {
 | 
			
		||||
                        return content.toString().replace(/dist\//g, '');
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        }),
 | 
			
		||||
        new MiniCssExtractPlugin({
 | 
			
		||||
            filename: '[name].css',
 | 
			
		||||
            chunkFilename: '[name].css'
 | 
			
		||||
        }),
 | 
			
		||||
        new CopyWebpackPlugin([
 | 
			
		||||
            {
 | 
			
		||||
                from: 'src/images/favicons',
 | 
			
		||||
                to: 'favicons'
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                from: './index.html',
 | 
			
		||||
                transform: function (content) {
 | 
			
		||||
                    return content.toString().replace(/dist\//g, '');
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ])
 | 
			
		||||
        })
 | 
			
		||||
    ],
 | 
			
		||||
    module: {
 | 
			
		||||
        rules: [
 | 
			
		||||
@@ -88,10 +81,17 @@ const webpackConfig = {
 | 
			
		||||
                test: /\.(sc|sa|c)ss$/,
 | 
			
		||||
                use: [
 | 
			
		||||
                    MiniCssExtractPlugin.loader,
 | 
			
		||||
                    'css-loader',
 | 
			
		||||
                    'fast-sass-loader'
 | 
			
		||||
                    {
 | 
			
		||||
                        loader: 'css-loader'
 | 
			
		||||
                    },
 | 
			
		||||
                    'resolve-url-loader',
 | 
			
		||||
                    'sass-loader'
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                test: /\.vue$/,
 | 
			
		||||
                use: 'vue-loader'
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                test: /\.html$/,
 | 
			
		||||
                use: 'html-loader'
 | 
			
		||||
@@ -104,7 +104,7 @@ const webpackConfig = {
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                test: /\.(jpg|jpeg|png|svg|ico|woff2?|eot|ttf)$/,
 | 
			
		||||
                test: /\.(jpg|jpeg|png|svg|ico|woff|woff2?|eot|ttf)$/,
 | 
			
		||||
                loader: 'file-loader',
 | 
			
		||||
                options: {
 | 
			
		||||
                    name: '[name].[ext]',
 | 
			
		||||
@@ -117,26 +117,15 @@ const webpackConfig = {
 | 
			
		||||
                            return `icons/${url}`;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (/\.(woff2?|eot|ttf)$/.test(url)) {
 | 
			
		||||
                        if (/\.(woff|woff2?|eot|ttf)$/.test(url)) {
 | 
			
		||||
                            return `fonts/${url}`;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            return `${url}`;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                test: /\.vue$/,
 | 
			
		||||
                use: 'vue-loader'
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    stats: {
 | 
			
		||||
        modules: false,
 | 
			
		||||
        timings: true,
 | 
			
		||||
        colors: true,
 | 
			
		||||
        warningsFilter: /asset size limit/g
 | 
			
		||||
    }
 | 
			
		||||
    stats: 'detailed'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = webpackConfig;
 | 
			
		||||
							
								
								
									
										20
									
								
								webpack.dev.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								webpack.dev.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
const { merge } = require('webpack-merge');
 | 
			
		||||
const common = require('./webpack.common');
 | 
			
		||||
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const webpack = require('webpack');
 | 
			
		||||
 | 
			
		||||
module.exports = merge(common, {
 | 
			
		||||
    mode: 'development',
 | 
			
		||||
    resolve: {
 | 
			
		||||
        alias: {
 | 
			
		||||
            "vue": path.join(__dirname, "node_modules/vue/dist/vue.js")
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    plugins: [
 | 
			
		||||
        new webpack.DefinePlugin({
 | 
			
		||||
            __OPENMCT_ROOT_RELATIVE__: '"dist/"'
 | 
			
		||||
        })
 | 
			
		||||
    ],
 | 
			
		||||
    devtool: 'eval-source-map'
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										20
									
								
								webpack.prod.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								webpack.prod.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
const { merge } = require('webpack-merge');
 | 
			
		||||
const common = require('./webpack.common');
 | 
			
		||||
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const webpack = require('webpack');
 | 
			
		||||
 | 
			
		||||
module.exports = merge(common, {
 | 
			
		||||
    mode: 'production',
 | 
			
		||||
    resolve: {
 | 
			
		||||
        alias: {
 | 
			
		||||
            "vue": path.join(__dirname, "node_modules/vue/dist/vue.min.js")
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    plugins: [
 | 
			
		||||
        new webpack.DefinePlugin({
 | 
			
		||||
            __OPENMCT_ROOT_RELATIVE__: '""'
 | 
			
		||||
        })
 | 
			
		||||
    ],
 | 
			
		||||
    devtool: 'source-map'
 | 
			
		||||
});
 | 
			
		||||
		Reference in New Issue
	
	Block a user