mirror of
https://github.com/nasa/openmct.git
synced 2025-06-14 13:18:15 +00:00
feat: Inspector tabs (#6137)
* framework for all inspector views being provided * move elements view to plugin * move location view into plugin * move styles view into plugin * move properties view into plugin * install inspector views in index.html * rename filters inspector view provider for tab * finish elements view as plugin * finish location view as plugin * finish properties view as plugin * finish styles view as plugin * point main styles to new plugins * finish inspector tab and views components * fix paths for styles views * fix path issues * rename fault management inspector view fix unit test * fix paths for unit tests * rename bar graph inspector view fix unit test * rename plots inspector view fix unit test * inspector views installed in mct.js * sort inspector views by priority * make name required for inspector tabs * priority changes * only show filters tab if filters exist * object renamed to domainObject * remove dead code * select first tab if selected tab becomes hidden * bandaid fix to get e2e working * also apply bandaid to this test * [a11y] Basic ARIA tab role for Inspector panels * test(e2e): better selectors for scatterPlot test * test(e2e): fix search test selector * pass key and glyph to views * use key for tabs identification * high + 1 priority for object specific views * Closes #6118 - Significant layout and behavior refinements to Inspector tabs. - New theme constants for tabs. - Tabs in Tab Views updated to use theme constants. * Closes #6118 - Refinement to look of Inspector tabs. - Shortened names in many *InspectorViewProvider.js files. - WIP adding glyph capability, display not yet wired up. * Closes #6118 - Tightened H2 spacing in Inspector. * move annotations into plugin * register annotations view provider * move tags inside annotations * fix paths * move element item group into plugin * move PlotElementsPool view into plugin * plots has a different element view * fix paths for plot elements pool * fix: `role=` instead of `aria-role=` 🤦♂️ * test(e2e): fix tab locators * move location views into properties tab view * include location.scss * move location into properties tab * fix html for location within properties view * retain selected tab on new selection * refresh view of same tab with new selection * add browse mode inspector view for alphanumerics * fix prop passing * removed vestigial code * fix inspector tab selection * remove timeouts and unnessecary awaits * test: assert checkbox status before checking * add selectInspectorTab to general app actions * use selectInspectorTabs from appActions * need to pass page to playwright function * select the correct tab * fix plan unit test * fix plots tests by clicking on correct tab --------- Co-authored-by: Jesse Mazzella <jesse.d.mazzella@nasa.gov> Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com> Co-authored-by: John Hill <john.c.hill@nasa.gov> Co-authored-by: Scott Bell <scott@traclabs.com>
This commit is contained in:
@ -383,6 +383,25 @@ async function setEndOffset(page, offset) {
|
|||||||
await setTimeConductorOffset(page, offset, endOffsetButton);
|
await setTimeConductorOffset(page, offset, endOffsetButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects an inspector tab based on the provided tab name
|
||||||
|
*
|
||||||
|
* @param {import('@playwright/test').Page} page
|
||||||
|
* @param {String} name the name of the tab
|
||||||
|
*/
|
||||||
|
async function selectInspectorTab(page, name) {
|
||||||
|
const inspectorTabs = page.getByRole('tablist');
|
||||||
|
const inspectorTab = inspectorTabs.getByTitle(name);
|
||||||
|
const inspectorTabClass = await inspectorTab.getAttribute('class');
|
||||||
|
const isSelectedInspectorTab = inspectorTabClass.includes('is-current');
|
||||||
|
|
||||||
|
// do not click a tab that is already selected or it will timeout your test
|
||||||
|
// do to a { pointer-events: none; } on selected tabs
|
||||||
|
if (!isSelectedInspectorTab) {
|
||||||
|
await inspectorTab.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createDomainObjectWithDefaults,
|
createDomainObjectWithDefaults,
|
||||||
@ -396,5 +415,6 @@ module.exports = {
|
|||||||
setFixedTimeMode,
|
setFixedTimeMode,
|
||||||
setRealTimeMode,
|
setRealTimeMode,
|
||||||
setStartOffset,
|
setStartOffset,
|
||||||
setEndOffset
|
setEndOffset,
|
||||||
|
selectInspectorTab
|
||||||
};
|
};
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
Testsuite for plot autoscale.
|
Testsuite for plot autoscale.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const { selectInspectorTab } = require('../../../../appActions');
|
||||||
const { test, expect } = require('../../../../pluginFixtures');
|
const { test, expect } = require('../../../../pluginFixtures');
|
||||||
test.use({
|
test.use({
|
||||||
viewport: {
|
viewport: {
|
||||||
@ -50,6 +51,7 @@ test.describe('Autoscale', () => {
|
|||||||
// enter edit mode
|
// enter edit mode
|
||||||
await page.click('button[title="Edit"]');
|
await page.click('button[title="Edit"]');
|
||||||
|
|
||||||
|
await selectInspectorTab(page, 'Config');
|
||||||
await turnOffAutoscale(page);
|
await turnOffAutoscale(page);
|
||||||
|
|
||||||
await setUserDefinedMinAndMax(page, '-2', '2');
|
await setUserDefinedMinAndMax(page, '-2', '2');
|
||||||
|
@ -26,6 +26,8 @@ necessarily be used for reference when writing new tests in this area.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const { test, expect } = require('../../../../pluginFixtures');
|
const { test, expect } = require('../../../../pluginFixtures');
|
||||||
|
const { selectInspectorTab } = require('../../../../appActions');
|
||||||
|
|
||||||
test.describe('Log plot tests', () => {
|
test.describe('Log plot tests', () => {
|
||||||
test('Log Plot ticks are functionally correct in regular and log mode and after refresh', async ({ page, openmctConfig }) => {
|
test('Log Plot ticks are functionally correct in regular and log mode and after refresh', async ({ page, openmctConfig }) => {
|
||||||
const { myItemsFolderName } = openmctConfig;
|
const { myItemsFolderName } = openmctConfig;
|
||||||
@ -36,6 +38,7 @@ test.describe('Log plot tests', () => {
|
|||||||
await makeOverlayPlot(page, myItemsFolderName);
|
await makeOverlayPlot(page, myItemsFolderName);
|
||||||
await testRegularTicks(page);
|
await testRegularTicks(page);
|
||||||
await enableEditMode(page);
|
await enableEditMode(page);
|
||||||
|
await selectInspectorTab(page, 'Config');
|
||||||
await enableLogMode(page);
|
await enableLogMode(page);
|
||||||
await testLogTicks(page);
|
await testLogTicks(page);
|
||||||
await disableLogMode(page);
|
await disableLogMode(page);
|
||||||
@ -186,6 +189,7 @@ async function enableEditMode(page) {
|
|||||||
*/
|
*/
|
||||||
async function enableLogMode(page) {
|
async function enableLogMode(page) {
|
||||||
// turn on log mode
|
// turn on log mode
|
||||||
|
await expect(page.getByRole('listitem').filter({ hasText: 'Log mode' }).getByRole('checkbox')).not.toBeChecked();
|
||||||
await page.getByRole('listitem').filter({ hasText: 'Log mode' }).getByRole('checkbox').check();
|
await page.getByRole('listitem').filter({ hasText: 'Log mode' }).getByRole('checkbox').check();
|
||||||
// await page.locator('text=Y Axis Label Log mode Auto scale Padding >> input[type="checkbox"]').first().check();
|
// await page.locator('text=Y Axis Label Log mode Auto scale Padding >> input[type="checkbox"]').first().check();
|
||||||
}
|
}
|
||||||
@ -195,6 +199,7 @@ async function enableLogMode(page) {
|
|||||||
*/
|
*/
|
||||||
async function disableLogMode(page) {
|
async function disableLogMode(page) {
|
||||||
// turn off log mode
|
// turn off log mode
|
||||||
|
await expect(page.getByRole('listitem').filter({ hasText: 'Log mode' }).getByRole('checkbox')).toBeChecked();
|
||||||
await page.getByRole('listitem').filter({ hasText: 'Log mode' }).getByRole('checkbox').uncheck();
|
await page.getByRole('listitem').filter({ hasText: 'Log mode' }).getByRole('checkbox').uncheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ necessarily be used for reference when writing new tests in this area.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const { test, expect } = require('../../../../pluginFixtures');
|
const { test, expect } = require('../../../../pluginFixtures');
|
||||||
const { createDomainObjectWithDefaults } = require('../../../../appActions');
|
const { createDomainObjectWithDefaults, selectInspectorTab } = require('../../../../appActions');
|
||||||
|
|
||||||
test.describe('Overlay Plot', () => {
|
test.describe('Overlay Plot', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
@ -45,6 +45,8 @@ test.describe('Overlay Plot', () => {
|
|||||||
|
|
||||||
await page.goto(overlayPlot.url);
|
await page.goto(overlayPlot.url);
|
||||||
|
|
||||||
|
await selectInspectorTab(page, 'Config');
|
||||||
|
|
||||||
// navigate to plot series color palette
|
// navigate to plot series color palette
|
||||||
await page.click('.l-browse-bar__actions__edit');
|
await page.click('.l-browse-bar__actions__edit');
|
||||||
await page.locator('li.c-tree__item.menus-to-left .c-disclosure-triangle').click();
|
await page.locator('li.c-tree__item.menus-to-left .c-disclosure-triangle').click();
|
||||||
@ -89,22 +91,7 @@ test.describe('Overlay Plot', () => {
|
|||||||
await page.goto(overlayPlot.url);
|
await page.goto(overlayPlot.url);
|
||||||
await page.click('button[title="Edit"]');
|
await page.click('button[title="Edit"]');
|
||||||
|
|
||||||
// Expand the elements pool vertically
|
await selectInspectorTab(page, 'Elements');
|
||||||
await page.locator('.l-pane.l-pane--vertical-handle-before', {
|
|
||||||
hasText: 'Elements'
|
|
||||||
}).locator('.l-pane__handle').hover();
|
|
||||||
await page.mouse.down();
|
|
||||||
await page.mouse.move(0, 100);
|
|
||||||
await page.mouse.up();
|
|
||||||
|
|
||||||
const yAxis1PropertyGroup = page.locator('[aria-label="Y Axis Properties"]');
|
|
||||||
const yAxis2PropertyGroup = page.locator('[aria-label="Y Axis 2 Properties"]');
|
|
||||||
const yAxis3PropertyGroup = page.locator('[aria-label="Y Axis 3 Properties"]');
|
|
||||||
|
|
||||||
// Assert that Y Axis 1 property group is visible only
|
|
||||||
await expect(yAxis1PropertyGroup).toBeVisible();
|
|
||||||
await expect(yAxis2PropertyGroup).toBeHidden();
|
|
||||||
await expect(yAxis3PropertyGroup).toBeHidden();
|
|
||||||
|
|
||||||
// Drag swg a, c, e into Y Axis 2
|
// Drag swg a, c, e into Y Axis 2
|
||||||
await page.locator(`#inspector-elements-tree >> text=${swgA.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
|
await page.locator(`#inspector-elements-tree >> text=${swgA.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
|
||||||
@ -112,6 +99,12 @@ test.describe('Overlay Plot', () => {
|
|||||||
await page.locator(`#inspector-elements-tree >> text=${swgE.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
|
await page.locator(`#inspector-elements-tree >> text=${swgE.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
|
||||||
|
|
||||||
// Assert that Y Axis 1 and Y Axis 2 property groups are visible only
|
// Assert that Y Axis 1 and Y Axis 2 property groups are visible only
|
||||||
|
await selectInspectorTab(page, 'Config');
|
||||||
|
|
||||||
|
const yAxis1PropertyGroup = page.locator('[aria-label="Y Axis Properties"]');
|
||||||
|
const yAxis2PropertyGroup = page.locator('[aria-label="Y Axis 2 Properties"]');
|
||||||
|
const yAxis3PropertyGroup = page.locator('[aria-label="Y Axis 3 Properties"]');
|
||||||
|
|
||||||
await expect(yAxis1PropertyGroup).toBeVisible();
|
await expect(yAxis1PropertyGroup).toBeVisible();
|
||||||
await expect(yAxis2PropertyGroup).toBeVisible();
|
await expect(yAxis2PropertyGroup).toBeVisible();
|
||||||
await expect(yAxis3PropertyGroup).toBeHidden();
|
await expect(yAxis3PropertyGroup).toBeHidden();
|
||||||
@ -120,15 +113,21 @@ test.describe('Overlay Plot', () => {
|
|||||||
const yAxis2Group = page.getByLabel("Y Axis 2");
|
const yAxis2Group = page.getByLabel("Y Axis 2");
|
||||||
const yAxis3Group = page.getByLabel("Y Axis 3");
|
const yAxis3Group = page.getByLabel("Y Axis 3");
|
||||||
|
|
||||||
|
await selectInspectorTab(page, 'Elements');
|
||||||
|
|
||||||
// Drag swg b into Y Axis 3
|
// Drag swg b into Y Axis 3
|
||||||
await page.locator(`#inspector-elements-tree >> text=${swgB.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 3"]'));
|
await page.locator(`#inspector-elements-tree >> text=${swgB.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 3"]'));
|
||||||
|
|
||||||
// Assert that all Y Axis property groups are visible
|
// Assert that all Y Axis property groups are visible
|
||||||
|
await selectInspectorTab(page, 'Config');
|
||||||
|
|
||||||
await expect(yAxis1PropertyGroup).toBeVisible();
|
await expect(yAxis1PropertyGroup).toBeVisible();
|
||||||
await expect(yAxis2PropertyGroup).toBeVisible();
|
await expect(yAxis2PropertyGroup).toBeVisible();
|
||||||
await expect(yAxis3PropertyGroup).toBeVisible();
|
await expect(yAxis3PropertyGroup).toBeVisible();
|
||||||
|
|
||||||
// Verify that the elements are in the correct buckets and in the correct order
|
// Verify that the elements are in the correct buckets and in the correct order
|
||||||
|
await selectInspectorTab(page, 'Elements');
|
||||||
|
|
||||||
expect(yAxis1Group.getByRole('listitem', { name: swgD.name })).toBeTruthy();
|
expect(yAxis1Group.getByRole('listitem', { name: swgD.name })).toBeTruthy();
|
||||||
expect(yAxis1Group.getByRole('listitem').nth(0).getByText(swgD.name)).toBeTruthy();
|
expect(yAxis1Group.getByRole('listitem').nth(0).getByText(swgD.name)).toBeTruthy();
|
||||||
expect(yAxis2Group.getByRole('listitem', { name: swgE.name })).toBeTruthy();
|
expect(yAxis2Group.getByRole('listitem', { name: swgE.name })).toBeTruthy();
|
||||||
@ -154,8 +153,10 @@ test.describe('Overlay Plot', () => {
|
|||||||
await page.goto(overlayPlot.url);
|
await page.goto(overlayPlot.url);
|
||||||
await page.click('button[title="Edit"]');
|
await page.click('button[title="Edit"]');
|
||||||
|
|
||||||
|
await selectInspectorTab(page, 'Elements');
|
||||||
|
|
||||||
await page.locator(`#inspector-elements-tree >> text=${swgA.name}`).click();
|
await page.locator(`#inspector-elements-tree >> text=${swgA.name}`).click();
|
||||||
await page.locator('.js-overlay canvas').nth(1);
|
|
||||||
const plotPixelSize = await getCanvasPixelsWithData(page);
|
const plotPixelSize = await getCanvasPixelsWithData(page);
|
||||||
expect(plotPixelSize).toBeGreaterThan(0);
|
expect(plotPixelSize).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
@ -25,6 +25,7 @@ Tests to verify log plot functionality. Note this test suite if very much under
|
|||||||
necessarily be used for reference when writing new tests in this area.
|
necessarily be used for reference when writing new tests in this area.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const { selectInspectorTab } = require('../../../../appActions');
|
||||||
const { test, expect } = require('../../../../pluginFixtures');
|
const { test, expect } = require('../../../../pluginFixtures');
|
||||||
|
|
||||||
test.describe('Legend color in sync with plot color', () => {
|
test.describe('Legend color in sync with plot color', () => {
|
||||||
@ -33,6 +34,8 @@ test.describe('Legend color in sync with plot color', () => {
|
|||||||
|
|
||||||
// navigate to plot series color palette
|
// navigate to plot series color palette
|
||||||
await page.click('.l-browse-bar__actions__edit');
|
await page.click('.l-browse-bar__actions__edit');
|
||||||
|
await selectInspectorTab(page, 'Config');
|
||||||
|
|
||||||
await page.locator('li.c-tree__item.menus-to-left .c-disclosure-triangle').click();
|
await page.locator('li.c-tree__item.menus-to-left .c-disclosure-triangle').click();
|
||||||
await page.locator('.c-click-swatch--menu').click();
|
await page.locator('.c-click-swatch--menu').click();
|
||||||
await page.locator('.c-palette__item[style="background: rgb(255, 166, 61);"]').click();
|
await page.locator('.c-palette__item[style="background: rgb(255, 166, 61);"]').click();
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const { test, expect } = require('../../../../pluginFixtures');
|
const { test, expect } = require('../../../../pluginFixtures');
|
||||||
const { createDomainObjectWithDefaults } = require('../../../../appActions');
|
const { createDomainObjectWithDefaults, selectInspectorTab } = require('../../../../appActions');
|
||||||
const uuid = require('uuid').v4;
|
const uuid = require('uuid').v4;
|
||||||
|
|
||||||
test.describe('Scatter Plot', () => {
|
test.describe('Scatter Plot', () => {
|
||||||
@ -40,8 +40,8 @@ test.describe('Scatter Plot', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Can add and remove telemetry sources', async ({ page }) => {
|
test('Can add and remove telemetry sources', async ({ page }) => {
|
||||||
const editButtonLocator = page.locator('button[title="Edit"]');
|
const editButton = page.locator('button[title="Edit"]');
|
||||||
const saveButtonLocator = page.locator('button[title="Save"]');
|
const saveButton = page.locator('button[title="Save"]');
|
||||||
|
|
||||||
// Create a sine wave generator within the scatter plot
|
// Create a sine wave generator within the scatter plot
|
||||||
const swg1 = await createDomainObjectWithDefaults(page, {
|
const swg1 = await createDomainObjectWithDefaults(page, {
|
||||||
@ -53,9 +53,10 @@ test.describe('Scatter Plot', () => {
|
|||||||
// Navigate to the scatter plot and verify that
|
// Navigate to the scatter plot and verify that
|
||||||
// the SWG appears in the elements pool
|
// the SWG appears in the elements pool
|
||||||
await page.goto(scatterPlot.url);
|
await page.goto(scatterPlot.url);
|
||||||
await editButtonLocator.click();
|
await editButton.click();
|
||||||
|
await selectInspectorTab(page, 'Elements');
|
||||||
await expect.soft(page.locator(`#inspector-elements-tree >> text=${swg1.name}`)).toBeVisible();
|
await expect.soft(page.locator(`#inspector-elements-tree >> text=${swg1.name}`)).toBeVisible();
|
||||||
await saveButtonLocator.click();
|
await saveButton.click();
|
||||||
await page.locator('li[title="Save and Finish Editing"]').click();
|
await page.locator('li[title="Save and Finish Editing"]').click();
|
||||||
|
|
||||||
// Create another sine wave generator within the scatter plot
|
// Create another sine wave generator within the scatter plot
|
||||||
@ -72,10 +73,13 @@ test.describe('Scatter Plot', () => {
|
|||||||
// Navigate to the scatter plot and verify that the new SWG
|
// Navigate to the scatter plot and verify that the new SWG
|
||||||
// appears in the elements pool and the old one is gone
|
// appears in the elements pool and the old one is gone
|
||||||
await page.goto(scatterPlot.url);
|
await page.goto(scatterPlot.url);
|
||||||
await editButtonLocator.click();
|
await editButton.click();
|
||||||
|
|
||||||
|
// Click the "Elements" tab
|
||||||
|
await selectInspectorTab(page, 'Elements');
|
||||||
await expect.soft(page.locator(`#inspector-elements-tree >> text=${swg1.name}`)).toBeHidden();
|
await expect.soft(page.locator(`#inspector-elements-tree >> text=${swg1.name}`)).toBeHidden();
|
||||||
await expect.soft(page.locator(`#inspector-elements-tree >> text=${swg2.name}`)).toBeVisible();
|
await expect.soft(page.locator(`#inspector-elements-tree >> text=${swg2.name}`)).toBeVisible();
|
||||||
await saveButtonLocator.click();
|
await saveButton.click();
|
||||||
|
|
||||||
// Right click on the new SWG in the elements pool and delete it
|
// Right click on the new SWG in the elements pool and delete it
|
||||||
await page.locator(`#inspector-elements-tree >> text=${swg2.name}`).click({
|
await page.locator(`#inspector-elements-tree >> text=${swg2.name}`).click({
|
||||||
|
@ -26,7 +26,7 @@ necessarily be used for reference when writing new tests in this area.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const { test, expect } = require('../../../../pluginFixtures');
|
const { test, expect } = require('../../../../pluginFixtures');
|
||||||
const { createDomainObjectWithDefaults } = require('../../../../appActions');
|
const { createDomainObjectWithDefaults, selectInspectorTab } = require('../../../../appActions');
|
||||||
|
|
||||||
test.describe('Stacked Plot', () => {
|
test.describe('Stacked Plot', () => {
|
||||||
let stackedPlot;
|
let stackedPlot;
|
||||||
@ -65,11 +65,7 @@ test.describe('Stacked Plot', () => {
|
|||||||
|
|
||||||
await page.click('button[title="Edit"]');
|
await page.click('button[title="Edit"]');
|
||||||
|
|
||||||
// Expand the elements pool vertically
|
await selectInspectorTab(page, 'Elements');
|
||||||
await page.locator('.l-pane__handle').nth(2).hover({ trial: true });
|
|
||||||
await page.mouse.down();
|
|
||||||
await page.mouse.move(0, 100);
|
|
||||||
await page.mouse.up();
|
|
||||||
|
|
||||||
await swgBElementsPoolItem.click({ button: 'right' });
|
await swgBElementsPoolItem.click({ button: 'right' });
|
||||||
await page.getByRole('menuitem').filter({ hasText: /Remove/ }).click();
|
await page.getByRole('menuitem').filter({ hasText: /Remove/ }).click();
|
||||||
@ -92,11 +88,7 @@ test.describe('Stacked Plot', () => {
|
|||||||
|
|
||||||
await page.click('button[title="Edit"]');
|
await page.click('button[title="Edit"]');
|
||||||
|
|
||||||
// Expand the elements pool vertically
|
await selectInspectorTab(page, 'Elements');
|
||||||
await page.locator('.l-pane__handle').nth(2).hover({ trial: true });
|
|
||||||
await page.mouse.down();
|
|
||||||
await page.mouse.move(0, 100);
|
|
||||||
await page.mouse.up();
|
|
||||||
|
|
||||||
const stackedPlotItem1 = page.locator('.c-plot--stacked-container').nth(0);
|
const stackedPlotItem1 = page.locator('.c-plot--stacked-container').nth(0);
|
||||||
const stackedPlotItem2 = page.locator('.c-plot--stacked-container').nth(1);
|
const stackedPlotItem2 = page.locator('.c-plot--stacked-container').nth(1);
|
||||||
@ -136,6 +128,8 @@ test.describe('Stacked Plot', () => {
|
|||||||
test('Selecting a child plot while in browse and edit modes shows its properties in the inspector', async ({ page }) => {
|
test('Selecting a child plot while in browse and edit modes shows its properties in the inspector', async ({ page }) => {
|
||||||
await page.goto(stackedPlot.url);
|
await page.goto(stackedPlot.url);
|
||||||
|
|
||||||
|
await selectInspectorTab(page, 'Config');
|
||||||
|
|
||||||
// Click on the 1st plot
|
// Click on the 1st plot
|
||||||
await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"] canvas`).nth(1).click();
|
await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"] canvas`).nth(1).click();
|
||||||
|
|
||||||
@ -163,6 +157,8 @@ test.describe('Stacked Plot', () => {
|
|||||||
// Go into edit mode
|
// Go into edit mode
|
||||||
await page.click('button[title="Edit"]');
|
await page.click('button[title="Edit"]');
|
||||||
|
|
||||||
|
await selectInspectorTab(page, 'Config');
|
||||||
|
|
||||||
// Click on canvas for the 1st plot
|
// Click on canvas for the 1st plot
|
||||||
await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"]`).click();
|
await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"]`).click();
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const { test, expect } = require('../../pluginFixtures');
|
const { test, expect } = require('../../pluginFixtures');
|
||||||
const { createDomainObjectWithDefaults } = require('../../appActions');
|
const { createDomainObjectWithDefaults, selectInspectorTab } = require('../../appActions');
|
||||||
const { v4: uuid } = require('uuid');
|
const { v4: uuid } = require('uuid');
|
||||||
|
|
||||||
test.describe('Grand Search', () => {
|
test.describe('Grand Search', () => {
|
||||||
@ -50,7 +50,7 @@ test.describe('Grand Search', () => {
|
|||||||
await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText(`Clock C ${myItemsFolderName} Red Folder Blue Folder`);
|
await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText(`Clock C ${myItemsFolderName} Red Folder Blue Folder`);
|
||||||
await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText(`Clock D ${myItemsFolderName} Red Folder Blue Folder`);
|
await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText(`Clock D ${myItemsFolderName} Red Folder Blue Folder`);
|
||||||
// Click the Elements pool to dismiss the search menu
|
// Click the Elements pool to dismiss the search menu
|
||||||
await page.locator('.l-pane__label:has-text("Elements")').click();
|
await selectInspectorTab(page, 'Elements');
|
||||||
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden();
|
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden();
|
||||||
|
|
||||||
await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click();
|
await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click();
|
||||||
|
@ -143,7 +143,7 @@ define([
|
|||||||
* @memberof module:openmct.MCT#
|
* @memberof module:openmct.MCT#
|
||||||
* @name inspectorViews
|
* @name inspectorViews
|
||||||
*/
|
*/
|
||||||
['inspectorViews', () => new InspectorViewRegistry()],
|
['inspectorViews', () => new InspectorViewRegistry.default()],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registry for views which should appear in Edit Properties
|
* Registry for views which should appear in Edit Properties
|
||||||
@ -295,6 +295,7 @@ define([
|
|||||||
this.install(this.plugins.DeviceClassifier());
|
this.install(this.plugins.DeviceClassifier());
|
||||||
this.install(this.plugins.UserIndicator());
|
this.install(this.plugins.UserIndicator());
|
||||||
this.install(this.plugins.Gauge());
|
this.install(this.plugins.Gauge());
|
||||||
|
this.install(this.plugins.InspectorViews());
|
||||||
}
|
}
|
||||||
|
|
||||||
MCT.prototype = Object.create(EventEmitter.prototype);
|
MCT.prototype = Object.create(EventEmitter.prototype);
|
||||||
|
@ -5,7 +5,7 @@ import BarGraphOptions from "./BarGraphOptions.vue";
|
|||||||
export default function BarGraphInspectorViewProvider(openmct) {
|
export default function BarGraphInspectorViewProvider(openmct) {
|
||||||
return {
|
return {
|
||||||
key: BAR_GRAPH_INSPECTOR_KEY,
|
key: BAR_GRAPH_INSPECTOR_KEY,
|
||||||
name: 'Bar Graph Inspector View',
|
name: 'Bar Graph Configuration',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length === 0 || selection[0].length === 0) {
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -42,7 +42,7 @@ export default function BarGraphInspectorViewProvider(openmct) {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return openmct.priority.HIGH + 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -579,7 +579,7 @@ describe("the plugin", function () {
|
|||||||
child.append(viewContainer);
|
child.append(viewContainer);
|
||||||
|
|
||||||
const applicableViews = openmct.inspectorViews.get(selection);
|
const applicableViews = openmct.inspectorViews.get(selection);
|
||||||
plotInspectorView = applicableViews[0];
|
plotInspectorView = applicableViews.filter(view => view.name === 'Bar Graph Configuration')[0];
|
||||||
plotInspectorView.show(viewContainer);
|
plotInspectorView.show(viewContainer);
|
||||||
|
|
||||||
await Vue.nextTick();
|
await Vue.nextTick();
|
||||||
|
@ -5,7 +5,7 @@ import PlotOptions from "./PlotOptions.vue";
|
|||||||
export default function ScatterPlotInspectorViewProvider(openmct) {
|
export default function ScatterPlotInspectorViewProvider(openmct) {
|
||||||
return {
|
return {
|
||||||
key: SCATTER_PLOT_INSPECTOR_KEY,
|
key: SCATTER_PLOT_INSPECTOR_KEY,
|
||||||
name: 'Bar Graph Inspector View',
|
name: 'Config',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length === 0 || selection[0].length === 0) {
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -42,7 +42,7 @@ export default function ScatterPlotInspectorViewProvider(openmct) {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return openmct.priority.HIGH + 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,6 @@
|
|||||||
Your selection includes one or more items that use Conditional Styling. Applying a static style below will replace any Conditional Styling with the new choice.
|
Your selection includes one or more items that use Conditional Styling. Applying a static style below will replace any Conditional Styling with the new choice.
|
||||||
</div>
|
</div>
|
||||||
<template v-if="!conditionSetDomainObject">
|
<template v-if="!conditionSetDomainObject">
|
||||||
<div class="c-inspect-styles__header">
|
|
||||||
Object Style
|
|
||||||
</div>
|
|
||||||
<FontStyleEditor
|
<FontStyleEditor
|
||||||
v-if="canStyleFont"
|
v-if="canStyleFont"
|
||||||
:font-style="consolidatedFontStyle"
|
:font-style="consolidatedFontStyle"
|
||||||
@ -63,9 +60,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="c-inspect-styles__header">
|
|
||||||
Conditional Object Styles
|
|
||||||
</div>
|
|
||||||
<div class="c-inspect-styles__content c-inspect-styles__condition-set c-inspect-styles__elem">
|
<div class="c-inspect-styles__content c-inspect-styles__condition-set c-inspect-styles__elem">
|
||||||
<a
|
<a
|
||||||
v-if="conditionSetDomainObject"
|
v-if="conditionSetDomainObject"
|
||||||
@ -156,7 +150,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import FontStyleEditor from '@/ui/inspector/styles/FontStyleEditor.vue';
|
import FontStyleEditor from '../../../inspectorViews/styles/FontStyleEditor.vue';
|
||||||
import StyleEditor from "./StyleEditor.vue";
|
import StyleEditor from "./StyleEditor.vue";
|
||||||
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
||||||
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionSetIdentifierForItem } from "@/plugins/condition/utils/styleUtils";
|
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionSetIdentifierForItem } from "@/plugins/condition/utils/styleUtils";
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
import { createOpenMct, resetApplicationState } from "utils/testing";
|
import { createOpenMct, resetApplicationState } from "utils/testing";
|
||||||
import ConditionPlugin from "./plugin";
|
import ConditionPlugin from "./plugin";
|
||||||
import stylesManager from '@/ui/inspector/styles/StylesManager';
|
import stylesManager from '../inspectorViews/styles/StylesManager';
|
||||||
import StylesView from "./components/inspector/StylesView.vue";
|
import StylesView from "./components/inspector/StylesView.vue";
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import {getApplicableStylesForItem} from "./utils/styleUtils";
|
import {getApplicableStylesForItem} from "./utils/styleUtils";
|
||||||
|
@ -79,7 +79,7 @@ export default function AlphanumericFormatViewProvider(openmct, options) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
key: 'alphanumeric-format',
|
key: 'alphanumeric-format',
|
||||||
name: 'Alphanumeric Format',
|
name: 'Format',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length === 0 || selection[0].length === 1) {
|
if (selection.length === 0 || selection[0].length === 1) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -22,12 +22,8 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="isEditing"
|
|
||||||
class="c-inspect-properties"
|
class="c-inspect-properties"
|
||||||
>
|
>
|
||||||
<div class="c-inspect-properties__header">
|
|
||||||
Alphanumeric Format
|
|
||||||
</div>
|
|
||||||
<ul class="c-inspect-properties__section">
|
<ul class="c-inspect-properties__section">
|
||||||
<li class="c-inspect-properties__row">
|
<li class="c-inspect-properties__row">
|
||||||
<div
|
<div
|
||||||
@ -40,6 +36,7 @@
|
|||||||
<input
|
<input
|
||||||
id="telemetryPrintfFormat"
|
id="telemetryPrintfFormat"
|
||||||
type="text"
|
type="text"
|
||||||
|
:disabled="!isEditing"
|
||||||
:value="telemetryFormat"
|
:value="telemetryFormat"
|
||||||
:placeholder="nonMixedFormat ? '' : 'Mixed'"
|
:placeholder="nonMixedFormat ? '' : 'Mixed'"
|
||||||
@change="formatTelemetry"
|
@change="formatTelemetry"
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DetailText from '@/ui/inspector/details/DetailText.vue';
|
import DetailText from '../inspectorViews/properties/DetailText.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FaultManagementInspector',
|
name: 'FaultManagementInspector',
|
||||||
|
@ -30,7 +30,7 @@ export default function FaultManagementInspectorViewProvider(openmct) {
|
|||||||
return {
|
return {
|
||||||
openmct: openmct,
|
openmct: openmct,
|
||||||
key: FAULT_MANAGEMENT_INSPECTOR,
|
key: FAULT_MANAGEMENT_INSPECTOR,
|
||||||
name: 'FAULT_MANAGEMENT_TYPE',
|
name: 'Fault Management Configuration',
|
||||||
canView: (selection) => {
|
canView: (selection) => {
|
||||||
if (selection.length !== 1 || selection[0].length === 0) {
|
if (selection.length !== 1 || selection[0].length === 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -64,8 +64,8 @@ export default function FaultManagementInspectorViewProvider(openmct) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: () => {
|
priority: function () {
|
||||||
return 1;
|
return openmct.priority.HIGH + 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -86,8 +86,9 @@ describe("The Fault Management Plugin", () => {
|
|||||||
}
|
}
|
||||||
]];
|
]];
|
||||||
const applicableInspectorViews = openmct.inspectorViews.get(faultDomainObjectSelection);
|
const applicableInspectorViews = openmct.inspectorViews.get(faultDomainObjectSelection);
|
||||||
|
const faultManagementInspectorView = applicableInspectorViews.filter(view => view.name === 'Fault Management Configuration');
|
||||||
|
|
||||||
expect(applicableInspectorViews.length).toEqual(1);
|
expect(faultManagementInspectorView.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a root object for fault management', async () => {
|
it('creates a root object for fault management', async () => {
|
||||||
|
@ -31,19 +31,17 @@ define([
|
|||||||
function FiltersInspectorViewProvider(openmct, supportedObjectTypesArray) {
|
function FiltersInspectorViewProvider(openmct, supportedObjectTypesArray) {
|
||||||
return {
|
return {
|
||||||
key: 'filters-inspector',
|
key: 'filters-inspector',
|
||||||
name: 'Filters Inspector View',
|
name: 'Filters',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length === 0 || selection[0].length === 0) {
|
const domainObject = selection?.[0]?.[0]?.context?.item;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let object = selection[0][0].context.item;
|
return domainObject && supportedObjectTypesArray.some(type => domainObject.type === type);
|
||||||
|
|
||||||
return object && supportedObjectTypesArray.some(type => object.type === type);
|
|
||||||
},
|
},
|
||||||
view: function (selection) {
|
view: function (selection) {
|
||||||
let component;
|
let component;
|
||||||
|
|
||||||
|
const domainObject = selection?.[0]?.[0]?.context?.item;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
show: function (element) {
|
show: function (element) {
|
||||||
component = new Vue({
|
component = new Vue({
|
||||||
@ -57,6 +55,12 @@ define([
|
|||||||
template: '<filters-view></filters-view>'
|
template: '<filters-view></filters-view>'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
showTab: function (isEditing) {
|
||||||
|
const hasPersistedFilters = Boolean(domainObject?.configuration?.filters);
|
||||||
|
const hasGlobalFilters = Boolean(domainObject?.configuration?.globalFilters);
|
||||||
|
|
||||||
|
return hasPersistedFilters || hasGlobalFilters;
|
||||||
|
},
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
if (component) {
|
if (component) {
|
||||||
component.$destroy();
|
component.$destroy();
|
||||||
@ -66,7 +70,7 @@ define([
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return openmct.priority.DEFAULT;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TagEditor from '../../components/tags/TagEditor.vue';
|
import TagEditor from './tags/TagEditor.vue';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
export default {
|
export default {
|
@ -0,0 +1,62 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2022, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import Annotations from './AnnotationsInspectorView.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default function ElementsViewProvider(openmct) {
|
||||||
|
return {
|
||||||
|
key: 'annotationsView',
|
||||||
|
name: 'Annotations',
|
||||||
|
canView: function (selection) {
|
||||||
|
return selection.length;
|
||||||
|
},
|
||||||
|
view: function (selection) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
const domainObject = selection?.[0]?.[0]?.context?.item;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (el) {
|
||||||
|
component = new Vue({
|
||||||
|
el,
|
||||||
|
components: {
|
||||||
|
Annotations
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
domainObject
|
||||||
|
},
|
||||||
|
template: `<Annotations />`
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
priority: function () {
|
||||||
|
return this.openmct.priority.DEFAULT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import AutoCompleteField from '../../../api/forms/components/controls/AutoCompleteField.vue';
|
import AutoCompleteField from '../../../../api/forms/components/controls/AutoCompleteField.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
@ -42,7 +42,7 @@
|
|||||||
></span>
|
></span>
|
||||||
<object-label
|
<object-label
|
||||||
:domain-object="elementObject"
|
:domain-object="elementObject"
|
||||||
:object-path="[elementObject, parentObject]"
|
:object-path="[elementObject, domainObject]"
|
||||||
@context-click-active="setContextClickState"
|
@context-click-active="setContextClickState"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -50,13 +50,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ObjectLabel from '../components/ObjectLabel.vue';
|
import ObjectLabel from '../../../ui/components/ObjectLabel.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ObjectLabel
|
ObjectLabel
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: [
|
||||||
|
'openmct',
|
||||||
|
'domainObject'
|
||||||
|
],
|
||||||
props: {
|
props: {
|
||||||
index: {
|
index: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@ -72,19 +75,12 @@ export default {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
parentObject: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
default: () => {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
allowDrop: {
|
allowDrop: {
|
||||||
type: Boolean
|
type: Boolean
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
const isAlias = this.elementObject.location !== this.openmct.objects.makeKeyString(this.parentObject.identifier);
|
const isAlias = this.elementObject.location !== this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
contextClickActive: false,
|
contextClickActive: false,
|
@ -41,7 +41,6 @@
|
|||||||
:key="element.identifier.key"
|
:key="element.identifier.key"
|
||||||
:index="index"
|
:index="index"
|
||||||
:element-object="element"
|
:element-object="element"
|
||||||
:parent-object="parentObject"
|
|
||||||
:allow-drop="allowDrop"
|
:allow-drop="allowDrop"
|
||||||
@dragstart-custom="moveFrom(index)"
|
@dragstart-custom="moveFrom(index)"
|
||||||
@drop-custom="moveTo(index)"
|
@drop-custom="moveTo(index)"
|
||||||
@ -60,7 +59,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import Search from '../components/search.vue';
|
import Search from '../../../ui/components/search.vue';
|
||||||
import ElementItem from './ElementItem.vue';
|
import ElementItem from './ElementItem.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -68,12 +67,14 @@ export default {
|
|||||||
Search,
|
Search,
|
||||||
ElementItem
|
ElementItem
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: [
|
||||||
|
'openmct',
|
||||||
|
'domainObject'
|
||||||
|
],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
elements: [],
|
elements: [],
|
||||||
isEditing: this.openmct.editor.isEditing(),
|
isEditing: this.openmct.editor.isEditing(),
|
||||||
parentObject: undefined,
|
|
||||||
currentSearch: '',
|
currentSearch: '',
|
||||||
selection: [],
|
selection: [],
|
||||||
contextClickTracker: {},
|
contextClickTracker: {},
|
||||||
@ -111,14 +112,13 @@ export default {
|
|||||||
this.elements = [];
|
this.elements = [];
|
||||||
this.elementsCache = {};
|
this.elementsCache = {};
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
this.parentObject = selection && selection[0] && selection[0][0].context.item;
|
|
||||||
|
|
||||||
if (this.compositionUnlistener) {
|
if (this.compositionUnlistener) {
|
||||||
this.compositionUnlistener();
|
this.compositionUnlistener();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.parentObject) {
|
if (this.domainObject) {
|
||||||
this.composition = this.openmct.composition.get(this.parentObject);
|
this.composition = this.openmct.composition.get(this.domainObject);
|
||||||
|
|
||||||
if (this.composition) {
|
if (this.composition) {
|
||||||
this.composition.load();
|
this.composition.load();
|
||||||
@ -152,7 +152,7 @@ export default {
|
|||||||
},
|
},
|
||||||
applySearch(input) {
|
applySearch(input) {
|
||||||
this.currentSearch = input;
|
this.currentSearch = input;
|
||||||
this.elements = this.parentObject.composition.map((id) =>
|
this.elements = this.domainObject.composition.map((id) =>
|
||||||
this.elementsCache[this.openmct.objects.makeKeyString(id)]
|
this.elementsCache[this.openmct.objects.makeKeyString(id)]
|
||||||
).filter((element) => {
|
).filter((element) => {
|
||||||
return element !== undefined
|
return element !== undefined
|
70
src/plugins/inspectorViews/elements/ElementsViewProvider.js
Normal file
70
src/plugins/inspectorViews/elements/ElementsViewProvider.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2022, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import ElementsPool from './ElementsPool.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default function ElementsViewProvider(openmct) {
|
||||||
|
return {
|
||||||
|
key: 'elementsView',
|
||||||
|
name: 'Elements',
|
||||||
|
canView: function (selection) {
|
||||||
|
const hasValidSelection = selection?.length;
|
||||||
|
const isOverlayPlot = selection?.[0]?.[0]?.context?.item?.type === 'telemetry.plot.overlay';
|
||||||
|
|
||||||
|
return hasValidSelection && !isOverlayPlot;
|
||||||
|
},
|
||||||
|
view: function (selection) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
const domainObject = selection?.[0]?.[0]?.context?.item;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (el) {
|
||||||
|
component = new Vue({
|
||||||
|
el,
|
||||||
|
components: {
|
||||||
|
ElementsPool
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
domainObject
|
||||||
|
},
|
||||||
|
template: `<ElementsPool />`
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showTab: function (isEditing) {
|
||||||
|
const hasComposition = Boolean(domainObject && openmct.composition.get(domainObject));
|
||||||
|
|
||||||
|
return hasComposition && isEditing;
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
priority: function () {
|
||||||
|
return this.openmct.priority.DEFAULT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -77,10 +77,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import Search from '../components/search.vue';
|
import Search from '../../../ui/components/search.vue';
|
||||||
import ElementItem from './ElementItem.vue';
|
import ElementItem from './ElementItem.vue';
|
||||||
import ElementItemGroup from './ElementItemGroup.vue';
|
import ElementItemGroup from './ElementItemGroup.vue';
|
||||||
import configStore from '../../plugins/plot/configuration/ConfigStore';
|
import configStore from '../../plot/configuration/ConfigStore';
|
||||||
|
|
||||||
const Y_AXIS_1 = 1;
|
const Y_AXIS_1 = 1;
|
||||||
|
|
@ -0,0 +1,67 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2022, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import PlotElementsPool from './PlotElementsPool.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default function PlotElementsViewProvider(openmct) {
|
||||||
|
return {
|
||||||
|
key: 'plotElementsView',
|
||||||
|
name: 'Elements',
|
||||||
|
canView: function (selection) {
|
||||||
|
return selection?.[0]?.[0]?.context?.item?.type === 'telemetry.plot.overlay';
|
||||||
|
},
|
||||||
|
view: function (selection) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
const domainObject = selection?.[0]?.[0]?.context?.item;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (el) {
|
||||||
|
component = new Vue({
|
||||||
|
el,
|
||||||
|
components: {
|
||||||
|
PlotElementsPool
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
domainObject
|
||||||
|
},
|
||||||
|
template: `<PlotElementsPool />`
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showTab: function (isEditing) {
|
||||||
|
const hasComposition = Boolean(domainObject && openmct.composition.get(domainObject));
|
||||||
|
|
||||||
|
return hasComposition && isEditing;
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
priority: function () {
|
||||||
|
return this.openmct.priority.DEFAULT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
37
src/plugins/inspectorViews/plugin.js
Normal file
37
src/plugins/inspectorViews/plugin.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2022, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import PropertiesViewProvider from './properties/PropertiesViewProvider';
|
||||||
|
import ElementsViewProvider from './elements/ElementsViewProvider';
|
||||||
|
import PlotElementsViewProvider from './elements/PlotElementsViewProvider';
|
||||||
|
import StylesInspectorViewProvider from './styles/StylesInspectorViewProvider';
|
||||||
|
import AnnotationsViewProvider from './annotations/AnnotationsViewProvider';
|
||||||
|
|
||||||
|
export default function InspectorViewsPlugin() {
|
||||||
|
return function install(openmct) {
|
||||||
|
openmct.inspectorViews.addProvider(new PropertiesViewProvider(openmct));
|
||||||
|
openmct.inspectorViews.addProvider(new ElementsViewProvider(openmct));
|
||||||
|
openmct.inspectorViews.addProvider(new PlotElementsViewProvider(openmct));
|
||||||
|
openmct.inspectorViews.addProvider(new StylesInspectorViewProvider(openmct));
|
||||||
|
openmct.inspectorViews.addProvider(new AnnotationsViewProvider(openmct));
|
||||||
|
};
|
||||||
|
}
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="originalPath.length"
|
|
||||||
class="c-inspect-properties c-inspect-properties--location"
|
class="c-inspect-properties c-inspect-properties--location"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -32,16 +31,14 @@
|
|||||||
Original Location
|
Original Location
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
v-if="!multiSelect"
|
|
||||||
class="c-inspect-properties__section"
|
class="c-inspect-properties__section"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
v-if="originalPath.length"
|
|
||||||
class="c-inspect-properties__row"
|
class="c-inspect-properties__row"
|
||||||
>
|
>
|
||||||
<ul class="c-inspect-properties__value c-location">
|
<ul class="c-inspect-properties__value c-location">
|
||||||
<li
|
<li
|
||||||
v-for="pathObject in orderedOriginalPath"
|
v-for="pathObject in orderedPathBreadCrumb"
|
||||||
:key="pathObject.key"
|
:key="pathObject.key"
|
||||||
class="c-location__item"
|
class="c-location__item"
|
||||||
>
|
>
|
||||||
@ -53,53 +50,58 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div
|
|
||||||
v-if="multiSelect"
|
|
||||||
class="c-inspect-properties__row--span-all"
|
|
||||||
>
|
|
||||||
No location to display for multiple items
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ObjectLabel from '../components/ObjectLabel.vue';
|
import ObjectLabel from '../../../ui/components/ObjectLabel.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ObjectLabel
|
ObjectLabel
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: [
|
||||||
|
'openmct'
|
||||||
|
],
|
||||||
|
props: {
|
||||||
|
domainObject: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
parentDomainObject: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
domainObject: {},
|
pathBreadCrumb: []
|
||||||
multiSelect: false,
|
|
||||||
originalPath: [],
|
|
||||||
keyString: ''
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
orderedOriginalPath() {
|
orderedPathBreadCrumb() {
|
||||||
return this.originalPath.slice().reverse();
|
return this.pathBreadCrumb.slice().reverse();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
this.openmct.selection.on('change', this.updateSelection);
|
await this.createPathBreadCrumb();
|
||||||
this.updateSelection(this.openmct.selection.get());
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
this.openmct.selection.off('change', this.updateSelection);
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setOriginalPath(path, skipSlice) {
|
async createPathBreadCrumb() {
|
||||||
let originalPath = path;
|
if (!this.domainObject && this.parentDomainObject) {
|
||||||
|
this.setPathBreadCrumb([this.parentDomainObject]);
|
||||||
|
} else {
|
||||||
|
const keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
const originalPath = await this.openmct.objects.getOriginalPath(keyString);
|
||||||
|
const originalPathWithoutSelf = originalPath.slice(1, -1);
|
||||||
|
|
||||||
if (!skipSlice) {
|
this.setPathBreadCrumb(originalPathWithoutSelf);
|
||||||
originalPath = path.slice(1, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.originalPath = originalPath.map((domainObject, index, pathArray) => {
|
},
|
||||||
let key = this.openmct.objects.makeKeyString(domainObject.identifier);
|
setPathBreadCrumb(path) {
|
||||||
|
const pathBreadCrumb = path.map((domainObject, index, pathArray) => {
|
||||||
|
const key = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
domainObject,
|
domainObject,
|
||||||
@ -107,46 +109,8 @@ export default {
|
|||||||
objectPath: pathArray.slice(index)
|
objectPath: pathArray.slice(index)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
|
||||||
clearData() {
|
|
||||||
this.domainObject = {};
|
|
||||||
this.originalPath = [];
|
|
||||||
this.keyString = '';
|
|
||||||
},
|
|
||||||
updateSelection(selection) {
|
|
||||||
if (!selection.length || !selection[0].length) {
|
|
||||||
this.clearData();
|
|
||||||
|
|
||||||
return;
|
this.pathBreadCrumb = pathBreadCrumb;
|
||||||
}
|
|
||||||
|
|
||||||
if (selection.length > 1) {
|
|
||||||
this.multiSelect = true;
|
|
||||||
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.multiSelect = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.domainObject = selection[0][0].context.item;
|
|
||||||
let parentObject = selection[0][1];
|
|
||||||
|
|
||||||
if (!this.domainObject && parentObject && parentObject.context.item) {
|
|
||||||
this.setOriginalPath([parentObject.context.item], true);
|
|
||||||
this.keyString = '';
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
|
||||||
|
|
||||||
if (keyString && this.keyString !== keyString) {
|
|
||||||
this.keyString = keyString;
|
|
||||||
this.originalPath = [];
|
|
||||||
|
|
||||||
this.openmct.objects.getOriginalPath(this.keyString)
|
|
||||||
.then(this.setOriginalPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -21,6 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
<div class="c-inspector__properties c-inspect-properties">
|
<div class="c-inspector__properties c-inspect-properties">
|
||||||
<div class="c-inspect-properties__header">
|
<div class="c-inspect-properties__header">
|
||||||
Details
|
Details
|
||||||
@ -44,15 +45,24 @@
|
|||||||
{{ noDetailsMessage }}
|
{{ noDetailsMessage }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Location
|
||||||
|
v-if="hasLocation"
|
||||||
|
:domain-object="domainObject"
|
||||||
|
:parent-domain-object="parentDomainObject"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Moment from 'moment';
|
import Moment from 'moment';
|
||||||
import DetailText from './DetailText.vue';
|
import DetailText from './DetailText.vue';
|
||||||
|
import Location from './Location.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DetailText
|
DetailText,
|
||||||
|
Location
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
data() {
|
data() {
|
||||||
@ -62,21 +72,16 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
details() {
|
details() {
|
||||||
return this.customDetails ? this.customDetails : this.domainObjectDetails;
|
return this.customDetails ?? this.domainObjectDetails;
|
||||||
},
|
},
|
||||||
customDetails() {
|
customDetails() {
|
||||||
if (this.context === undefined) {
|
return this.context?.details;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.context.details;
|
|
||||||
},
|
},
|
||||||
domainObject() {
|
domainObject() {
|
||||||
if (this.context === undefined) {
|
return this.context?.item;
|
||||||
return;
|
},
|
||||||
}
|
parentDomainObject() {
|
||||||
|
return this.selection?.[0]?.[1]?.context?.item;
|
||||||
return this.context.item;
|
|
||||||
},
|
},
|
||||||
type() {
|
type() {
|
||||||
if (this.domainObject === undefined) {
|
if (this.domainObject === undefined) {
|
||||||
@ -162,20 +167,11 @@ export default {
|
|||||||
return [...details, ...this.typeProperties];
|
return [...details, ...this.typeProperties];
|
||||||
},
|
},
|
||||||
context() {
|
context() {
|
||||||
if (
|
return this.selection?.[0]?.[0]?.context;
|
||||||
!this.selection
|
|
||||||
|| !this.selection.length
|
|
||||||
|| !this.selection[0].length
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.selection[0][0].context;
|
|
||||||
},
|
},
|
||||||
hasDetails() {
|
hasDetails() {
|
||||||
return Boolean(
|
return Boolean(
|
||||||
this.details
|
this.details?.length
|
||||||
&& this.details.length
|
|
||||||
&& !this.multiSelection
|
&& !this.multiSelection
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -227,6 +223,13 @@ export default {
|
|||||||
}, this.domainObject)
|
}, this.domainObject)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
hasLocation() {
|
||||||
|
const domainObject = this.selection?.[0]?.[0]?.context?.item;
|
||||||
|
const isRootObject = domainObject?.location === 'ROOT';
|
||||||
|
const hasSingleSelection = this.selection?.length === 1;
|
||||||
|
|
||||||
|
return hasSingleSelection && !isRootObject;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
@ -0,0 +1,60 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2022, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import Properties from './Properties.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default function PropertiesViewProvider(openmct) {
|
||||||
|
return {
|
||||||
|
key: 'propertiesView',
|
||||||
|
name: 'Properties',
|
||||||
|
glyph: 'icon-info',
|
||||||
|
canView: function (selection) {
|
||||||
|
return selection.length > 0;
|
||||||
|
},
|
||||||
|
view: function (selection) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (el) {
|
||||||
|
component = new Vue({
|
||||||
|
el,
|
||||||
|
components: {
|
||||||
|
Properties
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct
|
||||||
|
},
|
||||||
|
template: `<Properties />`
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
priority: function () {
|
||||||
|
return this.openmct.priority.DEFAULT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -29,7 +29,7 @@
|
|||||||
import {
|
import {
|
||||||
FONT_SIZES,
|
FONT_SIZES,
|
||||||
FONTS
|
FONTS
|
||||||
} from '@/ui/inspector/styles/constants';
|
} from './constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
@ -25,7 +25,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SavedStylesView from '@/ui/inspector/styles/SavedStylesView.vue';
|
import SavedStylesView from './SavedStylesView.vue';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
@ -38,7 +38,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SavedStyleSelector from '@/ui/inspector/styles/SavedStyleSelector.vue';
|
import SavedStyleSelector from './SavedStyleSelector.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SavedStylesView',
|
name: 'SavedStylesView',
|
@ -21,51 +21,53 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="u-contents"></div>
|
<multipane
|
||||||
|
type="vertical"
|
||||||
|
>
|
||||||
|
<pane class="c-inspector__styles">
|
||||||
|
<div class="u-contents">
|
||||||
|
<StylesView />
|
||||||
|
</div>
|
||||||
|
</pane>
|
||||||
|
<pane
|
||||||
|
v-if="isEditing"
|
||||||
|
class="c-inspector__saved-styles"
|
||||||
|
handle="before"
|
||||||
|
label="Saved Styles"
|
||||||
|
>
|
||||||
|
<SavedStylesInspectorView />
|
||||||
|
</pane>
|
||||||
|
</multipane>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import multipane from '../../../ui/layout/multipane.vue';
|
||||||
|
import pane from '../../../ui/layout/pane.vue';
|
||||||
import StylesView from '@/plugins/condition/components/inspector/StylesView.vue';
|
import StylesView from '@/plugins/condition/components/inspector/StylesView.vue';
|
||||||
import Vue from 'vue';
|
import SavedStylesInspectorView from './SavedStylesInspectorView.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'stylesManager'],
|
components: {
|
||||||
|
multipane,
|
||||||
|
pane,
|
||||||
|
StylesView,
|
||||||
|
SavedStylesInspectorView
|
||||||
|
},
|
||||||
|
inject: ['openmct'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selection: []
|
isEditing: this.openmct.editor.isEditing()
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.openmct.selection.on('change', this.updateSelection);
|
this.openmct.editor.on('isEditing', this.setEditMode);
|
||||||
this.updateSelection(this.openmct.selection.get());
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
beforeDestroyed() {
|
||||||
this.openmct.selection.off('change', this.updateSelection);
|
this.openmct.editor.off('isEditing', this.setEditMode);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateSelection(selection) {
|
setEditMode(isEditing) {
|
||||||
if (selection.length > 0 && selection[0].length > 0) {
|
this.isEditing = isEditing;
|
||||||
if (this.component) {
|
|
||||||
this.component.$destroy();
|
|
||||||
this.component = undefined;
|
|
||||||
this.$el.innerHTML = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
let viewContainer = document.createElement('div');
|
|
||||||
this.$el.append(viewContainer);
|
|
||||||
this.component = new Vue({
|
|
||||||
el: viewContainer,
|
|
||||||
components: {
|
|
||||||
StylesView
|
|
||||||
},
|
|
||||||
provide: {
|
|
||||||
openmct: this.openmct,
|
|
||||||
selection: selection,
|
|
||||||
stylesManager: this.stylesManager
|
|
||||||
},
|
|
||||||
template: '<styles-view/>'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -0,0 +1,89 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2022, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import stylesManager from './StylesManager';
|
||||||
|
import StylesInspectorView from './StylesInspectorView.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
const NON_STYLABLE_TYPES = ['folder', 'webPage', 'conditionSet', 'summary-widget', 'hyperlink'];
|
||||||
|
|
||||||
|
function isLayoutObject(selection, objectType) {
|
||||||
|
//we allow conditionSets to be styled if they're part of a layout
|
||||||
|
return selection.length > 1
|
||||||
|
&& ((objectType === 'conditionSet') || (NON_STYLABLE_TYPES.indexOf(objectType) < 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCreatableObject(object, type) {
|
||||||
|
return (NON_STYLABLE_TYPES.indexOf(object.type) < 0) && type.definition.creatable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function StylesInspectorViewProvider(openmct) {
|
||||||
|
return {
|
||||||
|
key: 'stylesInspectorView',
|
||||||
|
name: 'Styles',
|
||||||
|
glyph: 'icon-paint-bucket',
|
||||||
|
canView: function (selection) {
|
||||||
|
const objectSelection = selection?.[0];
|
||||||
|
const layoutItem = objectSelection?.[0]?.context?.layoutItem;
|
||||||
|
const domainObject = objectSelection?.[0]?.context?.item;
|
||||||
|
|
||||||
|
if (layoutItem) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!domainObject) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = openmct.types.get(domainObject.type);
|
||||||
|
|
||||||
|
return isLayoutObject(objectSelection, domainObject.type) || isCreatableObject(domainObject, type);
|
||||||
|
},
|
||||||
|
view: function (selection) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (el) {
|
||||||
|
component = new Vue({
|
||||||
|
el,
|
||||||
|
components: {
|
||||||
|
StylesInspectorView
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
stylesManager,
|
||||||
|
selection
|
||||||
|
},
|
||||||
|
template: `<StylesInspectorView />`
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
priority: function () {
|
||||||
|
return this.openmct.priority.DEFAULT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -63,7 +63,7 @@ export default function PlanInspectorViewProvider(openmct) {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return openmct.priority.HIGH + 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
import {createOpenMct, resetApplicationState} from "utils/testing";
|
import {createOpenMct, resetApplicationState} from "utils/testing";
|
||||||
import PlanPlugin from "../plan/plugin";
|
import PlanPlugin from "../plan/plugin";
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Properties from "@/ui/inspector/details/Properties.vue";
|
import Properties from "../inspectorViews/properties/Properties.vue";
|
||||||
|
|
||||||
describe('the plugin', function () {
|
describe('the plugin', function () {
|
||||||
let planDefinition;
|
let planDefinition;
|
||||||
@ -264,7 +264,7 @@ describe('the plugin', function () {
|
|||||||
it('provides an inspector view with the version information if available', () => {
|
it('provides an inspector view with the version information if available', () => {
|
||||||
componentObject = component.$root.$children[0];
|
componentObject = component.$root.$children[0];
|
||||||
const propertiesEls = componentObject.$el.querySelectorAll('.c-inspect-properties__row');
|
const propertiesEls = componentObject.$el.querySelectorAll('.c-inspect-properties__row');
|
||||||
expect(propertiesEls.length).toEqual(6);
|
expect(propertiesEls.length).toEqual(7);
|
||||||
const found = Array.from(propertiesEls).some((propertyEl) => {
|
const found = Array.from(propertiesEls).some((propertyEl) => {
|
||||||
return (propertyEl.children[0].innerHTML.trim() === 'Version'
|
return (propertyEl.children[0].innerHTML.trim() === 'Version'
|
||||||
&& propertyEl.children[1].innerHTML.trim() === 'v1');
|
&& propertyEl.children[1].innerHTML.trim() === 'v1');
|
||||||
|
@ -29,7 +29,10 @@
|
|||||||
class="c-tree"
|
class="c-tree"
|
||||||
aria-label="Plot Series Properties"
|
aria-label="Plot Series Properties"
|
||||||
>
|
>
|
||||||
<h2 title="Plot series display properties in this object">Plot Series</h2>
|
<h2
|
||||||
|
class="--first"
|
||||||
|
title="Plot series display properties in this object"
|
||||||
|
>Plot Series</h2>
|
||||||
<plot-options-item
|
<plot-options-item
|
||||||
v-for="series in plotSeries"
|
v-for="series in plotSeries"
|
||||||
:key="series.key"
|
:key="series.key"
|
||||||
@ -101,7 +104,10 @@
|
|||||||
<ul
|
<ul
|
||||||
class="l-inspector-part js-legend-properties"
|
class="l-inspector-part js-legend-properties"
|
||||||
>
|
>
|
||||||
<h2 title="Legend settings for this object">Legend</h2>
|
<h2
|
||||||
|
class="--first"
|
||||||
|
title="Legend settings for this object"
|
||||||
|
>Legend</h2>
|
||||||
<li class="grid-row">
|
<li class="grid-row">
|
||||||
<div
|
<div
|
||||||
class="grid-cell label"
|
class="grid-cell label"
|
||||||
|
@ -29,7 +29,10 @@
|
|||||||
class="c-tree"
|
class="c-tree"
|
||||||
aria-label="Plot Series Properties"
|
aria-label="Plot Series Properties"
|
||||||
>
|
>
|
||||||
<h2 title="Display properties for this object">Plot Series</h2>
|
<h2
|
||||||
|
class="--first"
|
||||||
|
title="Display properties for this object"
|
||||||
|
>Plot Series</h2>
|
||||||
<li
|
<li
|
||||||
v-for="series in plotSeries"
|
v-for="series in plotSeries"
|
||||||
:key="series.key"
|
:key="series.key"
|
||||||
@ -52,7 +55,10 @@
|
|||||||
v-if="isStackedPlotObject || !isStackedPlotNestedObject"
|
v-if="isStackedPlotObject || !isStackedPlotNestedObject"
|
||||||
class="l-inspector-part"
|
class="l-inspector-part"
|
||||||
>
|
>
|
||||||
<h2 title="Legend options">Legend</h2>
|
<h2
|
||||||
|
class="--first"
|
||||||
|
title="Legend options"
|
||||||
|
>Legend</h2>
|
||||||
<legend-form
|
<legend-form
|
||||||
class="grid-properties"
|
class="grid-properties"
|
||||||
:legend="config.legend"
|
:legend="config.legend"
|
||||||
|
@ -5,7 +5,7 @@ import Vue from 'vue';
|
|||||||
export default function PlotsInspectorViewProvider(openmct) {
|
export default function PlotsInspectorViewProvider(openmct) {
|
||||||
return {
|
return {
|
||||||
key: 'plots-inspector',
|
key: 'plots-inspector',
|
||||||
name: 'Plots Inspector View',
|
name: 'Config',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length === 0 || selection[0].length === 0) {
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -53,7 +53,7 @@ export default function PlotsInspectorViewProvider(openmct) {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return openmct.priority.HIGH + 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import Vue from 'vue';
|
|||||||
export default function StackedPlotsInspectorViewProvider(openmct) {
|
export default function StackedPlotsInspectorViewProvider(openmct) {
|
||||||
return {
|
return {
|
||||||
key: 'stacked-plots-inspector',
|
key: 'stacked-plots-inspector',
|
||||||
name: 'Stacked Plots Inspector View',
|
name: 'Config',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length === 0 || selection[0].length === 0) {
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -51,7 +51,7 @@ export default function StackedPlotsInspectorViewProvider(openmct) {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return openmct.priority.HIGH + 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -279,8 +279,10 @@ describe("the plugin", function () {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
const plotInspectorView = openmct.inspectorViews.get(selection);
|
const applicableInspectorViews = openmct.inspectorViews.get(selection);
|
||||||
expect(plotInspectorView.length).toEqual(1);
|
const plotInspectorView = applicableInspectorViews.find(view => view.name = 'Plots Configuration');
|
||||||
|
|
||||||
|
expect(plotInspectorView).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("provides a stacked plot view for objects with telemetry", () => {
|
it("provides a stacked plot view for objects with telemetry", () => {
|
||||||
|
@ -82,7 +82,8 @@ define([
|
|||||||
'./gauge/GaugePlugin',
|
'./gauge/GaugePlugin',
|
||||||
'./timelist/plugin',
|
'./timelist/plugin',
|
||||||
'./faultManagement/FaultManagementPlugin',
|
'./faultManagement/FaultManagementPlugin',
|
||||||
'../../example/exampleTags/plugin'
|
'../../example/exampleTags/plugin',
|
||||||
|
'./inspectorViews/plugin'
|
||||||
], function (
|
], function (
|
||||||
_,
|
_,
|
||||||
UTCTimeSystem,
|
UTCTimeSystem,
|
||||||
@ -145,7 +146,8 @@ define([
|
|||||||
GaugePlugin,
|
GaugePlugin,
|
||||||
TimeList,
|
TimeList,
|
||||||
FaultManagementPlugin,
|
FaultManagementPlugin,
|
||||||
ExampleTags
|
ExampleTags,
|
||||||
|
InspectorViews
|
||||||
) {
|
) {
|
||||||
const plugins = {};
|
const plugins = {};
|
||||||
|
|
||||||
@ -229,6 +231,7 @@ define([
|
|||||||
plugins.OperatorStatus = OperatorStatus.default;
|
plugins.OperatorStatus = OperatorStatus.default;
|
||||||
plugins.Gauge = GaugePlugin.default;
|
plugins.Gauge = GaugePlugin.default;
|
||||||
plugins.Timelist = TimeList.default;
|
plugins.Timelist = TimeList.default;
|
||||||
|
plugins.InspectorViews = InspectorViews.default;
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
});
|
});
|
||||||
|
@ -35,7 +35,7 @@ define([
|
|||||||
function TableConfigurationViewProvider(openmct) {
|
function TableConfigurationViewProvider(openmct) {
|
||||||
return {
|
return {
|
||||||
key: 'table-configuration',
|
key: 'table-configuration',
|
||||||
name: 'Telemetry Table Configuration',
|
name: 'Configuration',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length !== 1 || selection[0].length === 0) {
|
if (selection.length !== 1 || selection[0].length === 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="c-inspect-properties">
|
<div class="c-inspect-properties">
|
||||||
<template v-if="isEditing">
|
<template v-if="isEditing">
|
||||||
<div class="c-inspect-properties__header">
|
<div class="c-inspect-properties__header">
|
||||||
Table Layout
|
Layout
|
||||||
</div>
|
</div>
|
||||||
<ul class="c-inspect-properties__section">
|
<ul class="c-inspect-properties__section">
|
||||||
<li class="c-inspect-properties__row">
|
<li class="c-inspect-properties__row">
|
||||||
@ -39,7 +39,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="c-inspect-properties__header">
|
<div class="c-inspect-properties__header">
|
||||||
Table Column Visibility
|
Columns
|
||||||
</div>
|
</div>
|
||||||
<ul class="c-inspect-properties__section">
|
<ul class="c-inspect-properties__section">
|
||||||
<li
|
<li
|
||||||
|
@ -64,7 +64,7 @@ export default function TimeListInspectorViewProvider(openmct) {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return openmct.priority.HIGH + 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -289,6 +289,13 @@ $colorInspectorPropVal: pullForward($colorInspectorFg, 15%);
|
|||||||
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
|
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
|
||||||
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
|
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
|
||||||
|
|
||||||
|
// Tabs
|
||||||
|
$colorTabBg: pullForward($colorBodyBg, 5%);
|
||||||
|
$colorTabFg: pullForward($colorBodyFg, 0%);
|
||||||
|
$colorTabCurrentBg: pullForward($colorTabBg, 10%);
|
||||||
|
$colorTabCurrentFg: pullForward($colorTabFg, 20%);
|
||||||
|
$colorTabsBaseline: $colorTabCurrentBg;
|
||||||
|
|
||||||
// Overlay
|
// Overlay
|
||||||
$colorOvrBlocker: rgba(black, 0.7);
|
$colorOvrBlocker: rgba(black, 0.7);
|
||||||
$overlayCr: $interiorMargin;
|
$overlayCr: $interiorMargin;
|
||||||
@ -341,7 +348,7 @@ $colorItemFg: $colorBtnFg;
|
|||||||
$colorItemFgDetails: pushBack($colorItemFg, 20%);
|
$colorItemFgDetails: pushBack($colorItemFg, 20%);
|
||||||
$shdwItemText: none;
|
$shdwItemText: none;
|
||||||
|
|
||||||
// Tabular
|
// Tabular (NOT TABS!)
|
||||||
$colorTabBorder: pullForward($colorBodyBg, 10%);
|
$colorTabBorder: pullForward($colorBodyBg, 10%);
|
||||||
$colorTabBodyBg: $colorBodyBg;
|
$colorTabBodyBg: $colorBodyBg;
|
||||||
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
|
$colorTabBodyFg: pullForward($colorBodyFg, 20%);
|
||||||
|
@ -293,6 +293,13 @@ $colorInspectorPropVal: pullForward($colorInspectorFg, 15%);
|
|||||||
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
|
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
|
||||||
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
|
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
|
||||||
|
|
||||||
|
// Tabs
|
||||||
|
$colorTabBg: pullForward($colorBodyBg, 5%);
|
||||||
|
$colorTabFg: pullForward($colorBtnFg, 10%);
|
||||||
|
$colorTabCurrentBg: pullForward($colorTabBg, 10%);
|
||||||
|
$colorTabCurrentFg: pullForward($colorTabFg, 10%);
|
||||||
|
$colorTabsBaseline: $colorTabCurrentBg;
|
||||||
|
|
||||||
// Overlay
|
// Overlay
|
||||||
$colorOvrBlocker: rgba(black, 0.7);
|
$colorOvrBlocker: rgba(black, 0.7);
|
||||||
$overlayCr: $interiorMarginLg;
|
$overlayCr: $interiorMarginLg;
|
||||||
|
@ -289,6 +289,13 @@ $colorInspectorPropVal: pullForward($colorInspectorFg, 15%);
|
|||||||
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
|
$colorInspectorSectionHeaderBg: pullForward($colorInspectorBg, 5%);
|
||||||
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
|
$colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%);
|
||||||
|
|
||||||
|
// Tabs
|
||||||
|
$colorTabBg: pullForward($colorBodyBg, 15%);
|
||||||
|
$colorTabFg: pullForward($colorTabBg, 60%);
|
||||||
|
$colorTabCurrentBg: $colorBodyFg; //pullForward($colorTabBg, 10%);
|
||||||
|
$colorTabCurrentFg: $colorBodyBg; //pullForward($colorTabFg, 10%);
|
||||||
|
$colorTabsBaseline: $colorTabCurrentBg;
|
||||||
|
|
||||||
// Overlay
|
// Overlay
|
||||||
$colorOvrBlocker: rgba(black, 0.7);
|
$colorOvrBlocker: rgba(black, 0.7);
|
||||||
$overlayCr: $interiorMarginLg;
|
$overlayCr: $interiorMarginLg;
|
||||||
|
@ -529,7 +529,7 @@ select {
|
|||||||
display: block;
|
display: block;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: $colorBtnReverseBg;
|
background: $colorTabsBaseline;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@ -548,8 +548,8 @@ select {
|
|||||||
100% 100%,
|
100% 100%,
|
||||||
0% 100%
|
0% 100%
|
||||||
);
|
);
|
||||||
background: rgba($colorBtnBg, 0.7);
|
background: $colorTabBg;
|
||||||
color: $colorBtnFg;
|
color: $colorTabFg;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -569,8 +569,8 @@ select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.is-current {
|
&.is-current {
|
||||||
background: $colorBtnReverseBg;
|
background: $colorTabCurrentBg;
|
||||||
color: $colorBtnReverseFg;
|
color: $colorTabCurrentFg;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,13 @@
|
|||||||
@import "../ui/components/progress-bar.scss";
|
@import "../ui/components/progress-bar.scss";
|
||||||
@import "../ui/components/search.scss";
|
@import "../ui/components/search.scss";
|
||||||
@import "../ui/components/swim-lane/swimlane.scss";
|
@import "../ui/components/swim-lane/swimlane.scss";
|
||||||
@import "../ui/components/tags/tags.scss";
|
@import "../plugins/inspectorViews/annotations/tags/tags.scss";
|
||||||
@import "../ui/components/toggle-switch.scss";
|
@import "../ui/components/toggle-switch.scss";
|
||||||
@import "../ui/components/timesystem-axis.scss";
|
@import "../ui/components/timesystem-axis.scss";
|
||||||
@import "../ui/components/List/list-view.scss";
|
@import "../ui/components/List/list-view.scss";
|
||||||
@import "../ui/inspector/elements.scss";
|
@import "../plugins/inspectorViews/elements/elements.scss";
|
||||||
@import "../ui/inspector/inspector.scss";
|
@import "../ui/inspector/inspector.scss";
|
||||||
@import "../ui/inspector/location.scss";
|
@import "../plugins/inspectorViews/properties/location.scss";
|
||||||
@import "../ui/layout/app-logo.scss";
|
@import "../ui/layout/app-logo.scss";
|
||||||
@import "../ui/layout/create-button.scss";
|
@import "../ui/layout/create-button.scss";
|
||||||
@import "../ui/layout/layout.scss";
|
@import "../ui/layout/layout.scss";
|
||||||
|
@ -23,111 +23,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-inspector">
|
<div class="c-inspector">
|
||||||
<object-name />
|
<object-name />
|
||||||
<div
|
<InspectorTabs
|
||||||
v-if="showStyles"
|
:selection="selection"
|
||||||
class="c-inspector__tabs c-tabs"
|
:is-editing="isEditing"
|
||||||
>
|
@select-tab="selectTab"
|
||||||
<div
|
|
||||||
v-for="tabbedView in tabbedViews"
|
|
||||||
:key="tabbedView.key"
|
|
||||||
class="c-inspector__tab c-tab"
|
|
||||||
:class="{'is-current': isCurrent(tabbedView)}"
|
|
||||||
@click="updateCurrentTab(tabbedView)"
|
|
||||||
>
|
|
||||||
{{ tabbedView.name }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="c-inspector__content">
|
|
||||||
<multipane
|
|
||||||
v-show="currentTabbedView.key === '__properties'"
|
|
||||||
type="vertical"
|
|
||||||
>
|
|
||||||
<pane class="c-inspector__properties">
|
|
||||||
<Properties v-if="!activity" />
|
|
||||||
<div
|
|
||||||
v-if="!multiSelect"
|
|
||||||
class="c-inspect-properties c-inspect-properties--location"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<inspector-views />
|
|
||||||
</pane>
|
|
||||||
<pane
|
|
||||||
v-if="isEditing && hasComposition"
|
|
||||||
class="c-inspector__elements"
|
|
||||||
handle="before"
|
|
||||||
label="Elements"
|
|
||||||
>
|
|
||||||
<plot-elements-pool
|
|
||||||
v-if="isOverlayPlot"
|
|
||||||
/>
|
/>
|
||||||
<elements-pool
|
<InspectorViews
|
||||||
v-else
|
:selection="selection"
|
||||||
|
:selected-tab="selectedTab"
|
||||||
/>
|
/>
|
||||||
</pane>
|
|
||||||
</multipane>
|
|
||||||
<multipane
|
|
||||||
v-show="currentTabbedView.key === '__styles'"
|
|
||||||
type="vertical"
|
|
||||||
>
|
|
||||||
<pane class="c-inspector__styles">
|
|
||||||
<StylesInspectorView />
|
|
||||||
</pane>
|
|
||||||
<pane
|
|
||||||
v-if="isEditing"
|
|
||||||
class="c-inspector__saved-styles"
|
|
||||||
handle="before"
|
|
||||||
label="Saved Styles"
|
|
||||||
>
|
|
||||||
<SavedStylesInspectorView :is-editing="isEditing" />
|
|
||||||
</pane>
|
|
||||||
</multipane>
|
|
||||||
<multipane
|
|
||||||
v-show="currentTabbedView.key === '__annotations'"
|
|
||||||
type="vertical"
|
|
||||||
>
|
|
||||||
<pane class="c-inspector__annotations">
|
|
||||||
<AnnotationsInspectorView
|
|
||||||
@annotationCreated="updateCurrentTab(tabbedViews[2])"
|
|
||||||
/>
|
|
||||||
</pane>
|
|
||||||
</multipane>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import multipane from '../layout/multipane.vue';
|
|
||||||
import pane from '../layout/pane.vue';
|
|
||||||
import ElementsPool from './ElementsPool.vue';
|
|
||||||
import PlotElementsPool from './PlotElementsPool.vue';
|
|
||||||
import Properties from './details/Properties.vue';
|
|
||||||
import ObjectName from './ObjectName.vue';
|
import ObjectName from './ObjectName.vue';
|
||||||
|
import InspectorTabs from './InspectorTabs.vue';
|
||||||
import InspectorViews from './InspectorViews.vue';
|
import InspectorViews from './InspectorViews.vue';
|
||||||
import _ from "lodash";
|
|
||||||
import stylesManager from "@/ui/inspector/styles/StylesManager";
|
|
||||||
import StylesInspectorView from "@/ui/inspector/styles/StylesInspectorView.vue";
|
|
||||||
import SavedStylesInspectorView from "@/ui/inspector/styles/SavedStylesInspectorView.vue";
|
|
||||||
import AnnotationsInspectorView from "./annotations/AnnotationsInspectorView.vue";
|
|
||||||
|
|
||||||
const OVERLAY_PLOT_TYPE = "telemetry.plot.overlay";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
StylesInspectorView,
|
|
||||||
SavedStylesInspectorView,
|
|
||||||
AnnotationsInspectorView,
|
|
||||||
multipane,
|
|
||||||
pane,
|
|
||||||
ElementsPool,
|
|
||||||
PlotElementsPool,
|
|
||||||
Properties,
|
|
||||||
ObjectName,
|
ObjectName,
|
||||||
|
InspectorTabs,
|
||||||
InspectorViews
|
InspectorViews
|
||||||
},
|
},
|
||||||
provide: {
|
inject: ['openmct'],
|
||||||
stylesManager: stylesManager
|
|
||||||
},
|
|
||||||
inject: ["openmct"],
|
|
||||||
props: {
|
props: {
|
||||||
isEditing: {
|
isEditing: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@ -136,116 +55,22 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hasComposition: false,
|
selection: this.openmct.selection.get(),
|
||||||
multiSelect: false,
|
selectedTab: undefined
|
||||||
showStyles: false,
|
|
||||||
isOverlayPlot: false,
|
|
||||||
tabbedViews: [
|
|
||||||
{
|
|
||||||
key: "__properties",
|
|
||||||
name: "Properties"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "__styles",
|
|
||||||
name: "Styles"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "__annotations",
|
|
||||||
name: "Annotations"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
currentTabbedView: {},
|
|
||||||
activity: undefined
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.excludeObjectTypes = [
|
this.openmct.selection.on('change', this.setSelection);
|
||||||
"folder",
|
|
||||||
"webPage",
|
|
||||||
"conditionSet",
|
|
||||||
"summary-widget",
|
|
||||||
"hyperlink"
|
|
||||||
];
|
|
||||||
this.openmct.selection.on("change", this.updateInspectorViews);
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.openmct.selection.off("change", this.updateInspectorViews);
|
this.openmct.selection.off('change', this.setSelection);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateInspectorViews(selection) {
|
setSelection(selection) {
|
||||||
this.refreshComposition(selection);
|
this.selection = selection;
|
||||||
|
|
||||||
if (this.openmct.types.get("conditionSet")) {
|
|
||||||
this.refreshTabs(selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selection.length > 1) {
|
|
||||||
this.multiSelect = true;
|
|
||||||
|
|
||||||
// return;
|
|
||||||
} else {
|
|
||||||
this.multiSelect = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setActivity(selection);
|
|
||||||
},
|
},
|
||||||
refreshComposition(selection) {
|
selectTab(tab) {
|
||||||
if (selection.length > 0 && selection[0].length > 0) {
|
this.selectedTab = tab;
|
||||||
const parentObject = selection[0][0].context.item;
|
|
||||||
|
|
||||||
this.hasComposition = Boolean(
|
|
||||||
parentObject && this.openmct.composition.get(parentObject)
|
|
||||||
);
|
|
||||||
this.isOverlayPlot = parentObject?.type === OVERLAY_PLOT_TYPE;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
refreshTabs(selection) {
|
|
||||||
if (selection.length > 0 && selection[0].length > 0) {
|
|
||||||
//layout items are not domain objects but should allow conditional styles
|
|
||||||
this.showStyles = selection[0][0].context.layoutItem;
|
|
||||||
let object = selection[0][0].context.item;
|
|
||||||
if (object) {
|
|
||||||
let type = this.openmct.types.get(object.type);
|
|
||||||
this.showStyles =
|
|
||||||
this.isLayoutObject(selection[0], object.type)
|
|
||||||
|| this.isCreatableObject(object, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!this.currentTabbedView.key
|
|
||||||
|| (!this.showStyles
|
|
||||||
&& this.currentTabbedView.key === this.tabbedViews[1].key)
|
|
||||||
) {
|
|
||||||
this.updateCurrentTab(this.tabbedViews[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isLayoutObject(selection, objectType) {
|
|
||||||
//we allow conditionSets to be styled if they're part of a layout
|
|
||||||
return (
|
|
||||||
selection.length > 1
|
|
||||||
&& (objectType === "conditionSet"
|
|
||||||
|| this.excludeObjectTypes.indexOf(objectType) < 0)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
isCreatableObject(object, type) {
|
|
||||||
return (
|
|
||||||
this.excludeObjectTypes.indexOf(object.type) < 0
|
|
||||||
&& type.definition.creatable
|
|
||||||
);
|
|
||||||
},
|
|
||||||
updateCurrentTab(view) {
|
|
||||||
this.currentTabbedView = view;
|
|
||||||
},
|
|
||||||
isCurrent(view) {
|
|
||||||
return _.isEqual(this.currentTabbedView, view);
|
|
||||||
},
|
|
||||||
setActivity(selection) {
|
|
||||||
this.activity =
|
|
||||||
selection
|
|
||||||
&& selection.length
|
|
||||||
&& selection[0].length
|
|
||||||
&& selection[0][0].activity;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -36,8 +36,8 @@ import {
|
|||||||
} from './InspectorStylesSpecMocks';
|
} from './InspectorStylesSpecMocks';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import StylesView from '@/plugins/condition/components/inspector/StylesView.vue';
|
import StylesView from '@/plugins/condition/components/inspector/StylesView.vue';
|
||||||
import SavedStylesView from '@/ui/inspector/styles/SavedStylesView.vue';
|
import SavedStylesView from '../../plugins/inspectorViews/styles/SavedStylesView.vue';
|
||||||
import stylesManager from '@/ui/inspector/styles/StylesManager';
|
import stylesManager from '../../plugins/inspectorViews/styles/StylesManager';
|
||||||
|
|
||||||
describe("the inspector", () => {
|
describe("the inspector", () => {
|
||||||
let openmct;
|
let openmct;
|
||||||
|
115
src/ui/inspector/InspectorTabs.vue
Normal file
115
src/ui/inspector/InspectorTabs.vue
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2022, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="c-inspector__tabs c-tabs"
|
||||||
|
role="tablist"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="tab in visibleTabs"
|
||||||
|
:key="tab.key"
|
||||||
|
role="tab"
|
||||||
|
class="c-inspector__tab c-tab"
|
||||||
|
:class="{'is-current': isSelected(tab)}"
|
||||||
|
:title="tab.name"
|
||||||
|
@click="selectTab(tab)"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="c-inspector__tab-name c-tab__name"
|
||||||
|
>{{ tab.name }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
selection: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isEditing: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selection: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tabs: [],
|
||||||
|
selectedTab: undefined
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
visibleTabs() {
|
||||||
|
return this.tabs
|
||||||
|
.filter(tab => {
|
||||||
|
return tab.showTab === undefined || tab.showTab(this.isEditing);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selection() {
|
||||||
|
this.updateSelection();
|
||||||
|
},
|
||||||
|
visibleTabs() {
|
||||||
|
this.selectDefaultTabIfSelectedNotVisible();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateSelection() {
|
||||||
|
const inspectorViews = this.openmct.inspectorViews.get(this.selection);
|
||||||
|
|
||||||
|
this.tabs = inspectorViews.map(view => {
|
||||||
|
return {
|
||||||
|
key: view.key,
|
||||||
|
name: view.name,
|
||||||
|
glyph: view.glyph ?? 'icon-object',
|
||||||
|
showTab: view.showTab
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isSelected(tab) {
|
||||||
|
return this.selectedTab?.key === tab.key;
|
||||||
|
},
|
||||||
|
selectTab(tab) {
|
||||||
|
this.selectedTab = tab;
|
||||||
|
this.$emit('select-tab', tab);
|
||||||
|
},
|
||||||
|
selectDefaultTabIfSelectedNotVisible() {
|
||||||
|
const selectedTabIsVisible = this.visibleTabs.some(tab => this.isSelected(tab));
|
||||||
|
|
||||||
|
if (!selectedTabIsVisible) {
|
||||||
|
this.selectTab(this.visibleTabs[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -21,41 +21,65 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div aria-label="Inspector Views"></div>
|
<div
|
||||||
|
class="c-inspector__content"
|
||||||
|
role="tabpanel"
|
||||||
|
aria-label="Inspector Views"
|
||||||
|
></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
data() {
|
props: {
|
||||||
return {
|
selectedTab: {
|
||||||
selection: []
|
type: Object,
|
||||||
};
|
default: undefined
|
||||||
},
|
},
|
||||||
mounted() {
|
selection: {
|
||||||
this.openmct.selection.on('change', this.updateSelection);
|
type: Array,
|
||||||
this.updateSelection(this.openmct.selection.get());
|
default: () => {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
destroyed() {
|
watch: {
|
||||||
this.openmct.selection.off('change', this.updateSelection);
|
selection() {
|
||||||
|
this.updateSelectionViews();
|
||||||
|
},
|
||||||
|
selectedTab() {
|
||||||
|
this.clearAndShowViewsForTab();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateSelection(selection) {
|
updateSelectionViews(selection) {
|
||||||
this.selection = selection;
|
this.clearViews();
|
||||||
|
this.selectedViews = this.openmct.inspectorViews.get(this.selection);
|
||||||
if (this.selectedViews) {
|
this.showViewsForTab();
|
||||||
this.selectedViews.forEach(selectedView => {
|
},
|
||||||
selectedView.destroy();
|
clearViews() {
|
||||||
|
if (this.visibleViews) {
|
||||||
|
this.visibleViews.forEach(visibleView => {
|
||||||
|
visibleView.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.visibleViews = [];
|
||||||
this.$el.innerHTML = '';
|
this.$el.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
showViewsForTab() {
|
||||||
|
this.visibleViews = this.selectedViews
|
||||||
|
.filter(view => view.key === this.selectedTab.key);
|
||||||
|
|
||||||
this.selectedViews = this.openmct.inspectorViews.get(selection);
|
this.visibleViews.forEach(visibleView => {
|
||||||
this.selectedViews.forEach(selectedView => {
|
|
||||||
let viewContainer = document.createElement('div');
|
let viewContainer = document.createElement('div');
|
||||||
this.$el.append(viewContainer);
|
this.$el.append(viewContainer);
|
||||||
selectedView.show(viewContainer);
|
visibleView.show(viewContainer);
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
clearAndShowViewsForTab() {
|
||||||
|
this.clearViews();
|
||||||
|
this.showViewsForTab();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -42,6 +42,41 @@
|
|||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
&.c-tabs {
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-tab {
|
||||||
|
background: $colorTabBg;
|
||||||
|
color: $colorTabFg;
|
||||||
|
padding: $interiorMargin;
|
||||||
|
|
||||||
|
&:not(.is-current) {
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
background-image: linear-gradient(90deg, transparent 0%, rgba($colorTabBg, 1) 70%);
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 15px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-current {
|
||||||
|
background: $colorTabCurrentBg;
|
||||||
|
color: $colorTabCurrentFg;
|
||||||
|
padding-right: $interiorMargin + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
@ -93,6 +128,11 @@
|
|||||||
@include propertiesHeader();
|
@include propertiesHeader();
|
||||||
font-size: 0.65rem;
|
font-size: 0.65rem;
|
||||||
grid-column: 1 / 3;
|
grid-column: 1 / 3;
|
||||||
|
margin: $interiorMargin 0;
|
||||||
|
|
||||||
|
&.--first {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-tree .grid-properties {
|
.c-tree .grid-properties {
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([], function () {
|
const DEFAULT_VIEW_PRIORITY = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A InspectorViewRegistry maintains the definitions for views
|
* A InspectorViewRegistry maintains the definitions for views
|
||||||
@ -29,7 +29,8 @@ define([], function () {
|
|||||||
* @interface InspectorViewRegistry
|
* @interface InspectorViewRegistry
|
||||||
* @memberof module:openmct
|
* @memberof module:openmct
|
||||||
*/
|
*/
|
||||||
function InspectorViewRegistry() {
|
export default class InspectorViewRegistry {
|
||||||
|
constructor() {
|
||||||
this.providers = {};
|
this.providers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,18 +41,25 @@ define([], function () {
|
|||||||
* which can provide views of this object
|
* which can provide views of this object
|
||||||
* @private for platform-internal use
|
* @private for platform-internal use
|
||||||
*/
|
*/
|
||||||
InspectorViewRegistry.prototype.get = function (selection) {
|
get(selection) {
|
||||||
return this.getAllProviders().filter(function (provider) {
|
function byPriority(providerA, providerB) {
|
||||||
return provider.canView(selection);
|
const priorityA = providerA.priority?.() ?? DEFAULT_VIEW_PRIORITY;
|
||||||
}).map(provider => provider.view(selection));
|
const priorityB = providerB.priority?.() ?? DEFAULT_VIEW_PRIORITY;
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
return priorityB - priorityA;
|
||||||
* @private
|
}
|
||||||
*/
|
|
||||||
InspectorViewRegistry.prototype.getAllProviders = function () {
|
return this.#getAllProviders()
|
||||||
return Object.values(this.providers);
|
.filter(provider => provider.canView(selection))
|
||||||
};
|
.map(provider => {
|
||||||
|
const view = provider.view(selection);
|
||||||
|
view.key = provider.key;
|
||||||
|
view.name = provider.name;
|
||||||
|
view.glyph = provider.glyph;
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}).sort(byPriority);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a new type of view.
|
* Registers a new type of view.
|
||||||
@ -60,26 +68,33 @@ define([], function () {
|
|||||||
* @method addProvider
|
* @method addProvider
|
||||||
* @memberof module:openmct.InspectorViewRegistry#
|
* @memberof module:openmct.InspectorViewRegistry#
|
||||||
*/
|
*/
|
||||||
InspectorViewRegistry.prototype.addProvider = function (provider) {
|
addProvider(provider) {
|
||||||
const key = provider.key;
|
const key = provider.key;
|
||||||
|
const name = provider.name;
|
||||||
|
|
||||||
if (key === undefined) {
|
if (key === undefined) {
|
||||||
throw "View providers must have a unique 'key' property defined";
|
throw "View providers must have a unique 'key' property defined";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name === undefined) {
|
||||||
|
throw "View providers must have a 'name' property defined";
|
||||||
|
}
|
||||||
|
|
||||||
if (this.providers[key] !== undefined) {
|
if (this.providers[key] !== undefined) {
|
||||||
console.warn("Provider already defined for key '%s'. Provider keys must be unique.", key);
|
console.warn(`Provider already defined for key '${key}'. Provider keys must be unique.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.providers[key] = provider;
|
this.providers[key] = provider;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
getByProviderKey(key) {
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
InspectorViewRegistry.prototype.getByProviderKey = function (key) {
|
|
||||||
return this.providers[key];
|
return this.providers[key];
|
||||||
};
|
}
|
||||||
|
|
||||||
|
#getAllProviders() {
|
||||||
|
return Object.values(this.providers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A View is used to provide displayable content, and to react to
|
* A View is used to provide displayable content, and to react to
|
||||||
@ -144,6 +159,3 @@ define([], function () {
|
|||||||
* @param {module:openmct.selection} selection the selection object
|
* @param {module:openmct.selection} selection the selection object
|
||||||
* @returns {module:openmct.View} a view of this selection
|
* @returns {module:openmct.View} a view of this selection
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return InspectorViewRegistry;
|
|
||||||
});
|
|
||||||
|
Reference in New Issue
Block a user