diff --git a/e2e/tests/functional/plugins/lad/lad.e2e.spec.js b/e2e/tests/functional/plugins/lad/lad.e2e.spec.js index c14d769535..aa295bc4c7 100644 --- a/e2e/tests/functional/plugins/lad/lad.e2e.spec.js +++ b/e2e/tests/functional/plugins/lad/lad.e2e.spec.js @@ -23,6 +23,88 @@ const { test, expect } = require('../../../../pluginFixtures'); const { createDomainObjectWithDefaults, setStartOffset, setFixedTimeMode, setRealTimeMode } = require('../../../../appActions'); +test.describe('Testing LAD table configuration', () => { + test.beforeEach(async ({ page }) => { + await page.goto('./', { waitUntil: 'networkidle' }); + + // Create Sine Wave Generator + await createDomainObjectWithDefaults(page, { + type: 'Sine Wave Generator', + name: "Test Sine Wave Generator" + }); + + // Create LAD table + await createDomainObjectWithDefaults(page, { + type: 'LAD Table', + name: "Test LAD Table" + }); + }); + test('in edit mode, LAD Tables provide ability to hide columns', async ({ page }) => { + // Edit LAD table + await page.locator('[title="Edit"]').click(); + + // Expand the 'My Items' folder in the left tree + await page.locator('.c-tree__item__view-control.c-disclosure-triangle').click(); + // Add the Sine Wave Generator to the LAD table and save changes + await page.dragAndDrop('role=treeitem[name=/Test Sine Wave Generator/]', '.c-lad-table-wrapper'); + // select configuration tab in inspector + await page.getByRole('tab', { name: 'LAD Table Configuration' }).getByText('LAD Table Configuration').click(); + + // make sure headers are visible initially + await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Units' })).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(); + + // hide units column + await page.getByLabel('Units').uncheck(); + await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeHidden(); + await expect(page.getByRole('cell', { name: 'Units' })).toBeHidden(); + + // save and reload and verify they columns are still hidden + 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' })).toBeHidden(); + await expect(page.getByRole('cell', { name: 'Units' })).toBeHidden(); + + // Edit LAD table + await page.locator('[title="Edit"]').click(); + await page.getByRole('tab', { name: 'LAD Table Configuration' }).getByText('LAD Table Configuration').click(); + + // show timestamp column + await page.getByLabel('Timestamp').check(); + await expect(page.getByRole('cell', { name: 'Units' })).toBeHidden(); + await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); + + // save and reload and make sure only timestamp is 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: 'Units' })).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 + await page.getByLabel('Units').check(); + await expect(page.getByRole('cell', { name: 'Timestamp' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Units' })).toBeVisible(); + + // save and reload and make sure both 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(); + }); +}); + test.describe('Testing LAD table @unstable', () => { let sineWaveObject; test.beforeEach(async ({ page }) => { diff --git a/src/plugins/LADTable/LADTableConfiguration.js b/src/plugins/LADTable/LADTableConfiguration.js new file mode 100644 index 0000000000..064a536548 --- /dev/null +++ b/src/plugins/LADTable/LADTableConfiguration.js @@ -0,0 +1,56 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2023, 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 EventEmitter from 'EventEmitter'; + +export default class LADTableConfiguration extends EventEmitter { + constructor(domainObject, openmct) { + super(); + + this.domainObject = domainObject; + this.openmct = openmct; + + this.objectMutated = this.objectMutated.bind(this); + this.unlistenFromMutation = openmct.objects.observe(domainObject, 'configuration', this.objectMutated); + } + + getConfiguration() { + const configuration = this.domainObject.configuration || {}; + configuration.hiddenColumns = configuration.hiddenColumns || {}; + + return configuration; + } + + updateConfiguration(configuration) { + this.openmct.objects.mutate(this.domainObject, 'configuration', configuration); + } + + objectMutated(configuration) { + if (configuration !== undefined) { + this.emit('change', configuration); + } + } + + destroy() { + this.unlistenFromMutation(); + } +} diff --git a/src/plugins/LADTable/LADTableConfigurationViewProvider.js b/src/plugins/LADTable/LADTableConfigurationViewProvider.js new file mode 100644 index 0000000000..1e0c012e22 --- /dev/null +++ b/src/plugins/LADTable/LADTableConfigurationViewProvider.js @@ -0,0 +1,67 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2023, 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 LADTableConfigurationComponent from './components/LADTableConfiguration.vue'; +import Vue from 'vue'; + +export default function LADTableConfigurationViewProvider(openmct) { + return { + key: 'lad-table-configuration', + name: 'LAD Table Configuration', + canView(selection) { + if (selection.length !== 1 || selection[0].length === 0) { + return false; + } + + const object = selection[0][0].context.item; + + return object?.type === 'LadTable' || object?.type === 'LadTableSet'; + }, + view(selection) { + let component; + + return { + show(element) { + component = new Vue({ + el: element, + components: { + LADTableConfiguration: LADTableConfigurationComponent + }, + provide: { + openmct + }, + template: '' + }); + }, + destroy() { + if (component) { + component.$destroy(); + component = undefined; + } + } + }; + }, + priority() { + return 1; + } + }; +} diff --git a/src/plugins/LADTable/LADTableView.js b/src/plugins/LADTable/LADTableView.js index e7dd15b209..5ce760e819 100644 --- a/src/plugins/LADTable/LADTableView.js +++ b/src/plugins/LADTable/LADTableView.js @@ -1,5 +1,27 @@ -import LadTable from './components/LADTable.vue'; +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2023, 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 LadTable from './components/LADTable.vue'; +import LADTableConfiguration from './LADTableConfiguration'; import Vue from 'vue'; export default class LADTableView { @@ -11,6 +33,8 @@ export default class LADTableView { } show(element) { + let ladTableConfiguration = new LADTableConfiguration(this.domainObject, this.openmct); + this.component = new Vue({ el: element, components: { @@ -18,7 +42,8 @@ export default class LADTableView { }, provide: { openmct: this.openmct, - currentView: this + currentView: this, + ladTableConfiguration }, data: () => { return { diff --git a/src/plugins/LADTable/LadTableSetView.js b/src/plugins/LADTable/LadTableSetView.js index 7a8d13a5f6..165d9760f9 100644 --- a/src/plugins/LADTable/LadTableSetView.js +++ b/src/plugins/LADTable/LadTableSetView.js @@ -1,5 +1,27 @@ -import LadTableSet from './components/LadTableSet.vue'; +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2023, 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 LadTableSet from './components/LadTableSet.vue'; +import LADTableConfiguration from './LADTableConfiguration'; import Vue from 'vue'; export default class LadTableSetView { @@ -11,6 +33,8 @@ export default class LadTableSetView { } show(element) { + let ladTableConfiguration = new LADTableConfiguration(this.domainObject, this.openmct); + this.component = new Vue({ el: element, components: { @@ -19,7 +43,8 @@ export default class LadTableSetView { provide: { openmct: this.openmct, objectPath: this.objectPath, - currentView: this + currentView: this, + ladTableConfiguration }, data: () => { return { diff --git a/src/plugins/LADTable/components/LADRow.vue b/src/plugins/LADTable/components/LADRow.vue index 62bcc1fdfc..a89411ba45 100644 --- a/src/plugins/LADTable/components/LADRow.vue +++ b/src/plugins/LADTable/components/LADRow.vue @@ -26,7 +26,10 @@ @contextmenu.prevent="showContextMenu" > {{ domainObject.name }} - {{ formattedTimestamp }} + {{ formattedTimestamp }} Name - Timestamp + Timestamp Value - Unit + Units @@ -42,6 +42,7 @@ :path-to-table="objectPath" :has-units="hasUnits" :is-stale="staleObjects.includes(ladRow.key)" + :configuration="configuration" @rowContextClick="updateViewContext" /> @@ -58,7 +59,7 @@ export default { components: { LadRow }, - inject: ['openmct', 'currentView'], + inject: ['openmct', 'currentView', 'ladTableConfiguration'], props: { domainObject: { type: Object, @@ -73,7 +74,8 @@ export default { return { items: [], viewContext: {}, - staleObjects: [] + staleObjects: [], + configuration: this.ladTableConfiguration.getConfiguration() }; }, computed: { @@ -86,7 +88,10 @@ export default { }); - return itemsWithUnits.length !== 0; + return itemsWithUnits.length !== 0 && !this.configuration?.hiddenColumns?.units; + }, + showTimestamp() { + return !this.configuration?.hiddenColumns?.timestamp; }, staleClass() { if (this.staleObjects.length !== 0) { @@ -97,6 +102,7 @@ export default { } }, mounted() { + this.ladTableConfiguration.on('change', this.handleConfigurationChange); this.composition = this.openmct.composition.get(this.domainObject); this.composition.on('add', this.addItem); this.composition.on('remove', this.removeItem); @@ -105,6 +111,8 @@ export default { this.stalenessSubscription = {}; }, destroyed() { + this.ladTableConfiguration.off('change', this.handleConfigurationChange); + this.composition.off('add', this.addItem); this.composition.off('remove', this.removeItem); this.composition.off('reorder', this.reorder); @@ -156,6 +164,9 @@ export default { return metadataWithUnits.length > 0; }, + handleConfigurationChange(configuration) { + this.configuration = configuration; + }, handleStaleness(id, stalenessResponse, skipCheck = false) { if (skipCheck || this.stalenessSubscription[id].stalenessUtils.shouldUpdateStaleness(stalenessResponse)) { const index = this.staleObjects.indexOf(id); diff --git a/src/plugins/LADTable/components/LADTableConfiguration.vue b/src/plugins/LADTable/components/LADTableConfiguration.vue new file mode 100644 index 0000000000..5895b0be54 --- /dev/null +++ b/src/plugins/LADTable/components/LADTableConfiguration.vue @@ -0,0 +1,249 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2023, 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. + *****************************************************************************/ + + + + diff --git a/src/plugins/LADTable/components/LadTableSet.vue b/src/plugins/LADTable/components/LadTableSet.vue index 757fe0ffb6..fe28b699d9 100644 --- a/src/plugins/LADTable/components/LadTableSet.vue +++ b/src/plugins/LADTable/components/LadTableSet.vue @@ -29,9 +29,9 @@ Name - Timestamp + Timestamp Value - Unit + Units @@ -53,6 +53,7 @@ :path-to-table="ladTable.objectPath" :has-units="hasUnits" :is-stale="staleObjects.includes(combineKeys(ladTable.key, ladRow.key))" + :configuration="configuration" @rowContextClick="updateViewContext" /> @@ -70,7 +71,7 @@ export default { components: { LadRow }, - inject: ['openmct', 'objectPath', 'currentView'], + inject: ['openmct', 'objectPath', 'currentView', 'ladTableConfiguration'], props: { domainObject: { type: Object, @@ -83,12 +84,15 @@ export default { ladTelemetryObjects: {}, compositions: [], viewContext: {}, - staleObjects: [] + staleObjects: [], + configuration: this.ladTableConfiguration.getConfiguration() }; }, computed: { hasUnits() { - let ladTables = Object.values(this.ladTelemetryObjects); + const ladTables = Object.values(this.ladTelemetryObjects); + let showUnits = false; + for (let ladTable of ladTables) { for (let telemetryObject of ladTable) { let metadata = this.openmct.telemetry.getMetadata(telemetryObject.domainObject); @@ -96,14 +100,17 @@ export default { if (metadata) { for (let metadatum of metadata.valueMetadatas) { if (metadatum.unit) { - return true; + showUnits = true; } } } } } - return false; + return showUnits && !this.configuration?.hiddenColumns?.units; + }, + showTimestamp() { + return !this.configuration?.hiddenColumns?.timestamp; }, staleClass() { if (this.staleObjects.length !== 0) { @@ -114,6 +121,7 @@ export default { } }, mounted() { + this.ladTableConfiguration.on('change', this.handleConfigurationChange); this.composition = this.openmct.composition.get(this.domainObject); this.composition.on('add', this.addLadTable); this.composition.on('remove', this.removeLadTable); @@ -123,6 +131,7 @@ export default { this.stalenessSubscription = {}; }, destroyed() { + this.ladTableConfiguration.off('change', this.handleConfigurationChange); this.composition.off('add', this.addLadTable); this.composition.off('remove', this.removeLadTable); this.composition.off('reorder', this.reorderLadTables); @@ -230,6 +239,9 @@ export default { delete this.stalenessSubscription[combinedKey]; }, + handleConfigurationChange(configuration) { + this.configuration = configuration; + }, handleStaleness(combinedKey, stalenessResponse, skipCheck = false) { if (skipCheck || this.stalenessSubscription[combinedKey].stalenessUtils.shouldUpdateStaleness(stalenessResponse)) { const index = this.staleObjects.indexOf(combinedKey); diff --git a/src/plugins/LADTable/plugin.js b/src/plugins/LADTable/plugin.js index 3bca6106fc..8066b17706 100644 --- a/src/plugins/LADTable/plugin.js +++ b/src/plugins/LADTable/plugin.js @@ -22,12 +22,14 @@ import LADTableViewProvider from './LADTableViewProvider'; import LADTableSetViewProvider from './LADTableSetViewProvider'; import ladTableCompositionPolicy from './LADTableCompositionPolicy'; +import LADTableConfigurationViewProvider from './LADTableConfigurationViewProvider'; export default function plugin() { return function install(openmct) { openmct.objectViews.addProvider(new LADTableViewProvider(openmct)); openmct.objectViews.addProvider(new LADTableSetViewProvider(openmct)); + openmct.inspectorViews.addProvider(new LADTableConfigurationViewProvider(openmct)); openmct.types.addType('LadTable', { name: "LAD Table",