diff --git a/e2e/tests/functional/plugins/lad/lad.e2e.spec.js b/e2e/tests/functional/plugins/lad/lad.e2e.spec.js index aa295bc4c7..eb5dec56b0 100644 --- a/e2e/tests/functional/plugins/lad/lad.e2e.spec.js +++ b/e2e/tests/functional/plugins/lad/lad.e2e.spec.js @@ -53,16 +53,20 @@ test.describe('Testing LAD table configuration', () => { // make sure headers are visible initially await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); await expect(page.getByRole('cell', { name: 'Units' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Type' })).toBeVisible(); // hide timestamp column await page.getByLabel('Timestamp').uncheck(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeHidden(); await expect(page.getByRole('cell', { name: 'Units' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Type' })).toBeVisible(); - // hide units column + // hide units & type column await page.getByLabel('Units').uncheck(); + await page.getByLabel('Type').uncheck(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeHidden(); await expect(page.getByRole('cell', { name: 'Units' })).toBeHidden(); + await expect(page.getByRole('cell', { name: 'Type' })).toBeHidden(); // save and reload and verify they columns are still hidden await page.locator('button[title="Save"]').click(); @@ -70,6 +74,7 @@ test.describe('Testing LAD table configuration', () => { await page.reload(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeHidden(); await expect(page.getByRole('cell', { name: 'Units' })).toBeHidden(); + await expect(page.getByRole('cell', { name: 'Type' })).toBeHidden(); // Edit LAD table await page.locator('[title="Edit"]').click(); @@ -78,6 +83,7 @@ test.describe('Testing LAD table configuration', () => { // show timestamp column await page.getByLabel('Timestamp').check(); await expect(page.getByRole('cell', { name: 'Units' })).toBeHidden(); + await expect(page.getByRole('cell', { name: 'Type' })).toBeHidden(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); // save and reload and make sure only timestamp is still visible @@ -85,23 +91,27 @@ test.describe('Testing LAD table configuration', () => { await page.locator('text=Save and Finish Editing').click(); await page.reload(); await expect(page.getByRole('cell', { name: 'Units' })).toBeHidden(); + await expect(page.getByRole('cell', { name: 'Type' })).toBeHidden(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); // Edit LAD table await page.locator('[title="Edit"]').click(); await page.getByRole('tab', { name: 'LAD Table Configuration' }).getByText('LAD Table Configuration').click(); - // show units column + // show units and type columns await page.getByLabel('Units').check(); + await page.getByLabel('Type').check(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); await expect(page.getByRole('cell', { name: 'Units' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Type' })).toBeVisible(); - // save and reload and make sure both columns are still visible + // save and reload and make sure all columns are still visible await page.locator('button[title="Save"]').click(); await page.locator('text=Save and Finish Editing').click(); await page.reload(); await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); await expect(page.getByRole('cell', { name: 'Units' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Type' })).toBeVisible(); }); }); diff --git a/src/plugins/LADTable/components/LADRow.vue b/src/plugins/LADTable/components/LADRow.vue index a89411ba45..45b6ac7dd8 100644 --- a/src/plugins/LADTable/components/LADRow.vue +++ b/src/plugins/LADTable/components/LADRow.vue @@ -22,7 +22,8 @@ @@ -52,6 +57,9 @@ const CONTEXT_MENU_ACTIONS = [ ]; const BLANK_VALUE = '---'; +import identifierToString from '/src/tools/url'; +import PreviewAction from "@/ui/preview/PreviewAction.js"; + export default { inject: ['openmct', 'currentView'], props: { @@ -83,17 +91,28 @@ export default { datum: undefined, timestamp: undefined, timestampKey: undefined, + composition: [], unit: '' }; }, computed: { value() { - if (!this.datum) { + if (!this.datum || this.isAggregate) { return BLANK_VALUE; } return this.formats[this.valueKey].format(this.datum); }, + typeLabel() { + if (this.isAggregate) { + return 'Aggregate'; + } + + return "Telemetry"; + }, + isAggregate() { + return this.composition && this.composition.length > 0; + }, valueClasses() { let classes = []; @@ -113,7 +132,7 @@ export default { }, formattedTimestamp() { - if (!this.timestamp) { + if (!this.timestamp || this.isAggregate) { return BLANK_VALUE; } @@ -131,12 +150,19 @@ export default { }, showTimestamp() { return !this.configuration?.hiddenColumns?.timestamp; + }, + showType() { + return !this.configuration?.hiddenColumns?.type; } }, - mounted() { + async mounted() { this.metadata = this.openmct.telemetry.getMetadata(this.domainObject); this.formats = this.openmct.telemetry.getFormatMap(this.metadata); this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier); + const compositionCollection = this.openmct.composition.get(this.domainObject); + if (compositionCollection) { + this.composition = await compositionCollection.load(); + } this.timeContext = this.openmct.time.getContextForView(this.objectPath); @@ -170,11 +196,15 @@ export default { if (this.hasUnits) { this.setUnit(); } + + this.previewAction = new PreviewAction(this.openmct); + this.previewAction.on('isVisible', this.togglePreviewState); }, destroyed() { this.openmct.time.off('timeSystem', this.updateTimeSystem); this.telemetryCollection.off('add', this.setLatestValues); this.telemetryCollection.off('clear', this.resetValues); + this.previewAction.off('isVisible', this.togglePreviewState); this.telemetryCollection.destroy(); }, @@ -189,6 +219,20 @@ export default { }); } }, + clickedRow(event) { + if (this.openmct.editor.isEditing()) { + event.preventDefault(); + this.preview(this.objectPath); + } else { + const resultUrl = identifierToString(this.openmct, this.objectPath); + this.openmct.router.navigate(resultUrl); + } + }, + preview(objectPath) { + if (this.previewAction.appliesTo(objectPath)) { + this.previewAction.invoke(objectPath); + } + }, setLatestValues(data) { this.latestDatum = data[data.length - 1]; this.updateView(); diff --git a/src/plugins/LADTable/components/LADTable.vue b/src/plugins/LADTable/components/LADTable.vue index 99716e794c..93cfbcab84 100644 --- a/src/plugins/LADTable/components/LADTable.vue +++ b/src/plugins/LADTable/components/LADTable.vue @@ -32,6 +32,7 @@ Timestamp Value Units + Type @@ -93,6 +94,9 @@ export default { showTimestamp() { return !this.configuration?.hiddenColumns?.timestamp; }, + showType() { + return !this.configuration?.hiddenColumns?.type; + }, staleClass() { if (this.staleObjects.length !== 0) { return 'is-stale'; diff --git a/src/plugins/LADTable/components/LADTableConfiguration.vue b/src/plugins/LADTable/components/LADTableConfiguration.vue index 5895b0be54..06542f28be 100644 --- a/src/plugins/LADTable/components/LADTableConfiguration.vue +++ b/src/plugins/LADTable/components/LADTableConfiguration.vue @@ -74,7 +74,8 @@ export default { return { headers: { timestamp: 'Timestamp', - units: 'Units' + units: 'Units', + type: 'Type' }, ladTableConfiguration, isEditing: this.openmct.editor.isEditing(), diff --git a/src/plugins/LADTable/components/LadTableSet.vue b/src/plugins/LADTable/components/LadTableSet.vue index fe28b699d9..acca9a64b8 100644 --- a/src/plugins/LADTable/components/LadTableSet.vue +++ b/src/plugins/LADTable/components/LadTableSet.vue @@ -31,6 +31,7 @@ Name Timestamp Value + Type Units @@ -112,6 +113,9 @@ export default { showTimestamp() { return !this.configuration?.hiddenColumns?.timestamp; }, + showType() { + return !this.configuration?.hiddenColumns?.type; + }, staleClass() { if (this.staleObjects.length !== 0) { return 'is-stale'; diff --git a/src/plugins/LADTable/pluginSpec.js b/src/plugins/LADTable/pluginSpec.js index 8c18f2386b..5cc595e6d5 100644 --- a/src/plugins/LADTable/pluginSpec.js +++ b/src/plugins/LADTable/pluginSpec.js @@ -152,23 +152,42 @@ describe("The LAD Table", () => { } }).telemetry; - // add another telemetry object as composition in lad table to test multi rows - mockObj.ladTable.composition.push(anotherTelemetryObj.identifier); + const aggregateTelemetryObj = getMockObjects({ + objectKeyStrings: ['telemetry'], + overwrite: { + telemetry: { + name: "Aggregate Telemetry Object", + identifier: { + namespace: "", + key: "aggregate-telemetry-object" + } + } + } + }).telemetry; + + // add another aggregate telemetry object as composition in lad table to test multi rows + aggregateTelemetryObj.composition = [anotherTelemetryObj.identifier]; + mockObj.ladTable.composition.push(aggregateTelemetryObj.identifier); beforeEach(async () => { let telemetryRequestResolve; let telemetryObjectResolve; let anotherTelemetryObjectResolve; - let telemetryRequestPromise = new Promise((resolve) => { + let aggregateTelemetryObjectResolve; + const telemetryRequestPromise = new Promise((resolve) => { telemetryRequestResolve = resolve; }); - let telemetryObjectPromise = new Promise((resolve) => { + const telemetryObjectPromise = new Promise((resolve) => { telemetryObjectResolve = resolve; }); - let anotherTelemetryObjectPromise = new Promise((resolve) => { + const anotherTelemetryObjectPromise = new Promise((resolve) => { anotherTelemetryObjectResolve = resolve; }); + const aggregateTelemetryObjectPromise = new Promise((resolve) => { + aggregateTelemetryObjectResolve = resolve; + }); + spyOnBuiltins(['requestAnimationFrame']); window.requestAnimationFrame.and.callFake((callBack) => { callBack(); @@ -185,10 +204,14 @@ describe("The LAD Table", () => { telemetryObjectResolve(mockObj.telemetry); return telemetryObjectPromise; - } else { + } else if (obj.key === 'another-telemetry-object') { anotherTelemetryObjectResolve(anotherTelemetryObj); return anotherTelemetryObjectPromise; + } else { + aggregateTelemetryObjectResolve(aggregateTelemetryObj); + + return aggregateTelemetryObjectPromise; } }); @@ -202,7 +225,7 @@ describe("The LAD Table", () => { ladTableView = ladTableViewProvider.view(mockObj.ladTable, [mockObj.ladTable]); ladTableView.show(child, true); - await Promise.all([telemetryRequestPromise, telemetryObjectPromise, anotherTelemetryObjectPromise]); + await Promise.all([telemetryRequestPromise, telemetryObjectPromise, anotherTelemetryObjectPromise, aggregateTelemetryObjectResolve]); await Vue.nextTick(); }); @@ -217,6 +240,16 @@ describe("The LAD Table", () => { await Vue.nextTick(); const latestDate = parent.querySelector(TABLE_BODY_FIRST_ROW_SECOND_DATA).innerText; expect(latestDate).toBe(expectedDate); + const dataType = parent.querySelector(TABLE_BODY_ROWS).querySelector('.js-type-data').innerText; + expect(dataType).toBe('Telemetry'); + }); + + it("should show aggregate telemetry type with blank data", async () => { + await Vue.nextTick(); + const lastestData = parent.querySelectorAll(TABLE_BODY_ROWS)[1].querySelectorAll('td')[2].innerText; + expect(lastestData).toBe('---'); + const dataType = parent.querySelectorAll(TABLE_BODY_ROWS)[1].querySelector('.js-type-data').innerText; + expect(dataType).toBe('Aggregate'); }); it("should show the name provided for the the telemetry producing object", () => { diff --git a/src/styles/_table.scss b/src/styles/_table.scss index 528d5050ae..f610d0fb6f 100644 --- a/src/styles/_table.scss +++ b/src/styles/_table.scss @@ -150,6 +150,15 @@ div.c-table { tr:not(.c-table__group-header) + tr:not(.c-table__group-header) { border-top: 1px solid $colorTabBorder; } + transition: $transOut; + } + + &__selectable-row {cursor: pointer; + &:hover { + background: $colorListItemBgHov; + filter: $filterHov; + transition: $transIn; + } } &__group-header {