Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Inspector Tabs] Updates #7987

Open
wants to merge 49 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
e196958
added getTypes to types api, modifying which tabs are shown, working …
jvigliotta Dec 20, 2024
128f482
moving hasNumericTelemetry to an api method
jvigliotta Dec 20, 2024
1326693
updated types api to return all types, updated annotations api to ret…
jvigliotta Dec 20, 2024
cded8fc
not sure if scatter plots are annotatable
jvigliotta Dec 20, 2024
bac8c80
added annotation tab conditions
jvigliotta Dec 30, 2024
3cba87d
clean up the new hasNumericTelemetry method in the telemetry api
jvigliotta Dec 30, 2024
cc99f19
moving to canView, since that is where the logic should be
jvigliotta Dec 31, 2024
0912f5f
anytime a selection is updated, select the first (top priority) tab
jvigliotta Jan 7, 2025
59f855a
Merge branch 'mct-7442' into mct-7959
jvigliotta Jan 15, 2025
ffa6ea6
Changes for tabs visibility and priority
charlesh88 Jan 16, 2025
9f1cac5
Changes for tabs visibility and priority
charlesh88 Jan 16, 2025
f199ce5
Changes for tabs visibility and priority
charlesh88 Jan 16, 2025
b09b9e0
Changes for tabs visibility and priority
charlesh88 Jan 16, 2025
97292d4
update selection views on edit state change
jvigliotta Jan 16, 2025
e7eb070
adding edit listener to inspector tabs component as well
jvigliotta Jan 16, 2025
7cd1517
intitializing display layouts with objectStyles properties, so styles…
jvigliotta Jan 16, 2025
4202de9
initialize and backfill object styles config prop for flex layouts
jvigliotta Jan 16, 2025
f4f010a
if editing and styles tab is selected and it exists for the next item…
jvigliotta Jan 16, 2025
3527e4e
Changes for tabs visibility and priority
charlesh88 Jan 17, 2025
087fbd3
Changes for tabs visibility and priority
charlesh88 Jan 17, 2025
1934aea
Show Annotations for Overlay and Stacked p
jvigliotta Jan 22, 2025
567aa69
fix error in lad table config component
jvigliotta Jan 22, 2025
f7d78c1
Properties tab should not show for non-domain objects
jvigliotta Jan 22, 2025
1d4353b
Notebook should only show Annotations tab when an entry is selected, …
jvigliotta Jan 22, 2025
91a9fa5
make sure older objects not initialized with object styles are checked
jvigliotta Jan 23, 2025
175befa
initalize tables with objectStyles
jvigliotta Jan 23, 2025
d92a2b7
initial e2e tests
jvigliotta Feb 10, 2025
9d92ba9
add clock to no styles objects, initialize event message generators w…
jvigliotta Feb 11, 2025
e985c08
removing styles for event message generators, they dont have edit mode
jvigliotta Feb 11, 2025
fffa773
only add missing object styles if table has configuration
jvigliotta Feb 11, 2025
310bd17
stopping point
jvigliotta Feb 12, 2025
efd7369
WIP
jvigliotta Feb 14, 2025
a207e97
finishing up main views tests and updating some providers to fix errors
jvigliotta Feb 21, 2025
243bc2b
couple changes
jvigliotta Feb 21, 2025
850c015
update comment
jvigliotta Feb 21, 2025
19ee3e5
update helper method name, simplify isAnnotatableType method
jvigliotta Mar 3, 2025
367e494
remove commented code
jvigliotta Mar 3, 2025
f530e99
adding condition widget styles get interceptor
jvigliotta Mar 3, 2025
439c3de
rename
jvigliotta Mar 3, 2025
c385c90
rename
jvigliotta Mar 3, 2025
97ae8db
add styles get interceptor for overlay plots
jvigliotta Mar 3, 2025
f98cabe
make missing object interceptor run first, so other interceptors dont…
jvigliotta Mar 3, 2025
8655434
update previous interceptors and add for stacked plot
jvigliotta Mar 3, 2025
1a59b89
adding styles interceptor for telemetry tables
jvigliotta Mar 3, 2025
4c0791f
remove targeted plugin styling exclusion in browse mode
jvigliotta Mar 5, 2025
07eaac2
Merge branch 'master' into mct-7442-7959
jvigliotta Mar 5, 2025
8b2d77c
lint fixes
jvigliotta Mar 5, 2025
5ee9b66
Merge branch 'mct-7442-7959' of https://github.com/nasa/openmct into …
jvigliotta Mar 5, 2025
0deb2bf
removed save from interceptors and kept missing object intercepter as is
jvigliotta Mar 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,8 @@
"darkmatter",
"Undeletes",
"SSSZ",
"pageerror"
"pageerror",
"annotatable"
],
"dictionaries": ["npm", "softwareTerms", "node", "html", "css", "bash", "en_US", "en-gb", "misc"],
"ignorePaths": [
Expand Down
13 changes: 12 additions & 1 deletion e2e/appActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ import { v4 as genUuid } from 'uuid';
* @param {string | import('../src/api/objects/ObjectAPI').Identifier} [options.parent='mine'] - The Identifier or uuid of the parent object. Defaults to 'mine' folder
* @returns {Promise<CreatedObjectInfo>} An object containing information about the newly created domain object.
*/
async function createDomainObjectWithDefaults(page, { type, name, parent = 'mine' }) {
async function createDomainObjectWithDefaults(
page,
{ type, name, parent = 'mine' },
additionalOptions = {}
) {
if (!name) {
name = `${type}:${genUuid()}`;
}
Expand All @@ -89,6 +93,13 @@ async function createDomainObjectWithDefaults(page, { type, name, parent = 'mine
await page.getByLabel('Title', { exact: true }).fill('');
await page.getByLabel('Title', { exact: true }).fill(name);

if (additionalOptions) {
for (const [key, value] of Object.entries(additionalOptions)) {
// eslint-disable-next-line playwright/no-raw-locators
await page.locator(`#form-${key}`).fill(value);
}
}

if (page.testNotes) {
// Fill the "Notes" section with information about the
// currently running test and its project.
Expand Down
2 changes: 1 addition & 1 deletion e2e/helper/planningUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export async function createTimelistWithPlanAndSetActivityInProgress(page, planJ
await page.getByRole('button', { name: 'Edit Object' }).click();

// Find the display properties section in the inspector
await page.getByRole('tab', { name: 'View Properties' }).click();
await page.getByRole('tab', { name: 'Config' }).click();
// Switch to expanded view and save the setting
await page.getByLabel('Display Style').selectOption({ label: 'Expanded' });

Expand Down
2 changes: 1 addition & 1 deletion e2e/tests/functional/planning/timelist.e2e.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ test("View a timelist in expanded view, verify all the activities are displayed
await page.getByRole('button', { name: 'Edit Object' }).click();

// Find the display properties section in the inspector
await page.getByRole('tab', { name: 'View Properties' }).click();
await page.getByRole('tab', { name: 'Config' }).click();
// Switch to expanded view and save the setting
await page.getByLabel('Display Style').selectOption({ label: 'Expanded' });

Expand Down
8 changes: 4 additions & 4 deletions e2e/tests/functional/plugins/lad/lad.e2e.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ test.describe('Testing LAD table configuration', () => {
test('in edit mode, LAD Tables provide ability to hide columns', async ({ page }) => {
// Edit LAD table
await page.getByLabel('Edit Object').click();
await page.getByRole('tab', { name: 'LAD Table Configuration' }).click();
await page.getByRole('tab', { name: 'Config' }).click();

// make sure headers are visible initially
await expect(page.getByRole('columnheader', { name: 'Timestamp', exact: true })).toBeVisible();
Expand Down Expand Up @@ -114,7 +114,7 @@ test.describe('Testing LAD table configuration', () => {

// Edit LAD table
await page.getByLabel('Edit Object').click();
await page.getByRole('tab', { name: 'LAD Table Configuration' }).click();
await page.getByRole('tab', { key: 'lad-table-configuration' }).click();

// show timestamp column
await page.getByLabel('Timestamp', { exact: true }).check();
Expand Down Expand Up @@ -142,7 +142,7 @@ test.describe('Testing LAD table configuration', () => {

// Edit LAD table
await page.getByLabel('Edit Object').click();
await page.getByRole('tab', { name: 'LAD Table Configuration' }).click();
await page.getByRole('tab', { key: 'lad-table-configuration' }).click();

// show units, type, and WATCH columns
await page.getByLabel('Units').check();
Expand Down Expand Up @@ -182,7 +182,7 @@ test.describe('Testing LAD table configuration', () => {

// Edit LAD table
await page.getByLabel('Edit Object').click();
await page.getByRole('tab', { name: 'LAD Table Configuration' }).click();
await page.getByRole('tab', { key: 'lad-table-configuration' }).click();

// make sure Sine Wave headers are visible initially too
await expect(page.getByRole('columnheader', { name: 'Timestamp', exact: true })).toBeVisible();
Expand Down
145 changes: 145 additions & 0 deletions e2e/tests/functional/ui/inspector.e2e.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable playwright/no-conditional-in-test */
/* eslint-disable playwright/no-conditional-expect */
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, United States Government
* as represented by the Administrator of the National Aeronautics and Space
Expand Down Expand Up @@ -31,6 +33,104 @@ Enim nec dui nunc mattis. Cursus turpis massa tincidunt dui ut. Donec adipiscing
Proin libero nunc consequat interdum varius sit amet mattis vulputate. Metus dictum at tempor commodo ullamcorper a lacus vestibulum sed. Quisque non tellus orci ac auctor augue mauris. Id ornare arcu odio ut. Rhoncus est pellentesque elit ullamcorper dignissim. Senectus et netus et malesuada fames ac turpis egestas. Volutpat ac tincidunt vitae semper quis lectus nulla. Adipiscing elit duis tristique sollicitudin. Ipsum faucibus vitae aliquet nec ullamcorper sit. Gravida neque convallis a cras semper auctor neque vitae tempus. Porttitor leo a diam sollicitudin tempor id. Dictum non consectetur a erat nam at lectus. At volutpat diam ut venenatis tellus in. Morbi enim nunc faucibus a pellentesque sit amet. Cursus in hac habitasse platea. Sed augue lacus viverra vitae.
`;

const viewsTabsMatrix = {
Clock: {
Browse: ['Properties']
},
'Condition Set': {
Browse: ['Properties', 'Elements', 'Annotations'],
Edit: ['Elements', 'Properties']
},
'Condition Widget': {
Browse: ['Properties', 'Styles'],
Edit: ['Styles', 'Properties']
},
'Display Layout': {
Browse: ['Properties', 'Elements', 'Styles'],
Edit: ['Elements', 'Styles', 'Properties']
},
'Event Message Generator': {
Browse: ['Properties']
},
'Event Message Generator with Acknowledge': {
Browse: ['Properties']
},
'Example Imagery': {
Browse: ['Properties', 'Annotations']
},
'Flexible Layout': {
Browse: ['Properties', 'Elements', 'Styles'],
Edit: ['Elements', 'Styles', 'Properties']
},
Folder: {
Browse: ['Properties']
},
'Gantt Chart': {
Browse: ['Properties', 'Config', 'Elements'],
Edit: ['Config', 'Elements', 'Properties']
},
Gauge: {
Browse: ['Properties', 'Elements', 'Styles'],
Edit: ['Elements', 'Styles', 'Properties']
},
Graph: {
Browse: ['Properties', 'Config', 'Elements', 'Styles'],
Edit: ['Config', 'Elements', 'Styles', 'Properties']
},
Hyperlink: {
Browse: ['Properties'],
required: {
url: 'https://www.google.com',
displayText: 'Google'
}
},
'LAD Table': {
Browse: ['Properties', 'Config', 'Elements', 'Styles'],
Edit: ['Config', 'Elements', 'Styles', 'Properties']
},
'LAD Table Set': {
Browse: ['Properties', 'Config', 'Elements', 'Styles'],
Edit: ['Config', 'Elements', 'Styles', 'Properties']
},
Notebook: {
Browse: ['Properties']
},
'Overlay Plot': {
Browse: ['Properties', 'Config', 'Annotations', 'Styles'],
Edit: ['Config', 'Elements', 'Styles', 'Filters', 'Properties']
},
'Scatter Plot': {
Browse: ['Properties', 'Config', 'Elements', 'Styles'],
Edit: ['Config', 'Elements', 'Styles', 'Properties']
},
'Sine Wave Generator': {
Browse: ['Properties', 'Annotations']
},
'Stacked Plot': {
Browse: ['Properties', 'Config', 'Annotations', 'Elements', 'Styles'],
Edit: ['Config', 'Elements', 'Styles', 'Properties']
},
'Tabs View': {
Browse: ['Properties', 'Elements', 'Styles'],
Edit: ['Elements', 'Styles', 'Properties']
},
'Telemetry Table': {
Browse: ['Properties', 'Config', 'Elements', 'Styles'],
Edit: ['Config', 'Elements', 'Styles', 'Filters', 'Properties']
},
'Time List': {
Browse: ['Properties', 'Config', 'Elements'],
Edit: ['Config', 'Elements', 'Properties']
},
'Time Strip': {
Browse: ['Properties', 'Elements'],
Edit: ['Elements', 'Properties']
},
Timer: {
Browse: ['Properties']
}
};

test.describe('Inspector tests', () => {
test.beforeEach(async ({ page }) => {
await page.goto('./', { waitUntil: 'domcontentloaded' });
Expand Down Expand Up @@ -72,4 +172,49 @@ test.describe('Inspector tests', () => {

await expect(lastInspectorPropertyValue).toBeInViewport();
});

test(`Inspector tabs show the correct tabs per view and mode`, async ({ page }) => {
// loop through each view type
for (const view of Object.keys(viewsTabsMatrix)) {
const viewConfig = viewsTabsMatrix[view];
const createOptions = {
type: view,
name: view
};

// create and navigate to view;
const objectInfo = await createDomainObjectWithDefaults(
page,
createOptions,
viewConfig.required ? viewConfig.required : {}
);
await page.goto(objectInfo.url);

// verify correct number of tabs for browse mode
expect(await page.getByRole('tab').count()).toBe(Object.keys(viewConfig.Browse).length);

// verify correct order of tabs for browse mode
for (const [index, value] of Object.entries(viewConfig.Browse)) {
const tab = page.getByRole('tab').nth(index);
await expect(tab).toHaveText(value);
}

// enter Edit if necessary
if (viewConfig.Edit) {
await page.getByLabel('Edit Object').click();

// verify correct number of tabs for edit mode
expect(await page.getByRole('tab').count()).toBe(Object.keys(viewConfig.Edit).length);

// verify correct order of tabs for edit mode
for (const [index, value] of Object.entries(viewConfig.Edit)) {
const tab = page.getByRole('tab').nth(index);
await expect(tab).toHaveText(value);
}

await page.getByLabel('Save').first().click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
}
}
});
});
11 changes: 11 additions & 0 deletions src/api/annotation/AnnotationAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -582,4 +582,15 @@ export default class AnnotationAPI extends EventEmitter {
_.isEqual(targets, otherTargets)
);
}

/**
* Checks if the given type is annotatable
* @param {string} type The type to check
* @returns {boolean} Returns true if the type is annotatable
*/
isAnnotatableType(type) {
const types = this.openmct.types.getAllTypes();

return types[type]?.definition?.annotatable;
}
}
27 changes: 27 additions & 0 deletions src/api/telemetry/TelemetryAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,33 @@
return value;
}

/**
* Determines whether a domain object has numeric telemetry data.
* A domain object has numeric telemetry if it:
* 1. Has a telemetry property
* 2. Has telemetry metadata with domain values (like timestamps)
* 3. Has range values (measurements) where at least one is numeric
*
* @method hasNumericTelemetry
* @param {import('openmct').DomainObject} domainObject The domain object to check
* @returns {boolean} True if the object has numeric telemetry, false otherwise
*/
hasNumericTelemetry(domainObject) {
if (!Object.prototype.hasOwnProperty.call(domainObject, 'telemetry')) {
return false;
}

const metadata = this.openmct.telemetry.getMetadata(domainObject);
const rangeValues = metadata.valuesForHints(['range']);
const domains = metadata.valuesForHints(['domain']);

Check warning on line 305 in src/api/telemetry/TelemetryAPI.js

View check run for this annotation

Codecov / codecov/patch

src/api/telemetry/TelemetryAPI.js#L303-L305

Added lines #L303 - L305 were not covered by tests

return (

Check warning on line 307 in src/api/telemetry/TelemetryAPI.js

View check run for this annotation

Codecov / codecov/patch

src/api/telemetry/TelemetryAPI.js#L307

Added line #L307 was not covered by tests
domains.length > 0 &&
rangeValues.length > 0 &&
!rangeValues.every((value) => value.format === 'string')

Check warning on line 310 in src/api/telemetry/TelemetryAPI.js

View check run for this annotation

Codecov / codecov/patch

src/api/telemetry/TelemetryAPI.js#L310

Added line #L310 was not covered by tests
);
}

/**
* Generates a numeric hash value for an options object. The hash is consistent
* for equivalent option objects regardless of property order.
Expand Down
11 changes: 11 additions & 0 deletions src/api/types/TypeRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ export default class TypeRegistry {
get(typeKey) {
return this.types[typeKey] || UNKNOWN_TYPE;
}
/**
* List all registered types.
* @returns {Type[]} all registered types
*/
getAllTypes() {
return this.types;
}
/**
* Import legacy types.
* @param {TypeDefinition[]} types the types to import
*/
importLegacyTypes(types) {
types
.filter((t) => this.get(t.key) === UNKNOWN_TYPE)
Expand Down
5 changes: 3 additions & 2 deletions src/plugins/LADTable/LADTableConfiguration.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@
}

getConfiguration() {
const configuration = this.domainObject.configuration || {};
configuration.hiddenColumns = configuration.hiddenColumns || {};
const configuration = this.domainObject.configuration ?? {};
configuration.hiddenColumns = configuration.hiddenColumns ?? {};

Check warning on line 45 in src/plugins/LADTable/LADTableConfiguration.js

View check run for this annotation

Codecov / codecov/patch

src/plugins/LADTable/LADTableConfiguration.js#L44-L45

Added lines #L44 - L45 were not covered by tests
configuration.isFixedLayout = configuration.isFixedLayout ?? true;
configuration.objectStyles = configuration.objectStyles ?? {};

Check warning on line 47 in src/plugins/LADTable/LADTableConfiguration.js

View check run for this annotation

Codecov / codecov/patch

src/plugins/LADTable/LADTableConfiguration.js#L47

Added line #L47 was not covered by tests

return configuration;
}
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/LADTable/LADTableConfigurationViewProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
export default function LADTableConfigurationViewProvider(openmct) {
return {
key: 'lad-table-configuration',
name: 'LAD Table Configuration',
name: 'Config',
canView(selection) {
if (selection.length !== 1 || selection[0].length === 0) {
return false;
Expand Down Expand Up @@ -61,7 +61,7 @@
_destroy = destroy;
},
priority() {
return 1;
return openmct.editor.isEditing() ? openmct.priority.HIGH + 1 : openmct.priority.DEFAULT;

Check warning on line 64 in src/plugins/LADTable/LADTableConfigurationViewProvider.js

View check run for this annotation

Codecov / codecov/patch

src/plugins/LADTable/LADTableConfigurationViewProvider.js#L64

Added line #L64 was not covered by tests
},
destroy() {
if (_destroy) {
Expand Down
Loading
Loading