Compare commits

..

2 Commits

Author SHA1 Message Date
Michael Rogers
637cf7a12f Add a view action buttons to toggle on class to control fixed layout 2023-03-17 14:42:14 -05:00
Michael Rogers
5a2afece06 Set table to fixed layout and ellipted overflowing cells 2023-03-16 13:47:57 -05:00
78 changed files with 352 additions and 863 deletions

View File

@@ -1,20 +0,0 @@
# Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging.
#
# Source repository: https://github.com/actions/dependency-review-action
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
- name: 'Dependency Review'
uses: actions/dependency-review-action@v2

View File

@@ -20,11 +20,11 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
const { test } = require('../../pluginFixtures');
const { setBoundsToSpanAllActivities } = require('../../helper/planningUtils');
const { createDomainObjectWithDefaults, createPlanFromJSON } = require('../../appActions');
const { test } = require('../../../pluginFixtures');
const { setBoundsToSpanAllActivities } = require('../../../helper/planningUtils');
const { createDomainObjectWithDefaults, createPlanFromJSON } = require('../../../appActions');
const percySnapshot = require('@percy/playwright');
const examplePlanLarge = require('../../test-data/examplePlans/ExamplePlan_Large.json');
const examplePlanLarge = require('../../../test-data/ExamplePlan_Large.json');
test.describe('Visual - Planning', () => {
test.beforeEach(async ({ page }) => {

View File

@@ -52,9 +52,10 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
//Set object identifier from url
conditionSetUrl = page.url();
console.log('conditionSetUrl ' + conditionSetUrl);
getConditionSetIdentifierFromUrl = conditionSetUrl.split('/').pop().split('?')[0];
console.debug(`getConditionSetIdentifierFromUrl: ${getConditionSetIdentifierFromUrl}`);
console.debug('getConditionSetIdentifierFromUrl ' + getConditionSetIdentifierFromUrl);
await page.close();
});
@@ -245,81 +246,4 @@ test.describe('Basic Condition Set Use', () => {
await expect(page.getByRole('menuitem', { name: /Plot/ })).toBeVisible();
await expect(page.getByRole('menuitem', { name: /Telemetry Table/ })).toBeVisible();
});
test('ConditionSet should output blank instead of the default value', async ({ page }) => {
//Navigate to baseURL
await page.goto('./', { waitUntil: 'networkidle' });
//Click the Create button
await page.click('button:has-text("Create")');
// Click the object specified by 'type'
await page.click(`li[role='menuitem']:text("Sine Wave Generator")`);
await page.getByRole('spinbutton', { name: 'Loading Delay (ms)' }).fill('8000');
const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]');
await nameInput.fill("Delayed Sine Wave Generator");
// Click OK button and wait for Navigate event
await Promise.all([
page.waitForLoadState(),
page.click('[aria-label="Save"]'),
// Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message')
]);
// Create a new condition set
await createDomainObjectWithDefaults(page, {
type: 'Condition Set',
name: "Test Blank Output of Condition Set"
});
// Change the object to edit mode
await page.locator('[title="Edit"]').click();
// Click Add Condition button twice
await page.locator('#addCondition').click();
await page.locator('#addCondition').click();
await page.locator('#conditionCollection').getByRole('textbox').nth(0).fill('First Condition');
await page.locator('#conditionCollection').getByRole('textbox').nth(1).fill('Second Condition');
// Expand the 'My Items' folder in the left tree
await page.locator('.c-tree__item__view-control.c-disclosure-triangle').first().click();
// Add the Sine Wave Generator to the Condition Set and save changes
const treePane = page.getByRole('tree', {
name: 'Main Tree'
});
const sineWaveGeneratorTreeItem = treePane.getByRole('treeitem', { name: "Delayed Sine Wave Generator"});
const conditionCollection = await page.locator('#conditionCollection');
await sineWaveGeneratorTreeItem.dragTo(conditionCollection);
const firstCriterionTelemetry = await page.locator('[aria-label="Criterion Telemetry Selection"] >> nth=0');
firstCriterionTelemetry.selectOption({ label: 'Delayed Sine Wave Generator' });
const secondCriterionTelemetry = await page.locator('[aria-label="Criterion Telemetry Selection"] >> nth=1');
secondCriterionTelemetry.selectOption({ label: 'Delayed Sine Wave Generator' });
const firstCriterionMetadata = await page.locator('[aria-label="Criterion Metadata Selection"] >> nth=0');
firstCriterionMetadata.selectOption({ label: 'Sine' });
const secondCriterionMetadata = await page.locator('[aria-label="Criterion Metadata Selection"] >> nth=1');
secondCriterionMetadata.selectOption({ label: 'Sine' });
const firstCriterionComparison = await page.locator('[aria-label="Criterion Comparison Selection"] >> nth=0');
firstCriterionComparison.selectOption({ label: 'is greater than or equal to' });
const secondCriterionComparison = await page.locator('[aria-label="Criterion Comparison Selection"] >> nth=1');
secondCriterionComparison.selectOption({ label: 'is less than' });
const firstCriterionInput = await page.locator('[aria-label="Criterion Input"] >> nth=0');
await firstCriterionInput.fill("0");
const secondCriterionInput = await page.locator('[aria-label="Criterion Input"] >> nth=1');
await secondCriterionInput.fill("0");
const saveButtonLocator = page.locator('button[title="Save"]');
await saveButtonLocator.click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
const outputValue = await page.locator('[aria-label="Current Output Value"]');
await expect(outputValue).toHaveText('---');
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -268,9 +268,6 @@ async function getCanvasPixelsWithData(page) {
* @param {import('@playwright/test').Page} page
*/
async function assertLimitLinesExistAndAreVisible(page) {
// Wait for plot series data to load
await expect(page.locator('.js-series-data-loaded')).toBeVisible();
// Wait for limit lines to be created
await page.waitForSelector('.js-limit-area', { state: 'attached' });
const limitLineCount = await page.locator('.c-plot-limit-line').count();
// There should be 10 limit lines created by default

View File

@@ -115,9 +115,6 @@ test.describe('Stacked Plot', () => {
await expect(stackedPlotItem2).toHaveAttribute('aria-label', `Stacked Plot Item ${swgC.name}`);
await expect(stackedPlotItem3).toHaveAttribute('aria-label', `Stacked Plot Item ${swgA.name}`);
// collapse inspector
await page.locator('.l-shell__pane-inspector .l-pane__collapse-button').click();
// Save (exit edit mode)
await page.locator('button[title="Save"]').click();
await page.locator('li[title="Save and Finish Editing"]').click();

View File

@@ -28,14 +28,6 @@ const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults, setRealTimeMode, setFixedTimeMode } = require('../../../../appActions');
test.describe('Plot Tagging', () => {
/**
* Given a canvas and a set of points, tags the points on the canvas.
* @param {import('@playwright/test').Page} page
* @param {HTMLCanvasElement} canvas a telemetry item with a plot
* @param {Number} xEnd a telemetry item with a plot
* @param {Number} yEnd a telemetry item with a plot
* @returns {Promise}
*/
async function createTags({page, canvas, xEnd, yEnd}) {
await canvas.hover({trial: true});
@@ -72,20 +64,12 @@ test.describe('Plot Tagging', () => {
await page.getByText('Science').click();
}
/**
* Given a telemetry item (e.g., a Sine Wave Generator) with a plot, tests that the plot can be tagged.
* @param {import('@playwright/test').Page} page
* @param {import('../../../../appActions').CreatedObjectInfo} telemetryItem a telemetry item with a plot
* @returns {Promise}
*/
async function testTelemetryItem(page, telemetryItem) {
async function testTelemetryItem(page, canvas, telemetryItem) {
// Check that telemetry item also received the tag
await page.goto(telemetryItem.url);
await expect(page.getByText('No tags to display for this item')).toBeVisible();
const canvas = page.locator('canvas').nth(1);
//Wait for canvas to stablize.
await canvas.hover({trial: true});
@@ -101,32 +85,20 @@ test.describe('Plot Tagging', () => {
await expect(page.getByText('Driving')).toBeHidden();
}
/**
* Given a page, tests that tags are searchable, deletable, and persist across reloads.
* @param {import('@playwright/test').Page} page
* @returns {Promise}
*/
async function basicTagsTests(page) {
// Search for Driving
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
// Clicking elsewhere should cause annotation selection to be cleared
await expect(page.getByText('No tags to display for this item')).toBeVisible();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('driv');
// click on the search result
await page.getByRole('searchbox', { name: 'OpenMCT Search' }).getByText(/Sine Wave/).first().click();
// Delete Driving
await page.hover('[aria-label="Tag"]:has-text("Driving")');
await page.locator('[aria-label="Remove tag Driving"]').click();
async function basicTagsTests(page, canvas) {
// Search for Science
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
await expect(page.locator('[aria-label="Search Result"]').nth(0)).toContainText("Science");
await expect(page.locator('[aria-label="Search Result"]').nth(0)).not.toContainText("Drilling");
// Delete Driving
await page.hover('[aria-label="Tag"]:has-text("Driving")');
await page.locator('[aria-label="Remove tag Driving"]').click();
await expect(page.locator('[aria-label="Tags Inspector"]')).toContainText("Science");
await expect(page.locator('[aria-label="Tags Inspector"]')).not.toContainText("Driving");
// Search for Driving
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('driv');
@@ -137,13 +109,12 @@ test.describe('Plot Tagging', () => {
page.reload(),
page.waitForLoadState('networkidle')
]);
// wait for plots to load
await expect(page.locator('.js-series-data-loaded')).toBeVisible();
// wait for plot progress bar to disappear
await page.locator('.l-view-section.c-progress-bar').waitFor({ state: 'detached' });
await page.getByText('Annotations').click();
await expect(page.getByText('No tags to display for this item')).toBeVisible();
const canvas = page.locator('canvas').nth(1);
// click on the tagged plot point
await canvas.click({
position: {
@@ -200,23 +171,8 @@ test.describe('Plot Tagging', () => {
// changing to fixed time mode rebuilds canvas?
canvas = page.locator('canvas').nth(1);
await basicTagsTests(page);
await testTelemetryItem(page, alphaSineWave);
// set to real time mode
await setRealTimeMode(page);
// Search for Science
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
// click on the search result
await page.getByRole('searchbox', { name: 'OpenMCT Search' }).getByText('Alpha Sine Wave').first().click();
// wait for plots to load
await expect(page.locator('.js-series-data-loaded')).toBeVisible();
// expect plot to be paused
await expect(page.locator('[title="Resume displaying real-time data"]')).toBeVisible();
await setFixedTimeMode(page);
await basicTagsTests(page, canvas);
await testTelemetryItem(page, canvas, alphaSineWave);
});
test('Tags work with Plot View of telemetry items', async ({ page }) => {
@@ -231,7 +187,7 @@ test.describe('Plot Tagging', () => {
xEnd: 700,
yEnd: 480
});
await basicTagsTests(page);
await basicTagsTests(page, canvas);
});
test('Tags work with Stacked Plots', async ({ page }) => {
@@ -261,7 +217,7 @@ test.describe('Plot Tagging', () => {
xEnd: 700,
yEnd: 215
});
await basicTagsTests(page);
await testTelemetryItem(page, alphaSineWave);
await basicTagsTests(page, canvas);
await testTelemetryItem(page, canvas, alphaSineWave);
});
});

View File

@@ -191,7 +191,7 @@ test.describe('Recent Objects', () => {
expect(await clockBreadcrumbs.count()).toBe(2);
expect(await clockBreadcrumbs.nth(0).innerText()).not.toEqual(await clockBreadcrumbs.nth(1).innerText());
});
test("Enforces a limit of 20 recent objects and clears the recent objects", async ({ page }) => {
test("Enforces a limit of 20 recent objects", async ({ page }) => {
// Creating 21 objects takes a while, so increase the timeout
test.slow();
@@ -242,15 +242,6 @@ test.describe('Recent Objects', () => {
// Assert that the Clock treeitem is no longer highlighted
await expect(lastClockTreeItem.locator('.c-tree__item')).not.toHaveClass(/is-targeted-item/);
// Click the aria-label="Clear Recently Viewed" button
await page.getByRole('button', { name: 'Clear Recently Viewed' }).click();
// Click on the "OK" button in the confirmation dialog
await page.getByRole('button', { name: 'OK' }).click();
// Assert that the list is empty
expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(0);
});
function assertInitialRecentObjectsListState() {

View File

@@ -63,7 +63,7 @@ test.describe('Grand Search', () => {
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(`Clock A ${myItemsFolderName} Red Folder Blue Folder`);
// Click [aria-label="OpenMCT Search"] a >> nth=0
await page.locator('[aria-label="Search Result"] >> nth=0').click();
await page.locator('[aria-label="OpenMCT Search"] a').first().click();
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden();
// Fill [aria-label="OpenMCT Search"] input[type="search"]

View File

@@ -50,6 +50,7 @@ test.describe('Main Tree', () => {
await expandTreePaneItemByName(page, folder.name);
await assertTreeItemIsVisible(page, clock.name);
});
test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @2p', async ({ page, openmctConfig }) => {

View File

@@ -138,7 +138,6 @@ test.describe('Performance tests', () => {
await page.evaluate(() => window.performance.mark("notebook-search-processed"));
//Clear Search
await page.locator('.c-search.c-notebook__search .c-search__input').hover();
await page.locator('.c-search.c-notebook__search .c-search__clear-input').click();
await page.evaluate(() => window.performance.mark("notebook-search-processed"));

View File

@@ -1,6 +1,6 @@
{
"name": "openmct",
"version": "2.2.1-SNAPSHOT",
"version": "2.2.0-SNAPSHOT",
"description": "The Open MCT core platform",
"devDependencies": {
"@babel/eslint-parser": "7.18.9",
@@ -23,7 +23,7 @@
"eslint": "8.36.0",
"eslint-plugin-compat": "4.1.1",
"eslint-plugin-playwright": "0.12.0",
"eslint-plugin-vue": "9.10.0",
"eslint-plugin-vue": "9.9.0",
"eslint-plugin-you-dont-need-lodash-underscore": "6.12.0",
"eventemitter3": "1.2.0",
"file-saver": "2.0.5",
@@ -44,20 +44,20 @@
"kdbush": "^3.0.0",
"location-bar": "3.0.1",
"lodash": "4.17.21",
"mini-css-extract-plugin": "2.7.5",
"mini-css-extract-plugin": "2.7.2",
"moment": "2.29.4",
"moment-duration-format": "2.3.2",
"moment-timezone": "0.5.41",
"nyc": "15.1.0",
"painterro": "1.2.78",
"playwright-core": "1.29.0",
"plotly.js-basic-dist": "2.20.0",
"plotly.js-gl2d-dist": "2.20.0",
"plotly.js-basic-dist": "2.17.0",
"plotly.js-gl2d-dist": "2.17.1",
"printj": "1.3.1",
"resolve-url-loader": "5.0.0",
"sanitize-html": "2.10.0",
"sass": "1.59.3",
"sass-loader": "13.2.1",
"sass": "1.57.1",
"sass-loader": "13.2.0",
"sinon": "15.0.1",
"style-loader": "^3.3.1",
"typescript": "4.9.5",
@@ -66,7 +66,7 @@
"vue-eslint-parser": "9.1.0",
"vue-loader": "15.9.8",
"vue-template-compiler": "2.6.14",
"webpack": "5.76.3",
"webpack": "5.74.0",
"webpack-cli": "5.0.0",
"webpack-dev-server": "4.11.1",
"webpack-merge": "5.8.0"

View File

@@ -43,7 +43,7 @@
</div>
<div
v-if="!hideOptions && filteredOptions.length > 0"
class="c-menu c-input--autocomplete__options js-autocomplete-options"
class="c-menu c-input--autocomplete__options"
aria-label="Autocomplete Options"
@blur="hideOptions = true"
>

View File

@@ -415,10 +415,7 @@ export default class NotificationAPI extends EventEmitter {
for (; i < this.notifications.length; i++) {
notification = this.notifications[i];
const isNotificationMinimized = notification.model.minimized
|| notification?.model?.options?.minimized;
if (!isNotificationMinimized
if (!notification.model.minimized
&& notification !== this.activeNotification) {
return notification;
}

View File

@@ -81,7 +81,7 @@
}
.c-object-label__name {
color: $objectLabelNameColorFg;
filter: $objectLabelNameFilter;
}
}

View File

@@ -29,7 +29,6 @@ import DefaultMetadataProvider from './DefaultMetadataProvider';
import objectUtils from 'objectUtils';
export default class TelemetryAPI {
#isGreedyLAD;
constructor(openmct) {
this.openmct = openmct;
@@ -45,8 +44,8 @@ export default class TelemetryAPI {
this.requestProviders = [];
this.subscriptionProviders = [];
this.valueFormatterCache = new WeakMap();
this.requestInterceptorRegistry = new TelemetryRequestInterceptorRegistry();
this.#isGreedyLAD = true;
}
abortAllRequests() {
@@ -227,31 +226,6 @@ export default class TelemetryAPI {
return modifiedRequest;
}
/**
* Get or set greedy LAD. For stategy "latest" telemetry in
* realtime mode the start bound will be ignored if true and
* there is no new data to replace the existing data.
* defaults to true
*
* To turn off greedy LAD:
* openmct.telemetry.greedyLAD(false);
*
* @method greedyLAD
* @returns {boolean} if greedyLAD is active or not
* @memberof module:openmct.TelemetryAPI#
*/
greedyLAD(isGreedy) {
if (arguments.length > 0) {
if (isGreedy !== true && isGreedy !== false) {
throw new Error('Error setting greedyLAD. Greedy LAD only accepts true or false values');
}
this.#isGreedyLAD = isGreedy;
}
return this.#isGreedyLAD;
}
/**
* Request telemetry collection for a domain object.
* The `options` argument allows you to specify filters

View File

@@ -30,8 +30,8 @@ export default class TelemetryCollection extends EventEmitter {
/**
* Creates a Telemetry Collection
*
* @param {OpenMCT} openmct - Open MCT
* @param {module:openmct.DomainObject} domainObject - Domain Object to use for telemetry collection
* @param {object} openmct - Openm MCT
* @param {object} domainObject - Domain Object to user for telemetry collection
* @param {object} options - Any options passed in for request/subscribe
*/
constructor(openmct, domainObject, options) {
@@ -50,7 +50,6 @@ export default class TelemetryCollection extends EventEmitter {
this.lastBounds = undefined;
this.requestAbort = undefined;
this.isStrategyLatest = this.options.strategy === 'latest';
this.dataOutsideTimeBounds = false;
}
/**
@@ -130,6 +129,9 @@ export default class TelemetryCollection extends EventEmitter {
this.emit('requestStarted');
const modifiedOptions = await this.openmct.telemetry.applyRequestInterceptors(this.domainObject, options);
historicalData = await historicalProvider.request(this.domainObject, modifiedOptions);
if (!historicalData || !historicalData.length) {
return;
}
} catch (error) {
if (error.name !== 'AbortError') {
console.error('Error requesting telemetry data...');
@@ -140,10 +142,6 @@ export default class TelemetryCollection extends EventEmitter {
this.emit('requestEnded');
this.requestAbort = undefined;
if (!historicalData || !historicalData.length) {
return;
}
this._processNewTelemetry(historicalData);
}
@@ -186,7 +184,6 @@ export default class TelemetryCollection extends EventEmitter {
let afterEndOfBounds;
let added = [];
let addedIndices = [];
let hasDataBeforeStartBound = false;
// loop through, sort and dedupe
for (let datum of data) {
@@ -194,7 +191,7 @@ export default class TelemetryCollection extends EventEmitter {
beforeStartOfBounds = parsedValue < this.lastBounds.start;
afterEndOfBounds = parsedValue > this.lastBounds.end;
if (!afterEndOfBounds && (!beforeStartOfBounds || (this.isStrategyLatest && this.openmct.telemetry.greedyLAD()))) {
if (!afterEndOfBounds && !beforeStartOfBounds) {
let isDuplicate = false;
let startIndex = this._sortedIndex(datum);
let endIndex = undefined;
@@ -221,10 +218,6 @@ export default class TelemetryCollection extends EventEmitter {
this.boundedTelemetry.splice(index, 0, datum);
addedIndices.push(index);
added.push(datum);
if (!hasDataBeforeStartBound && beforeStartOfBounds) {
hasDataBeforeStartBound = true;
}
}
} else if (afterEndOfBounds) {
@@ -233,18 +226,12 @@ export default class TelemetryCollection extends EventEmitter {
}
if (added.length) {
// if latest strategy is requested, we need to check if the value is the latest unemitted value
// if latest strategy is requested, we need to check if the value is the latest unmitted value
if (this.isStrategyLatest) {
this.boundedTelemetry = [this.boundedTelemetry[this.boundedTelemetry.length - 1]];
// if true, then this value has yet to be emitted
if (this.boundedTelemetry[0] !== latestBoundedDatum) {
if (hasDataBeforeStartBound) {
this._handleDataOutsideBounds();
} else {
this._handleDataInsideBounds();
}
this.emit('add', this.boundedTelemetry);
}
} else {
@@ -307,17 +294,6 @@ export default class TelemetryCollection extends EventEmitter {
let added = [];
let testDatum = {};
if (endChanged) {
testDatum[this.timeKey] = bounds.end;
// Calculate the new index of the last item in bounds
endIndex = _.sortedLastIndexBy(
this.futureBuffer,
testDatum,
datum => this.parseTime(datum)
);
added = this.futureBuffer.splice(0, endIndex);
}
if (startChanged) {
testDatum[this.timeKey] = bounds.start;
@@ -331,21 +307,22 @@ export default class TelemetryCollection extends EventEmitter {
);
discarded = this.boundedTelemetry.splice(0, startIndex);
} else if (this.parseTime(testDatum) > this.parseTime(this.boundedTelemetry[0])) {
// if greedyLAD is active and there is no new data to replace, don't discard
const isGreedyLAD = this.openmct.telemetry.greedyLAD();
const shouldRemove = (!isGreedyLAD || (isGreedyLAD && added.length > 0));
if (shouldRemove) {
discarded = this.boundedTelemetry;
this.boundedTelemetry = [];
// since it IS strategy latest, we can assume there will be at least 1 datum
// unless no data was returned in the first request, we need to account for that
} else if (this.boundedTelemetry.length === 1) {
this._handleDataOutsideBounds();
}
discarded = this.boundedTelemetry;
this.boundedTelemetry = [];
}
}
if (endChanged) {
testDatum[this.timeKey] = bounds.end;
// Calculate the new index of the last item in bounds
endIndex = _.sortedLastIndexBy(
this.futureBuffer,
testDatum,
datum => this.parseTime(datum)
);
added = this.futureBuffer.splice(0, endIndex);
}
if (discarded.length > 0) {
this.emit('remove', discarded);
}
@@ -354,8 +331,6 @@ export default class TelemetryCollection extends EventEmitter {
if (!this.isStrategyLatest) {
this.boundedTelemetry = [...this.boundedTelemetry, ...added];
} else {
this._handleDataInsideBounds();
added = [added[added.length - 1]];
this.boundedTelemetry = added;
}
@@ -370,20 +345,6 @@ export default class TelemetryCollection extends EventEmitter {
}
_handleDataInsideBounds() {
if (this.dataOutsideTimeBounds) {
this.dataOutsideTimeBounds = false;
this.emit('dataInsideTimeBounds');
}
}
_handleDataOutsideBounds() {
if (!this.dataOutsideTimeBounds) {
this.dataOutsideTimeBounds = true;
this.emit('dataOutsideTimeBounds');
}
}
/**
* whenever the time system is updated need to update related values in
* the Telemetry Collection and reset the telemetry collection

View File

@@ -121,9 +121,8 @@ define([
}
TelemetryValueFormatter.prototype.parse = function (datum) {
const isDatumArray = Array.isArray(datum);
if (_.isObject(datum)) {
const objectDatum = isDatumArray ? datum : datum[this.valueMetadata.source];
const objectDatum = datum[this.valueMetadata.source];
if (Array.isArray(objectDatum)) {
return objectDatum.map((item) => {
return this.formatter.parse(item);
@@ -137,9 +136,8 @@ define([
};
TelemetryValueFormatter.prototype.format = function (datum) {
const isDatumArray = Array.isArray(datum);
if (_.isObject(datum)) {
const objectDatum = isDatumArray ? datum : datum[this.valueMetadata.source];
const objectDatum = datum[this.valueMetadata.source];
if (Array.isArray(objectDatum)) {
return objectDatum.map((item) => {
return this.formatter.format(item);

View File

@@ -22,7 +22,7 @@
const expandColumns = {
name: 'Expand Columns',
key: 'lad-expand-columns',
key: 'expand-columns',
description: "Increase column widths to fit currently available data.",
cssClass: 'icon-arrows-right-left labeled',
invoke: (objectPath, view) => {
@@ -34,7 +34,7 @@ const expandColumns = {
const autosizeColumns = {
name: 'Autosize Columns',
key: 'lad-autosize-columns',
key: 'autosize-columns',
description: "Automatically size columns to fit the table into the available space.",
cssClass: 'icon-expand labeled',
invoke: (objectPath, view) => {

View File

@@ -55,7 +55,7 @@
</template>
<script>
import Vue from 'vue';
import LadRow from './LADRow.vue';
import StalenessUtils from '@/utils/staleness';
@@ -115,23 +115,7 @@ export default {
return '';
}
},
watch: {
configuration: {
handler(newVal) {
if (this.viewActionsCollection) {
if (newVal.isFixedLayout) {
this.viewActionsCollection.show(['lad-expand-columns']);
this.viewActionsCollection.hide(['lad-autosize-columns']);
} else {
this.viewActionsCollection.show(['lad-autosize-columns']);
this.viewActionsCollection.hide(['lad-expand-columns']);
}
}
},
deep: true
}
},
async mounted() {
mounted() {
this.ladTableConfiguration.on('change', this.handleConfigurationChange);
this.composition = this.openmct.composition.get(this.domainObject);
this.composition.on('add', this.addItem);
@@ -139,9 +123,6 @@ export default {
this.composition.on('reorder', this.reorder);
this.composition.load();
this.stalenessSubscription = {};
await Vue.nextTick();
this.viewActionsCollection = this.openmct.actions.getActionsCollection(this.objectPath, this.currentView);
this.initializeViewActions();
},
destroyed() {
this.ladTableConfiguration.off('change', this.handleConfigurationChange);
@@ -227,16 +208,6 @@ export default {
},
toggleFixedLayout() {
this.configuration.isFixedLayout = !this.configuration.isFixedLayout;
},
initializeViewActions() {
if (this.configuration.isFixedLayout) {
this.viewActionsCollection.show(['lad-expand-columns']);
this.viewActionsCollection.hide(['lad-autosize-columns']);
} else {
this.viewActionsCollection.hide(['lad-expand-columns']);
this.viewActionsCollection.show(['lad-autosize-columns']);
}
}
}
};

View File

@@ -93,11 +93,6 @@ export default class ConditionManager extends EventEmitter {
);
this.updateConditionResults({id: id});
this.updateCurrentCondition(latestTimestamp);
if (Object.keys(this.telemetryObjects).length === 0) {
// no telemetry objects
this.emit('noTelemetryObjects');
}
}
initialize() {
@@ -107,11 +102,6 @@ export default class ConditionManager extends EventEmitter {
this.initCondition(conditionConfiguration, index);
});
}
if (Object.keys(this.telemetryObjects).length === 0) {
// no telemetry objects
this.emit('noTelemetryObjects');
}
}
updateConditionTelemetryObjects() {

View File

@@ -35,9 +35,7 @@ export default class StyleRuleManager extends EventEmitter {
}
if (styleConfiguration) {
// We don't set the selectedConditionId here because we want condition set computation to happen before we apply any selected style
const styleConfigurationWithNoSelection = Object.assign(styleConfiguration, {selectedConditionId: ''});
this.initialize(styleConfigurationWithNoSelection);
this.initialize(styleConfiguration);
if (styleConfiguration.conditionSetIdentifier) {
this.openmct.time.on("bounds", this.refreshData);
this.subscribeToConditionSet();
@@ -59,18 +57,14 @@ export default class StyleRuleManager extends EventEmitter {
this.applySelectedConditionStyle();
}
} else if (this.conditionSetIdentifier) {
//reset the selected style and let the condition set output determine what it should be
this.selectedConditionId = undefined;
this.currentStyle = undefined;
this.updateDomainObjectStyle();
this.subscribeToConditionSet();
}
}
initialize(styleConfiguration) {
this.conditionSetIdentifier = styleConfiguration.conditionSetIdentifier;
this.selectedConditionId = styleConfiguration.selectedConditionId;
this.staticStyle = styleConfiguration.staticStyle;
this.selectedConditionId = styleConfiguration.selectedConditionId;
this.defaultConditionId = styleConfiguration.defaultConditionId;
this.updateConditionStylesMap(styleConfiguration.styles || []);
}

View File

@@ -132,7 +132,6 @@
<span class="c-cdef__controls">
<select
v-model="condition.configuration.trigger"
aria-label="Condition Trigger"
@change="persist"
>
<option

View File

@@ -114,11 +114,15 @@ export default {
telemetryObjs: [],
moveIndex: undefined,
isDragging: false,
defaultOutput: undefined,
dragCounter: 0,
currentConditionId: ''
};
},
watch: {
defaultOutput(newOutput, oldOutput) {
this.$emit('updateDefaultOutput', newOutput);
},
testData: {
handler() {
this.updateTestData();
@@ -154,7 +158,7 @@ export default {
this.observeForChanges();
this.conditionManager = new ConditionManager(this.domainObject, this.openmct);
this.conditionManager.on('conditionSetResultUpdated', this.handleConditionSetResultUpdated);
this.conditionManager.on('noTelemetryObjects', this.emitNoTelemetryObjectEvent);
this.updateDefaultCondition();
this.stalenessSubscription = {};
},
methods: {
@@ -162,16 +166,18 @@ export default {
this.currentConditionId = data.conditionId;
this.$emit('conditionSetResultUpdated', data);
},
emitNoTelemetryObjectEvent(data) {
this.currentConditionId = '';
this.$emit('noTelemetryObjects');
},
observeForChanges() {
this.stopObservingForChanges = this.openmct.objects.observe(this.domainObject, 'configuration.conditionCollection', (newConditionCollection) => {
//this forces children to re-render
this.conditionCollection = newConditionCollection.map(condition => condition);
this.updateDefaultCondition();
});
},
updateDefaultCondition() {
const defaultCondition = this.domainObject.configuration.conditionCollection
.find(conditionConfiguration => conditionConfiguration.isDefault);
this.defaultOutput = defaultCondition.configuration.output;
},
setMoveIndex(index) {
this.moveIndex = index;
this.isDragging = true;

View File

@@ -28,15 +28,12 @@
<section class="c-cs__current-output c-section">
<div class="c-cs__content c-cs__current-output-value">
<span class="c-cs__current-output-value__label">Current Output</span>
<span
class="c-cs__current-output-value__value"
aria-label="Current Output Value"
>
<span class="c-cs__current-output-value__value">
<template v-if="currentConditionOutput">
{{ currentConditionOutput }}
</template>
<template v-else>
---
{{ defaultConditionOutput }}
</template>
</span>
</div>
@@ -54,7 +51,7 @@
:is-editing="isEditing"
:test-data="testData"
@conditionSetResultUpdated="updateCurrentOutput"
@noTelemetryObjects="updateCurrentOutput('---')"
@updateDefaultOutput="updateDefaultOutput"
@telemetryUpdated="updateTelemetry"
@telemetryStaleness="handleStaleness"
/>
@@ -78,6 +75,7 @@ export default {
data() {
return {
currentConditionOutput: '',
defaultConditionOutput: '',
telemetryObjs: [],
testData: {},
staleObjects: []

View File

@@ -29,7 +29,6 @@
<select
ref="telemetrySelect"
v-model="criterion.telemetry"
aria-label="Criterion Telemetry Selection"
@change="updateMetadataOptions"
>
<option value="">- Select Telemetry -</option>
@@ -51,7 +50,6 @@
<select
ref="metadataSelect"
v-model="criterion.metadata"
aria-label="Criterion Metadata Selection"
@change="updateOperations"
>
<option value="">- Select Field -</option>
@@ -71,7 +69,6 @@
>
<select
v-model="criterion.operation"
aria-label="Criterion Comparison Selection"
@change="updateInputVisibilityAndValues"
>
<option value="">- Select Comparison -</option>
@@ -92,7 +89,6 @@
<input
v-model="criterion.input[inputIndex]"
class="c-cdef__control__input"
aria-label="Criterion Input"
:type="setInputType"
@change="persist"
>
@@ -107,7 +103,6 @@
>
<select
v-model="criterion.input[0]"
aria-label="Criterion Else Selection"
@change="persist"
>
<option

View File

@@ -307,8 +307,6 @@ export default {
delete this.stopProvidingTelemetry;
}
} else {
//reset the selectedConditionID so that the condition set computation can drive it.
this.applySelectedConditionStyle('');
this.subscribeToConditionSet();
}
},

View File

@@ -80,9 +80,11 @@
.is-editing & {
cursor: pointer;
pointer-events: initial;
transition: $transOut;
&:hover {
background: rgba($colorBodyFg, 0.1);
transition: $transIn;
}
&.is-current {

View File

@@ -72,7 +72,7 @@ export default {
this.isEditing = isEditing;
},
formatTelemetry(event) {
const newFormat = event.currentTarget.value;
let newFormat = event.currentTarget.value;
this.openmct.selection.get().forEach(selectionPath => {
selectionPath[0].context.updateTelemetryFormat(newFormat);
});

View File

@@ -193,7 +193,7 @@ export default {
},
telemetryValue() {
if (!this.datum) {
return '---';
return;
}
return this.formatter && this.formatter.format(this.datum);

View File

@@ -86,7 +86,7 @@
*[s-selected-parent] {
> .l-layout {
// When main shell layout is the parent
@include displayMarquee(deeppink); // TEMP
@include displayMarquee(deeppink);
}
> * > * > * {
// When a sub-layout is the parent

View File

@@ -45,15 +45,18 @@
// Has-complex-content objects
.c-so-view.has-complex-content {
@include transition($prop: transform, $dur: $transOutTime, $delay: $moveBarOutDelay);
transition: $transOut;
transition-delay: $moveBarOutDelay;
> .c-so-view__local-controls {
@include transition($prop: transform, $dur: 250ms, $delay: $moveBarOutDelay);
transition: transform 250ms ease-in-out;
transition-delay: $moveBarOutDelay;
}
+ .c-frame__move-bar {
display: none;
}
}
.l-layout {
@@ -62,11 +65,13 @@
> .l-layout__frame {
> .c-so-view.has-complex-content {
> .c-so-view__local-controls {
@include transition($prop: transform, $dur: $transOutTime, $delay: $moveBarOutDelay);
transition: transform $transOutTime ease-in-out;
transition-delay: $moveBarOutDelay;
}
+ .c-frame__move-bar {
@include transition($prop: height, $delay: $moveBarOutDelay);
transition: $transOut;
transition-delay: $moveBarOutDelay;
@include userSelectNone();
background: $editFrameMovebarColorBg;
box-shadow: rgba(black, 0.3) 0 2px;
@@ -98,17 +103,18 @@
&:hover {
> .c-so-view.has-complex-content {
transition: $transInTransform;
transition: $transIn;
transition-delay: 0s;
> .c-so-view__local-controls {
transform: translateY($editFrameMovebarH);
@include transition(height, $transOutTime);
transition: transform $transInTime ease-in-out;
transition-delay: 0s;
}
+ .c-frame__move-bar {
@include transition(height);
transition: $transIn;
transition-delay: 0s;
height: $editFrameMovebarH;
}
}

View File

@@ -244,10 +244,11 @@
display: flex;
flex-direction: column;
flex: 0 0 ($margin * 2) + $size;
transition: $transOut;
&:before {
// The visible resize line
background-color: $editUIColor;
background: $editUIColor;
content: '';
display: block;
flex: 1 1 auto;
@@ -269,9 +270,10 @@
}
&:hover {
transition: $transOut;
&:before {
// The visible resize line
background-color: $editUIColorHov;
background: $editUIColorHov;
}
}
}

View File

@@ -37,7 +37,6 @@
.c-grid-item {
// Mobile-first
@include button($bg: $colorItemBg, $fg: $colorItemFg);
@include cControlHov();
cursor: pointer;
display: flex;
padding: $interiorMarginLg;
@@ -143,10 +142,15 @@
body.desktop & {
$transOutMs: 300ms;
flex-flow: column nowrap;
transition: $transOutMs ease-in-out;
&:hover {
filter: $filterItemHoverFg;
transition: $transIn;
.c-grid-item__type-icon {
transform: scale(1.1);
transition: $transInBounce;
}
}
@@ -167,6 +171,8 @@
font-size: floor(math.div($gridItemDesk, 3));
margin: $interiorMargin 22.5% $interiorMargin * 3 22.5%;
order: 2;
transform-origin: center;
transition: all $transOutMs ease-in-out;
}
&__details {

View File

@@ -322,7 +322,7 @@ export default {
rgba(125,125,125,.2) 8px
)`
) : ''}`,
transform: `scale(${this.zoomFactor}) translate(${this.imageTranslateX / 2}px, ${this.imageTranslateY / 2}px)`,
transform: `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`,
transition: `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}`,
width: `${this.sizedImageWidth}px`,
height: `${this.sizedImageHeight}px`
@@ -709,7 +709,7 @@ export default {
getVisibleLayerStyles(layer) {
return {
backgroundImage: `url(${layer.source})`,
transform: `scale(${this.zoomFactor}) translate(${this.imageTranslateX / 2}px, ${this.imageTranslateY / 2}px)`,
transform: `scale(${this.zoomFactor}) translate(${this.imageTranslateX}px, ${this.imageTranslateY}px)`,
transition: `${!this.pan && this.animateZoom ? 'transform 250ms ease-in' : 'initial'}`
};
},

View File

@@ -195,7 +195,7 @@
margin-bottom: 1px;
padding-bottom: $interiorMarginSm;
&.animate-scroll {
scroll-behavior: smooth;
scroll-behavior: smooth;
}
}
@@ -320,7 +320,7 @@
flex-direction: row;
position: absolute;
left: $interiorMargin; top: $interiorMargin;
z-index: 10;
z-index: 70;
background: $colorLocalControlOvrBg;
border-radius: $basicCr;
align-items: center;
@@ -495,6 +495,7 @@
&:hover {
z-index: 2;
filter: brightness(1) contrast(1) !important;
[class*='__image-handle'] {
background-color: $colorBodyFg;
}
@@ -518,4 +519,9 @@
display: block;
align-self: flex-end;
}
&:hover div.c-imagery-tsv__image-wrapper {
// TODO CH: convert to theme constants
filter: brightness(0.5) contrast(0.7);
}
}

View File

@@ -23,17 +23,11 @@
import Annotations from './AnnotationsInspectorView.vue';
import Vue from 'vue';
export default function AnnotationsViewProvider(openmct) {
export default function ElementsViewProvider(openmct) {
return {
key: 'annotationsView',
name: 'Annotations',
canView: function (selection) {
const availableTags = openmct.annotation.getAvailableTags();
if (availableTags.length < 1) {
return false;
}
return selection.length;
},
view: function (selection) {

View File

@@ -177,9 +177,10 @@ export default {
if (this.$refs.TagEditor) {
const clickedInsideTagEditor = this.$refs.TagEditor.contains(event.target);
if (!clickedInsideTagEditor) {
// Remove last tag when user clicks outside of TagSelection
this.addedTags.pop();
// Hide TagSelection and show "Add Tag" button
this.userAddingTag = false;
this.tagsChanged();
}
}
},

View File

@@ -13,24 +13,6 @@
/******************************* TAGS */
.c-tag {
/* merge conflict in 5247
border-radius: 10px; //TODO: convert to theme constant
display: inline-flex;
padding: 1px 10px; //TODO: convert to theme constant
> * + * {
margin-left: $interiorMargin;
}
&__remove-btn {
color: inherit !important;
display: none;
opacity: 0;
overflow: hidden;
padding: 1px !important;
@include transition(opacity);
width: 0;
*/
border-radius: $tagBorderRadius;
display: inline-flex;
overflow: hidden;
@@ -46,15 +28,15 @@
transition: $transIn;
width: 0;
&:hover {
opacity: 1;
}
&:hover {
opacity: 1;
}
}
/* SEARCH RESULTS */
&.--is-not-search-match {
opacity: 0.5;
}
/* SEARCH RESULTS */
&.--is-not-search-match {
opacity: 0.5;
}
}
.c-tag-holder {
@@ -69,31 +51,6 @@
/******************************* TAGS IN INSPECTOR / TAG SELECTION & APPLICATION */
.c-tag-applier {
/* merge conflict in fix-repaint-5247
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
> * + * {
margin-left: $interiorMargin;
}
&__add-btn {
&:before {
font-size: 0.9em;
}
}
.c-tag {
flex-direction: row;
align-items: center;
padding-right: 3px !important;
&__remove-btn {
display: block;
}
*/
$tagApplierPadding: 3px 6px;
@include tagHolder;
grid-column: 1 / 3;
@@ -124,6 +81,7 @@
min-height: auto !important;
padding: $tagApplierPadding;
}
}
}
.c-tag-btn__label {
@@ -132,21 +90,6 @@
/******************************* HOVERS */
.has-tag-applier {
/* merge conflict in fix-repaint-5247
$p: opacity, width;
// Apply this class to all components that should trigger tag removal btn on hover
.c-tag__remove-btn {
@include transition($prop: $p, $dur: $transOutTime);
}
&:hover {
.c-tag__remove-btn {
width: 1.1em;
opacity: 0.7;
}
}
}
*/
// Apply this class to all components that should trigger tag removal btn on hover
&:hover {
.c-tag {
@@ -177,4 +120,3 @@
}
}
}
}

View File

@@ -26,13 +26,12 @@
flex-wrap: wrap;
&__item {
$m: 1px;
cursor: pointer;
margin: 0 $m $m 0;
margin: 0 $interiorMarginSm $interiorMarginSm 0;
.c-object-label {
border-radius: $smallCr;
padding: 2px 3px;
padding: 0;
transition: $transOut;
&__type-icon {
width: auto;
@@ -40,8 +39,9 @@
min-width: auto;
}
@include hover() {
background: $colorItemTreeHoverBg;
&:hover {
transition: $transIn;
filter: $filterHov;
}
}
}

View File

@@ -45,7 +45,7 @@ export default class MoveAction {
}
navigateTo(objectPath) {
const urlPath = objectPath.reverse()
let urlPath = objectPath.reverse()
.map(object => this.openmct.objects.makeKeyString(object.identifier))
.join("/");
@@ -53,8 +53,8 @@ export default class MoveAction {
}
addToNewParent(child, newParent) {
const newParentKeyString = this.openmct.objects.makeKeyString(newParent.identifier);
const compositionCollection = this.openmct.composition.get(newParent);
let newParentKeyString = this.openmct.objects.makeKeyString(newParent.identifier);
let compositionCollection = this.openmct.composition.get(newParent);
this.openmct.objects.mutate(child, 'location', newParentKeyString);
compositionCollection.add(child);
@@ -63,7 +63,11 @@ export default class MoveAction {
async onSave(changes) {
this.startTransaction();
const inNavigationPath = this.inNavigationPath(this.object);
let inNavigationPath = this.inNavigationPath(this.object);
if (inNavigationPath && this.openmct.editor.isEditing()) {
this.openmct.editor.save();
}
const parentDomainObjectpath = changes.location || [this.parent];
const parent = parentDomainObjectpath[0];
@@ -87,15 +91,12 @@ export default class MoveAction {
}
let newObjectPath;
if (parentDomainObjectpath) {
newObjectPath = parentDomainObjectpath && [this.object].concat(parentDomainObjectpath);
} else {
const root = await this.openmct.objects.getRoot();
const rootCompositionCollection = this.openmct.composition.get(root);
const rootComposition = await rootCompositionCollection.load();
const rootChildCount = rootComposition.length;
newObjectPath = await this.openmct.objects.getOriginalPath(this.object.identifier);
let root = await this.openmct.objects.getRoot();
let rootChildCount = root.composition.length;
// if not multiple root children, remove root from path
if (rootChildCount < 2) {
@@ -107,7 +108,8 @@ export default class MoveAction {
}
removeFromOldParent(child) {
const compositionCollection = this.openmct.composition.get(this.oldParent);
let compositionCollection = this.openmct.composition.get(this.oldParent);
compositionCollection.remove(child);
}
@@ -164,9 +166,9 @@ export default class MoveAction {
return false;
}
const objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
const parentCandidateComposition = parentCandidate.composition;
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
const parentCandidateComposition = parentCandidate.composition;
if (parentCandidateComposition && parentCandidateComposition.indexOf(objectKeystring) !== -1) {
return false;
}
@@ -176,18 +178,20 @@ export default class MoveAction {
}
appliesTo(objectPath) {
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 isPersistable = this.openmct.objects.isPersistable(child.identifier);
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 isPersistable = this.openmct.objects.isPersistable(child.identifier);
if (parent?.locked || !isPersistable) {
if (child.locked || (parent && parent.locked) || !isPersistable) {
return false;
}
return parentType?.definition.creatable
&& childType?.definition.creatable
return parentType
&& parentType.definition.creatable
&& childType
&& childType.definition.creatable
&& Array.isArray(parent.composition);
}

View File

@@ -44,8 +44,7 @@ describe("The Move Action plugin", () => {
identifier: {
namespace: "",
key: "child-folder-object"
},
location: "parent-folder-object"
}
}
}
}).folder;
@@ -91,31 +90,6 @@ describe("The Move Action plugin", () => {
expect(moveAction).toBeDefined();
});
describe("when determining the object is applicable", () => {
beforeEach(() => {
spyOn(moveAction, 'appliesTo').and.callThrough();
});
it("should be true when the parent is creatable and has composition", () => {
let applies = moveAction.appliesTo([childObject, parentObject]);
expect(applies).toBe(true);
});
it("should be true when the child is locked and not an alias", () => {
childObject.locked = true;
let applies = moveAction.appliesTo([childObject, parentObject]);
expect(applies).toBe(true);
});
it("should still be true when the child is locked and is an alias", () => {
childObject.locked = true;
childObject.location = 'another-parent-folder-object';
let applies = moveAction.appliesTo([childObject, parentObject]);
expect(applies).toBe(true);
});
});
describe("when moving an object to a new parent and removing from the old parent", () => {
let unObserve;
beforeEach((done) => {

View File

@@ -236,7 +236,7 @@ export default {
sidebarCoversEntries: false,
filteredAndSortedEntries: [],
notebookAnnotations: {},
selectedEntryId: undefined,
selectedEntryId: '',
activeTransaction: false,
savingTransaction: false
};
@@ -381,10 +381,8 @@ export default {
});
},
updateSelection(selection) {
const keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
if (selection?.[0]?.[0]?.context?.targetDetails?.[keyString]?.entryId === undefined) {
this.selectedEntryId = undefined;
if (selection?.[0]?.[0]?.context?.targetDetails?.entryId === undefined) {
this.selectedEntryId = '';
}
},
async loadAnnotations() {
@@ -524,8 +522,6 @@ export default {
this.openmct.notifications.alert('Warning: unable to delete entry');
console.error(`unable to delete entry ${entryId} from section ${this.selectedSection}, page ${this.selectedPage}`);
this.cancelTransaction();
return;
}
@@ -538,15 +534,10 @@ export default {
emphasis: true,
callback: () => {
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
if (entries) {
entries.splice(entryPos, 1);
this.updateEntries(entries);
this.filterAndSortEntries();
this.removeAnnotations(entryId);
} else {
this.cancelTransaction();
}
entries.splice(entryPos, 1);
this.updateEntries(entries);
this.filterAndSortEntries();
this.removeAnnotations(entryId);
dialog.dismiss();
}
},

View File

@@ -54,7 +54,7 @@
class="c-ne__remove c-icon-button c-icon-button--major icon-trash"
title="Delete this entry"
tabindex="-1"
@click.stop.prevent="deleteEntry"
@click="deleteEntry"
>
</button>
</span>
@@ -466,10 +466,7 @@ export default {
if (!this.isSelectedEntry) {
$event.preventDefault();
// blur the previous focused entry if clicking on non selected entry input
const focusedElementId = document.activeElement?.id;
if (focusedElementId !== this.entry.id) {
document.activeElement.blur();
}
document.activeElement.blur();
}
},
editingEntry() {

View File

@@ -76,6 +76,13 @@
}
.c-list__item {
@include hover() {
[class*="__menu-indicator"] {
opacity: 0.7;
transition: $transIn;
}
}
> * + * {
margin-left: $interiorMargin;
}
@@ -85,10 +92,10 @@
}
&__menu-indicator {
// Not sure this is being used
flex: 0 0 auto;
font-size: 0.8em;
opacity: 0;
transition: $transOut;
}
}
}

View File

@@ -22,9 +22,7 @@
<template>
<div
v-if="loaded"
ref="plot"
class="gl-plot"
:class="{ 'js-series-data-loaded' : seriesDataLoaded }"
>
<slot></slot>
<div class="plot-wrapper-axis-and-display-area flex-elem grows">
@@ -349,9 +347,6 @@ export default {
const parentLeftTickWidth = this.parentYTickWidth.leftTickWidth;
return parentLeftTickWidth || leftTickWidth;
},
seriesDataLoaded() {
return ((this.pending === 0) && this.loaded);
}
},
watch: {
@@ -405,7 +400,7 @@ export default {
this.removeStatusListener = this.openmct.status.observe(this.domainObject.identifier, this.updateStatus);
this.openmct.objectViews.on('clearData', this.clearData);
this.$on('loadingComplete', this.loadAnnotations);
this.$on('loadingUpdated', this.loadAnnotations);
this.openmct.selection.on('change', this.updateSelection);
this.setTimeContext();
@@ -417,11 +412,10 @@ export default {
this.openmct.selection.off('change', this.updateSelection);
document.removeEventListener('keydown', this.handleKeyDown);
document.removeEventListener('keyup', this.handleKeyUp);
document.body.removeEventListener('click', this.cancelSelection);
this.destroy();
},
methods: {
async updateSelection(selection) {
updateSelection(selection) {
const selectionContext = selection?.[0]?.[0]?.context?.item;
// on clicking on a search result we highlight the annotation and zoom - we know it's an annotation result when isAnnotationSearchResult === true
// We shouldn't zoom when we're selecting existing annotations to view them or creating new annotations.
@@ -440,7 +434,15 @@ export default {
return;
}
await this.waitForAxesToLoad();
const currentXaxis = this.config.xAxis.get('displayRange');
const currentYaxis = this.config.yAxis.get('displayRange');
// when there is no plot data, the ranges can be undefined
// in which case we should not perform selection
if (!currentXaxis || !currentYaxis) {
return;
}
const selectedAnnotations = selection?.[0]?.[0]?.context?.annotations;
//This section is only for the annotations search results entry to displaying annotations
if (isAnnotationSearchResult) {
@@ -450,39 +452,10 @@ export default {
//This section is common to all entry points for annotation display
this.prepareExistingAnnotationSelection(selectedAnnotations);
},
cancelSelection(event) {
if (this.$refs?.plot) {
const clickedInsidePlot = this.$refs.plot.contains(event.target);
const clickedInsideInspector = event.target.closest('.js-inspector') !== null;
const clickedOption = event.target.closest('.js-autocomplete-options') !== null;
if (!clickedInsidePlot && !clickedInsideInspector && !clickedOption) {
this.rectangles = [];
this.annotationSelections = [];
this.selectPlot();
document.body.removeEventListener('click', this.cancelSelection);
}
}
},
waitForAxesToLoad() {
return new Promise(resolve => {
// When there is no plot data, the ranges can be undefined
// in which case we should not perform selection.
const currentXaxis = this.config.xAxis.get('displayRange');
const currentYaxis = this.config.yAxis.get('displayRange');
if (!currentXaxis || !currentYaxis) {
this.$once('loadingComplete', () => {
resolve();
});
} else {
resolve();
}
});
},
showAnnotationsFromSearchResults(selectedAnnotations) {
//Start section
if (selectedAnnotations?.length) {
// pause the plot if we haven't already so we can actually display
// the annotations
this.freeze();
// just use first annotation
const boundingBoxes = Object.values(selectedAnnotations[0].targets);
let minX = Number.MAX_SAFE_INTEGER;
@@ -699,9 +672,6 @@ export default {
stopLoading() {
this.pending -= 1;
this.updateLoading();
if (this.pending === 0) {
this.$emit('loadingComplete');
}
},
updateLoading() {
@@ -1295,8 +1265,6 @@ export default {
}
this.openmct.selection.select(selection, true);
document.body.addEventListener('click', this.cancelSelection);
},
selectNewPlotAnnotations(boundingBoxPerYAxis, pointsInBox, event) {
let targetDomainObjects = {};
@@ -1719,9 +1687,6 @@ export default {
},
resumeRealtimeData() {
// remove annotation selections
this.rectangles = [];
this.clearPanZoomHistory();
this.userViewportChangeEnd();
},

View File

@@ -603,20 +603,19 @@ export default {
const mainYAxisId = this.config.yAxis.get('id');
//There has to be at least one yAxis
const yAxisIds = [mainYAxisId].concat(this.config.additionalYAxes.map(yAxis => yAxis.get('id')));
// Repeat drawing for all yAxes
yAxisIds.filter(this.canDraw).forEach((id, yAxisIndex) => {
this.updateViewport(id);
this.drawSeries(id);
if (yAxisIndex === 0) {
yAxisIds.forEach((id) => {
if (this.canDraw(id)) {
this.updateViewport(id);
this.drawSeries(id);
this.drawRectangles(id);
}
this.drawHighlights(id);
this.drawHighlights(id);
// only draw these in fixed time mode or plot is paused
if (this.annotationViewingAndEditingAllowed) {
this.drawAnnotatedPoints(id);
this.drawAnnotationSelections(id);
// only draw these in fixed time mode or plot is paused
if (this.annotationViewingAndEditingAllowed) {
this.drawAnnotatedPoints(id);
this.drawAnnotationSelections(id);
}
}
});
},

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2022, United States Government
* Open MCT, Copyright (c) 2014-2023, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -20,8 +20,6 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
const SPECIAL_MESSAGE_TYPES = ['layout', 'flexible-layout'];
export default class RemoveAction {
#transaction;
@@ -41,37 +39,28 @@ export default class RemoveAction {
}
async invoke(objectPath) {
const child = objectPath[0];
const parent = objectPath[1];
let object = objectPath[0];
let parent = objectPath[1];
try {
await this.showConfirmDialog(child, parent);
await this.showConfirmDialog(object);
} catch (error) {
return; // form canceled, exit invoke
}
await this.removeFromComposition(parent, child, objectPath);
await this.removeFromComposition(parent, object);
if (this.inNavigationPath(child)) {
if (this.inNavigationPath(object)) {
this.navigateTo(objectPath.slice(1));
}
}
showConfirmDialog(child, parent) {
let message = 'Warning! This action will remove this object. Are you sure you want to continue?';
if (SPECIAL_MESSAGE_TYPES.includes(parent.type)) {
const type = this.openmct.types.get(parent.type);
const typeName = type.definition.name;
message = `Warning! This action will remove this item from the ${typeName}. Are you sure you want to continue?`;
}
showConfirmDialog(object) {
return new Promise((resolve, reject) => {
const dialog = this.openmct.overlays.dialog({
title: `Remove ${child.name}`,
let dialog = this.openmct.overlays.dialog({
title: `Remove ${object.name}`,
iconClass: 'alert',
message,
message: 'Warning! This action will remove this object. Are you sure you want to continue?',
buttons: [
{
label: 'OK',
@@ -105,13 +94,13 @@ export default class RemoveAction {
this.openmct.router.navigate('#/browse/' + urlPath);
}
async removeFromComposition(parent, child, objectPath) {
async removeFromComposition(parent, child) {
this.startTransaction();
const composition = this.openmct.composition.get(parent);
composition.remove(child);
if (!this.openmct.objects.isObjectPathToALink(child, objectPath)) {
if (!this.isAlias(child, parent)) {
this.openmct.objects.mutate(child, 'location', null);
}
@@ -122,6 +111,18 @@ export default class RemoveAction {
await this.saveTransaction();
}
isAlias(child, parent) {
if (parent === undefined) {
// then it's a root item, not an alias
return false;
}
const parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
const childLocation = child.location;
return childLocation !== parentKeyString;
}
appliesTo(objectPath) {
const parent = objectPath[1];
const parentType = parent && this.openmct.types.get(parent.type);
@@ -129,9 +130,9 @@ export default class RemoveAction {
const locked = child.locked ? child.locked : parent && parent.locked;
const isEditing = this.openmct.editor.isEditing();
const isPersistable = this.openmct.objects.isPersistable(child.identifier);
const isLink = this.openmct.objects.isObjectPathToALink(child, objectPath);
const isAlias = this.isAlias(child, parent);
if (!isLink && (locked || !isPersistable)) {
if (locked || (!isPersistable && !isAlias)) {
return false;
}
@@ -141,8 +142,9 @@ export default class RemoveAction {
}
}
return parentType?.definition.creatable
&& Array.isArray(parent?.composition);
return parentType
&& parentType.definition.creatable
&& Array.isArray(parent.composition);
}
startTransaction() {

View File

@@ -52,10 +52,6 @@ describe("The Remove Action plugin", () => {
objectKeyStrings: ['folder'],
overwrite: {
folder: {
identifier: {
namespace: "",
key: "parent-folder-object"
},
name: "Parent Folder",
composition: [childObject.identifier]
}
@@ -120,18 +116,10 @@ describe("The Remove Action plugin", () => {
expect(applies).toBe(true);
});
it("should be false when the child is locked and not an alias", () => {
it("should be false when the child is locked", () => {
childObject.locked = true;
childObject.location = 'parent-folder-object';
let applies = removeAction.appliesTo([childObject, parentObject]);
expect(applies).toBe(false);
});
it("should be true when the child is locked and IS an alias", () => {
childObject.locked = true;
childObject.location = 'other-folder-object';
let applies = removeAction.appliesTo([childObject, parentObject]);
expect(applies).toBe(true);
});
});
});

View File

@@ -49,10 +49,12 @@
background-size: 3px 30%;
background-color: $colorBodyBgSubtle;
box-shadow: inset rgba(black, 0.4) 0 1px 1px;
transition: $transOut;
svg text {
fill: $colorBodyFg;
stroke: $colorBodyBgSubtle;
transition: $transOut;
}
}

View File

@@ -68,6 +68,7 @@
&:hover,
&:active {
cursor: col-resize;
filter: $timeConductorAxisHoverFilter;
}
}
}
@@ -268,6 +269,7 @@
grid-column-gap: 3px;
grid-row-gap: 4px;
align-items: start;
filter: $filterMenu;
box-shadow: $shdwMenu;
padding: $interiorMargin;
position: absolute;

View File

@@ -72,7 +72,7 @@ $colorHeadBg: #262626;
$colorHeadFg: $colorBodyFg;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: lighten($colorKey, 10%);
$colorKeyHov: #26d8ff;
$colorKeyFilter: invert(36%) sepia(76%) saturate(2514%) hue-rotate(170deg) brightness(99%) contrast(101%);
$colorKeyFilterHov: invert(63%) sepia(88%) saturate(3029%) hue-rotate(154deg) brightness(101%) contrast(100%);
$colorKeySelectedBg: $colorKey;
@@ -86,7 +86,7 @@ $colorSelectedFg: pullForward($colorBodyFg, 20%);
// Object labels
$objectLabelTypeIconOpacity: 0.7;
$objectLabelNameColorFg: lighten($colorBodyFg, 10%);
$objectLabelNameFilter: brightness(1.3);
// Layout
$shellMainPad: 4px 0;
@@ -135,7 +135,7 @@ $colorPausedFg: #333;
// Base variations
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
$colorBodyBgSubtleHov: pullForward($colorBodyBg, 10%);
$colorBodyBgSubtleHov: pushBack($colorKey, 50%);
$colorKeySubtle: pushBack($colorKey, 10%);
// Time Colors
@@ -202,7 +202,6 @@ $colorTabsHolderBg: rgba(black, 0.2);
// Buttons and Controls
$colorBtnBg: pullForward($colorBodyBg, 10%);
$colorBtnBgHov: pullForward($colorBtnBg, 10%);
$shdwBtnHov: inset rgba(white, 10%) 0 0 0 100px;
$colorBtnFg: pullForward($colorBodyFg, 10%);
$colorBtnReverseFg: pullForward($colorBtnFg, 10%);
$colorBtnReverseBg: pullForward($colorBtnBg, 10%);
@@ -334,12 +333,6 @@ $colorLimitCyanBg: #4BA6B3;
$colorLimitCyanFg: #D3FAFF;
$colorLimitCyanIc: #6BEDFF;
// Events
$colorEventPurpleFg: #6433ff;
$colorEventRedFg: #cc0000;
$colorEventOrangeFg: orange;
$colorEventYellowFg: #ffcc00;
// Bubble colors
$colorInfoBubbleBg: #dddddd;
$colorInfoBubbleFg: #666;
@@ -471,8 +464,6 @@ $transInTime: 50ms;
$transOutTime: 250ms;
$transIn: all $transInTime ease-in-out;
$transOut: all $transOutTime ease-in-out;
$transInTransform: transform $transInTime ease-in-out;
$transOutTransform: transform $transOutTime ease-in-out;
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);

View File

@@ -337,12 +337,6 @@ $colorLimitCyanBg: #4BA6B3;
$colorLimitCyanFg: #D3FAFF;
$colorLimitCyanIc: #6BEDFF;
// Events
$colorEventPurpleFg: #6433ff;
$colorEventRedFg: #cc0000;
$colorEventOrangeFg: orange;
$colorEventYellowFg: #ffcc00;
// Bubble colors
$colorInfoBubbleBg: #dddddd;
$colorInfoBubbleFg: #666;
@@ -474,8 +468,6 @@ $transInTime: 50ms;
$transOutTime: 250ms;
$transIn: all $transInTime ease-in-out;
$transOut: all $transOutTime ease-in-out;
$transInTransform: transform $transInTime ease-in-out;
$transOutTransform: transform $transOutTime ease-in-out;
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);

View File

@@ -30,7 +30,6 @@ $mobileOverlayMargin: 20px;
$mobileMenuIconD: 25px;
$phoneItemH: floor(math.div($gridItemMobile, 4));
$tabletItemH: floor(math.div($gridItemMobile, 3));
$shellTimeConductorMobileH: 90px;
/************************** MOBILE TREE MENU DIMENSIONS */
$mobileTreeItemH: 35px;

View File

@@ -86,7 +86,7 @@ $colorSelectedFg: pullForward($colorBodyFg, 10%);
// Object labels
$objectLabelTypeIconOpacity: 0.5;
$objectLabelNameColorFg: darken($colorBodyFg, 10%);
$objectLabelNameFilter: brightness(0.9);
// Layout
$shellMainPad: 4px 0;
@@ -135,7 +135,7 @@ $colorPausedFg: #fff;
// Base variations
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
$colorBodyBgSubtleHov: pullForward($colorBodyBg, 10%);
$colorBodyBgSubtleHov: pushBack($colorKey, 50%);
$colorKeySubtle: pushBack($colorKey, 20%);
// Time Colors
@@ -202,7 +202,6 @@ $colorTabsHolderBg: rgba($colorBodyFg, 0.2);
// Buttons and Controls
$colorBtnBg: #aaa;
$colorBtnBgHov: pullForward($colorBtnBg, 10%);
$shdwBtnHov: inset rgba(white, 10%) 0 0 0 20px;
$colorBtnFg: #fff;
$colorBtnReverseFg: $colorBodyBg;
$colorBtnReverseBg: $colorBodyFg;
@@ -334,12 +333,6 @@ $colorLimitCyanBg: #4BA6B3;
$colorLimitCyanFg: #D3FAFF;
$colorLimitCyanIc: #1795c0;
// Events
$colorEventPurpleFg: #6433ff;
$colorEventRedFg: #cc0000;
$colorEventOrangeFg: orange;
$colorEventYellowFg: #ffcc00;
// Bubble colors
$colorInfoBubbleBg: $colorMenuBg;
$colorInfoBubbleFg: #666;
@@ -471,8 +464,6 @@ $transInTime: 50ms;
$transOutTime: 250ms;
$transIn: all $transInTime ease-in-out;
$transOut: all $transOutTime ease-in-out;
$transInTransform: transform $transInTime ease-in-out;
$transOutTransform: transform $transOutTime ease-in-out;
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);

View File

@@ -47,9 +47,6 @@ $overlayOuterMarginDialog: (5%, 20%);
$overlayInnerMargin: 25px;
$mainViewPad: 0px;
$treeNavArrowD: 20px;
$shellMainBrowseBarH: 22px;
$shellTimeConductorH: 55px;
$shellToolBarH: 29px;
/*************** Items */
$itemPadLR: 5px;
$gridItemDesk: 175px;

View File

@@ -565,7 +565,7 @@ select {
}
@include hover() {
box-shadow: $shdwBtnHov;
filter: $filterHov;
}
&.is-current {
@@ -725,6 +725,11 @@ select {
width: $d;
height: $d;
text-align: center;
transition: $transOut;
&:hover {
transition: $transIn;
}
&.is-selected {
border-width: 1px;
@@ -1079,7 +1084,7 @@ input[type="range"] {
// Controls that are in close proximity to an element they effect
&--show-on-hover {
// Hidden by default; requires a hover 1 - 3 levels above to display
@include transition(opacity, $transOutTime);
transition: $transOut;
opacity: 0;
pointer-events: none;
}
@@ -1091,7 +1096,7 @@ input[type="range"] {
> * > * > .c-local-controls--show-on-hover,
> * > * > * > .c-local-controls--show-on-hover
{
@include transition(opacity);
transition: $transIn;
opacity: 1;
pointer-events: inherit;
@@ -1104,7 +1109,6 @@ input[type="range"] {
.c-drop-hint {
// Used in Tabs View, Flexible Grid Layouts
@include abs();
@include transition($prop: background-color, $dur: $transOutTime);
background-color: $colorDropHintBg;
color: $colorDropHintFg;
border-radius: $basicCr;
@@ -1113,6 +1117,7 @@ input[type="range"] {
flex-direction: column;
justify-content: center;
align-items: center;
transition: $transOut;
z-index: 50;
&:not(.c-drop-hint--always-show) {
@@ -1137,11 +1142,13 @@ input[type="range"] {
.is-dragging &,
&.is-dragging {
pointer-events: inherit;
transition: $transIn;
opacity: 0.8;
}
.is-mouse-over &,
&.is-mouse-over {
transition: $transIn;
background-color: $colorDropHintBgHov;
opacity: 0.9;
}

View File

@@ -60,7 +60,7 @@
margin-right: 0;
min-width: 0;
overflow: hidden;
@include transition($prop: width, $dur: $transOutTime);
transition: $transOut;
width: 0;
.c-icon-button:before { font-size: 1em; }
@@ -78,7 +78,7 @@
&:hover {
.c-timer__controls {
@include transition($prop: width, $dur: $transOutTime); // On purpose: want this to take a bit longer
transition: $transOut; // On purpose: want this to take a bit longer
margin-right: $interiorMargin;
width: $ctrlW * 2;
}
@@ -168,6 +168,7 @@
.widget-rules-wrapper,
.widget-rule-content,
.w-widget-test-data-content {
transition: $transIn;
min-height: 0;
height: 0;
opacity: 0;
@@ -429,6 +430,7 @@
&:hover {
.l-autoflow-header .s-button.change-column-width {
transition: $transIn;
opacity: 1;
}
}
@@ -442,7 +444,7 @@
overflow: hidden;
}
.s-button.change-column-width {
@include transition($prop: opacity, $dur: $transOutTime);
transition: $transOut;
opacity: 0;
}
.l-filter {
@@ -735,7 +737,7 @@ body.desktop {
&:hover {
&:after {
background-color: $colorSplitterHover !important;
@include transition($prop: background-color, $dur: 150ms);
transiiton: background-color, 150ms;
}
}
}

View File

@@ -96,13 +96,6 @@
animation-timing-function: ease-in-out;
}
@mixin transition($prop: all, $dur: $transInTime, $timing: ease-in-out, $delay: 0ms) {
transition-property: $prop;
transition-duration: $dur;
transition-timing-function: $timing;
transition-delay: $delay;
}
/************************** VISUALS */
@mixin ancillaryIcon($d, $c) {
// Used for small icons used in combination with larger icons,
@@ -470,12 +463,22 @@
}
@mixin button($bg: $colorBtnBg, $fg: $colorBtnFg, $radius: $controlCr, $shdw: none) {
// Is this being used? Remove if not.
background: $bg;
color: $fg;
border-radius: $radius;
box-shadow: $shdw;
}
@mixin buttonBehavior() {
// Assign transition timings
transition: $transOut;
@include hover() {
transition: $transIn;
}
}
@mixin cControl() {
$fs: 1em;
@include userSelectNone();
@@ -512,18 +515,8 @@
}
}
@mixin cControlHov($styleConst: $shdwBtnHov) {
transition: box-shadow $transOutTime;
@include hover() {
transition: box-shadow $transInTime;
box-shadow: $styleConst !important;
}
}
@mixin cButton() {
@include cControl();
@include cControlHov();
@include themedButton();
border-radius: $controlCr;
color: $colorBtnFg;
@@ -535,6 +528,10 @@
margin-left: $interiorMarginSm;
}
@include hover() {
filter: $filterHov;
}
&[class*="--major"],
&[class*='is-active']{
background: $colorBtnMajorBg;
@@ -549,11 +546,11 @@
@mixin cClickIcon() {
@include cControl();
@include cControlHov();
color: $colorBodyFg;
cursor: pointer;
padding: 4px; // Bigger hit area
opacity: 0.7;
transition: $transOut;
transform-origin: center;
&[class*="--major"] {
@@ -563,6 +560,7 @@
@include hover() {
transform: scale(1.1);
transition: $transIn;
opacity: 1;
}
}
@@ -586,14 +584,21 @@
// Padding is included to facilitate a bigger hit area
// Make the icon bigger relative to its container
@include cControl();
@include cControlHov();
@include cClickIconButtonLayout();
background: none;
color: $colorClickIconButton;
box-shadow: none;
cursor: pointer;
transition: $transOut;
border-radius: $controlCr;
@include hover() {
transition: $transIn;
background: $colorClickIconButtonBgHov;
//color: $colorClickIconButtonFgHov;
filter: $filterHov;
}
&[class*="--major"] {
color: $colorBtnMajorBg !important;
}
@@ -649,6 +654,10 @@
border-color: $colorFg;
}
@include hover {
filter: $filterHov;
}
&--up, &--prev {
&:before {
transform: translate(-30%, -50%) rotate(135deg);

View File

@@ -192,12 +192,3 @@ tr {
@include isStatus($glyph: $glyph-icon-alert-rect, $color: $colorWarningLo);
}
}
.is-event {
&--purple { color: $colorEventPurpleFg !important; }
&--red { color: $colorEventRedFg !important; }
&--orange { color: $colorEventOrangeFg !important; }
&--yellow { color: $colorEventYellowFg !important; }
&--no-style { color: inherit; }
}

View File

@@ -208,8 +208,6 @@ div.c-table {
}
th, td {
width: 33%; // Needed to prevent size jumping as values dynamically update
overflow: hidden;
text-overflow: ellipsis;
}
td {

View File

@@ -2,6 +2,7 @@
.c-list-view {
tbody tr {
background: $colorListItemBg;
transition: $transOut;
}
td {
@@ -21,6 +22,8 @@
&:hover {
background: $colorListItemBgHov;
filter: $filterHov;
transition: $transIn;
}
}
}

View File

@@ -20,7 +20,7 @@
}
&__name {
color: $objectLabelNameColorFg;
filter: $objectLabelNameFilter;
}
}
}
@@ -61,7 +61,7 @@
pointer-events: none;
position: absolute;
top: 0; right: 0; bottom: auto; left: 0;
z-index: 10;
z-index: 2;
.c-object-label {
visibility: hidden;
@@ -99,8 +99,6 @@
}
}
}
&.c-so-view--flexible-layout,
&.c-so-view--layout {
// For sub-layouts with hidden frames, completely hide the header to avoid overlapping buttons
> .c-so-view__header {

View File

@@ -22,7 +22,6 @@
&__name {
@include ellipsize();
color: $objectLabelNameColorFg;
display: inline;
padding: 1px 0;
}

View File

@@ -1,7 +1,7 @@
@mixin visibleRegexButton {
opacity: 1;
padding: 1px 3px;
min-width: 24px;
width: 24px;
}
.c-search {
@@ -31,7 +31,7 @@
overflow: hidden;
padding: 1px 0;
transform-origin: left;
@include transition($prop: min-width, $dur: $transOutTime);
transition: $transOut;
width: 0;
&.is-active {
@@ -54,19 +54,8 @@
margin-left: 0;
}
&:before {
width: 0;
}
input[type='text'],
input[type='search'] {
margin-left: 0;
}
@include hover {
.c-search__clear-input {
display: block;
}
.c-search__clear-input {
display: block;
}
}
@@ -77,9 +66,10 @@
text-align: left;
}
@include hover {
&:hover {
.c-search__use-regex {
@include visibleRegexButton();
transition: $transIn;
}
}
}

View File

@@ -21,7 +21,7 @@
*****************************************************************************/
<template>
<div class="c-inspector js-inspector">
<div class="c-inspector">
<object-name />
<InspectorTabs
:selection="selection"

View File

@@ -25,6 +25,10 @@
}
&__selected {
.c-object-label__name {
filter: $objectLabelNameFilter;
}
.c-object-label__type-icon {
opacity: $objectLabelTypeIconOpacity;
}

View File

@@ -93,18 +93,9 @@
:persist-position="true"
>
<RecentObjectsList
ref="recentObjectsList"
class="l-shell__tree"
@openAndScrollTo="openAndScrollTo($event)"
/>
<button
slot="controls"
class="c-icon-button icon-clear-data"
aria-label="Clear Recently Viewed"
title="Clear Recently Viewed"
@click="handleClearRecentObjects"
>
</button>
</pane>
</multipane>
</pane>
@@ -288,9 +279,6 @@ export default {
handleTreeReset() {
this.triggerReset = !this.triggerReset;
},
handleClearRecentObjects() {
this.$refs.recentObjectsList.clearRecentObjects();
},
onStartResizing() {
this.isResizing = true;
},

View File

@@ -191,33 +191,6 @@ export default {
shouldTrackCompositionFor(domainObject, navigationPath) {
return this.compositionCollections[navigationPath] === undefined
&& this.openmct.composition.supportsComposition(domainObject);
},
/**
* Clears the Recent Objects list in localStorage and in the component.
* Before clearing, prompts the user to confirm the action with a dialog.
*/
clearRecentObjects() {
const dialog = this.openmct.overlays.dialog({
title: 'Clear Recently Viewed Objects',
iconClass: 'alert',
message: 'This action will clear the Recently Viewed Objects list. Are you sure you want to continue?',
buttons: [
{
label: 'OK',
callback: () => {
localStorage.removeItem(LOCAL_STORAGE_KEY__RECENT_OBJECTS);
this.recents = [];
dialog.dismiss();
}
},
{
label: 'Cancel',
callback: () => {
dialog.dismiss();
}
}
]
});
}
}
};

View File

@@ -20,7 +20,7 @@
z-index: 70;
[class*="__icon"] {
filter: $colorKeyFilter;
filter: $colorKeyFilter;
}
[class*="__item-description"] {

View File

@@ -35,7 +35,7 @@
min-height: 0;
max-height: 15%;
overflow: hidden;
@include transition(min-height);
transition: $transIn;
&.is-expanded {
min-height: 100px;
@@ -65,7 +65,8 @@
}
&__pane-tree,
&__pane-inspector {
&__pane-inspector,
&__pane-main {
.l-pane__contents {
display: flex;
flex-flow: column nowrap;
@@ -73,7 +74,8 @@
}
}
&__pane-tree {
&__pane-tree,
&__pane-main {
.l-pane__contents {
> * {
flex: 0 0 auto;
@@ -87,37 +89,6 @@
&__pane-main {
.l-pane__header { display: none; }
.l-pane__contents {
.l-shell__main-.l-shell__main-view-browse-bar {
position: relative;
}
// Using `position: absolute` due to flex having repaint issues with the Time Conductor, #5247
.l-shell__time-conductor,
.l-shell__main-container {
position: absolute;
left: 0;
right: 0;
height: auto;
width: auto;
}
.l-shell__main-container {
top: $shellMainBrowseBarH + $interiorMarginLg;
bottom: $shellTimeConductorH + $interiorMargin;
}
@include phonePortrait() {
.l-shell__main-container {
bottom: $shellTimeConductorMobileH + $interiorMargin;
}
}
.l-shell__time-conductor {
bottom: 0;
}
}
}
body.mobile & {
@@ -336,7 +307,6 @@
height: $p + 24px; // Need to standardize the height
justify-content: space-between;
padding: $p;
z-index: 2;
}
&__resizing {
@@ -362,7 +332,6 @@
box-shadow: $colorBodyBg 0 0 0 1px, $editUIAreaShdw;
margin-left: $m;
margin-right: $m;
top: $shellToolBarH + $shellMainBrowseBarH + $interiorMarginLg !important;
&[s-selected] {
// Provide a clearer selection context articulation for the main edit area
@@ -439,6 +408,10 @@
flex: 0 1 auto;
}
.c-object-label__name {
filter: $objectLabelNameFilter;
}
.c-object-label__type-icon {
opacity: $objectLabelTypeIconOpacity;
}
@@ -460,7 +433,7 @@
/************************** DRAWER */
.c-drawer {
/* Sliding overlay or push element to contain things
/* New sliding overlay or push element to contain things
* Designed for mobile and compact desktop scenarios
* Variations:
* --overlays: position absolute, overlays neighboring elements
@@ -469,8 +442,7 @@
* &.is-expanded: applied when expanded.
*/
$transProps: width, min-width, height, min-height;
transition: $transOut;
min-height: 0;
min-width: 0;
overflow: hidden;
@@ -483,12 +455,11 @@
}
&.c-drawer--align-left {
@include transition($prop: $transProps, $dur: $transOutTime);
height: 100%;
}
&.c-drawer--align-top {
@include transition($prop: $transProps, $dur: $transOutTime);
// Need anything here?
}
&.c-drawer--overlays {

View File

@@ -97,7 +97,7 @@
@include hover {
background: $colorItemTreeHoverBg;
//filter: $filterHov; // FILTER REMOVAL, CONVERT TO THEME CONSTANT
filter: $filterHov;
}
&.is-navigated-object,
@@ -192,6 +192,14 @@
}
}
}
&__item__label {
@include desktop {
&:hover {
filter: $filterHov;
}
}
}
}
.is-editing .is-navigated-object {

View File

@@ -355,18 +355,17 @@ export default {
this.abortItemLoad(path);
}
const pathIndex = this.openTreeItems.indexOf(path);
let pathIndex = this.openTreeItems.indexOf(path);
if (pathIndex === -1) {
return;
}
this.treeItems = this.treeItems.filter((item) => {
const otherPath = item.navigationPath;
if (otherPath !== path
&& this.isTreeItemAChildOf(otherPath, path)) {
this.destroyObserverByPath(otherPath);
this.destroyMutableByPath(otherPath);
this.treeItems = this.treeItems.filter((checkItem) => {
if (checkItem.navigationPath !== path
&& checkItem.navigationPath.includes(path)) {
this.destroyObserverByPath(checkItem.navigationPath);
this.destroyMutableByPath(checkItem.navigationPath);
return false;
}
@@ -451,14 +450,13 @@ export default {
}, Promise.resolve()).then(() => {
if (this.isSelectorTree) {
let item = this.getTreeItemByPath(navigationPath);
// If item is missing due to error in object creation,
// walk up the navigationPath until we find an item
while (!item && navigationPath !== '') {
let item = this.getTreeItemByPath(navigationPath);
while (!item) {
const startIndex = 0;
const endIndex = navigationPath.lastIndexOf('/');
navigationPath = navigationPath.substring(startIndex, endIndex);
item = this.getTreeItemByPath(navigationPath);
}
@@ -961,24 +959,6 @@ export default {
isTreeItemPathOpen(path) {
return this.openTreeItems.includes(path);
},
isTreeItemAChildOf(childNavigationPath, parentNavigationPath) {
const childPathKeys = childNavigationPath.split('/');
const parentPathKeys = parentNavigationPath.split('/');
// If child path is shorter than or same length as
// the parent path, then it's not a child.
if (childPathKeys.length <= parentPathKeys.length) {
return false;
}
for (let i = 0; i < parentPathKeys.length; i++) {
if (childPathKeys[i] !== parentPathKeys[i]) {
return false;
}
}
return true;
},
getElementStyleValue(el, style) {
if (!el) {
return;

View File

@@ -107,10 +107,10 @@
/************************************************ DESKTOP STYLES */
body.desktop & {
&__handle {
background-color: $colorSplitterBg;
background: $colorSplitterBg;
display: block;
position: absolute;
@include transition(background-color, $transOutTime);
transition: $transOut;
&:before {
// Extended hit area
@@ -121,8 +121,8 @@
}
&:hover {
background-color: $colorSplitterHover;
@include transition(background-color);
background: $colorSplitterHover;
transition: $transIn;
}
}
@@ -142,14 +142,14 @@
[class*="expand-button"] {
display: none; // Hidden by default
background-color: $splitterCollapsedBtnColorBg;
background: $splitterCollapsedBtnColorBg;
color: $splitterCollapsedBtnColorFg;
font-size: 0.9em;
&:hover {
background-color: $splitterCollapsedBtnColorBgHov;
background: $splitterCollapsedBtnColorBgHov;
color: inherit;
@include transition(background-color);
transition: $transIn;
}
}
@@ -163,7 +163,7 @@
.l-pane {
&__handle {
background-color: $colorSplitterHover;
background: $colorSplitterHover;
}
}
}

View File

@@ -129,11 +129,9 @@ export default {
mounted() {
this.previewAction = new PreviewAction(this.openmct);
this.previewAction.on('isVisible', this.togglePreviewState);
this.clickedPlotAnnotation = this.clickedPlotAnnotation.bind(this);
},
destroyed() {
this.previewAction.off('isVisible', this.togglePreviewState);
this.openmct.selection.off('change', this.clickedPlotAnnotation);
},
methods: {
clickedResult(event) {
@@ -143,19 +141,15 @@ export default {
this.preview(objectPath);
} else {
const resultUrl = identifierToString(this.openmct, objectPath);
if (!this.openmct.router.isNavigatedObject(objectPath)) {
// if we're not on the correct page, navigate to the object,
// then wait for the selection event to fire before issuing a new selection
if (this.result.annotationType === this.openmct.annotation.ANNOTATION_TYPES.PLOT_SPATIAL) {
this.openmct.selection.on('change', this.clickedPlotAnnotation);
}
this.openmct.router.navigate(resultUrl);
} else {
// if this is the navigated object, then we are already on the correct page
// and just need to issue the selection event
this.openmct.router.navigate(resultUrl);
}
if (this.result.annotationType === this.openmct.annotation.ANNOTATION_TYPES.PLOT_SPATIAL) {
//wait a beat for the navigation
setTimeout(() => {
this.clickedPlotAnnotation();
}
}, 100);
}
},
preview(objectPath) {
@@ -164,8 +158,6 @@ export default {
}
},
clickedPlotAnnotation() {
this.openmct.selection.off('change', this.clickedPlotAnnotation);
const targetDetails = {};
const targetDomainObjects = {};
Object.entries(this.result.targets).forEach(([key, value]) => {

View File

@@ -43,8 +43,8 @@
.s-button,
.c-button {
// Make <a> in label look like buttons
@include transition(background-color);
background-color: transparent;
transition: $transIn;
background: transparent;
border: 1px solid rgba($colorIndicatorMenuFg, 0.5);
border-radius: $controlCr;
box-sizing: border-box;
@@ -53,8 +53,8 @@
height: auto;
line-height: normal;
padding: 0 2px;
@include hover {
background-color: rgba($colorIndicatorMenuFg, 0.1);
&:hover {
background: rgba($colorIndicatorMenuFg, 0.1);
border-color: rgba($colorIndicatorMenuFg, 0.75);
color: $colorIndicatorMenuFgHov;
}

View File

@@ -49,19 +49,9 @@ export default {
},
computed: {
highlightedText() {
const highlight = this.highlight;
let regex = new RegExp(`(?<!<[^>]*)(${this.highlight})`, 'gi');
const normalCharsRegex = /^[^A-Za-z0-9]+$/g;
const newHighLight = normalCharsRegex.test(highlight)
? `\\${highlight}`
: highlight;
const highlightRegex = new RegExp(`(?<!<[^>]*)(${newHighLight})`, 'gi');
const replacement = `<span class="${this.highlightClass}">${highlight}</span>`;
return this.text.replace(highlightRegex, replacement);
return this.text.replace(regex, `<span class="${this.highlightClass}">${this.highlight}</span>`);
}
}
};