mirror of
https://github.com/nasa/openmct.git
synced 2025-06-15 13:48:12 +00:00
* fix: restore reactivity of config settings - move initialization steps to `created()` hook - remove unnecessary `:key` binds - fix comments * refactor: clean up * refactor: clean up * refactor: lint:fix * test(e2e): add regression test and cleanup suite * refactor: consistency is key! * test(fix): fix unit tests, further cleanup
This commit is contained in:
@ -29,6 +29,10 @@ const {
|
|||||||
test.describe('Flexible Layout', () => {
|
test.describe('Flexible Layout', () => {
|
||||||
let sineWaveObject;
|
let sineWaveObject;
|
||||||
let clockObject;
|
let clockObject;
|
||||||
|
let treePane;
|
||||||
|
let sineWaveGeneratorTreeItem;
|
||||||
|
let clockTreeItem;
|
||||||
|
let flexibleLayout;
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
@ -41,23 +45,27 @@ test.describe('Flexible Layout', () => {
|
|||||||
clockObject = await createDomainObjectWithDefaults(page, {
|
clockObject = await createDomainObjectWithDefaults(page, {
|
||||||
type: 'Clock'
|
type: 'Clock'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Create a Flexible Layout
|
||||||
|
flexibleLayout = await createDomainObjectWithDefaults(page, {
|
||||||
|
type: 'Flexible Layout'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define the Sine Wave Generator and Clock tree items
|
||||||
|
treePane = page.getByRole('tree', {
|
||||||
|
name: 'Main Tree'
|
||||||
|
});
|
||||||
|
sineWaveGeneratorTreeItem = treePane.getByRole('treeitem', {
|
||||||
|
name: new RegExp(sineWaveObject.name)
|
||||||
|
});
|
||||||
|
clockTreeItem = treePane.getByRole('treeitem', {
|
||||||
|
name: new RegExp(clockObject.name)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
test('panes have the appropriate draggable attribute while in Edit and Browse modes', async ({
|
test('panes have the appropriate draggable attribute while in Edit and Browse modes', async ({
|
||||||
page
|
page
|
||||||
}) => {
|
}) => {
|
||||||
const treePane = page.getByRole('tree', {
|
await page.goto(flexibleLayout.url);
|
||||||
name: 'Main Tree'
|
|
||||||
});
|
|
||||||
const sineWaveGeneratorTreeItem = treePane.getByRole('treeitem', {
|
|
||||||
name: new RegExp(sineWaveObject.name)
|
|
||||||
});
|
|
||||||
const clockTreeItem = treePane.getByRole('treeitem', {
|
|
||||||
name: new RegExp(clockObject.name)
|
|
||||||
});
|
|
||||||
// Create a Flexible Layout
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
|
||||||
type: 'Flexible Layout'
|
|
||||||
});
|
|
||||||
// Edit Flexible Layout
|
// Edit Flexible Layout
|
||||||
await page.locator('[title="Edit"]').click();
|
await page.locator('[title="Edit"]').click();
|
||||||
|
|
||||||
@ -78,19 +86,79 @@ test.describe('Flexible Layout', () => {
|
|||||||
dragWrapper = page.locator('.c-fl-container__frames-holder .c-fl-frame__drag-wrapper').first();
|
dragWrapper = page.locator('.c-fl-container__frames-holder .c-fl-frame__drag-wrapper').first();
|
||||||
await expect(dragWrapper).toHaveAttribute('draggable', 'false');
|
await expect(dragWrapper).toHaveAttribute('draggable', 'false');
|
||||||
});
|
});
|
||||||
|
test('changing toolbar settings in edit mode is immediately reflected and persists upon save', async ({
|
||||||
|
page
|
||||||
|
}) => {
|
||||||
|
test.info().annotations.push({
|
||||||
|
type: 'issue',
|
||||||
|
description: 'https://github.com/nasa/openmct/issues/6942'
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto(flexibleLayout.url);
|
||||||
|
|
||||||
|
// Expand the 'My Items' folder in the left tree
|
||||||
|
await page.locator('.c-tree__item__view-control.c-disclosure-triangle').first().click();
|
||||||
|
// Add the Sine Wave Generator and Clock to the Flexible Layout
|
||||||
|
await sineWaveGeneratorTreeItem.dragTo(page.locator('.c-fl__container.is-empty').first());
|
||||||
|
await clockTreeItem.dragTo(page.locator('.c-fl__container.is-empty'));
|
||||||
|
|
||||||
|
// Click on the first frame to select it
|
||||||
|
await page.locator('.c-fl-container__frame').first().click();
|
||||||
|
await expect(page.locator('.c-fl-container__frame > .c-frame').first()).toHaveAttribute(
|
||||||
|
's-selected',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert the toolbar is visible
|
||||||
|
await expect(page.locator('.c-toolbar')).toBeInViewport();
|
||||||
|
|
||||||
|
// Assert the layout is in columns orientation
|
||||||
|
expect(await page.locator('.c-fl--rows').count()).toEqual(0);
|
||||||
|
|
||||||
|
// Change the layout to rows orientation
|
||||||
|
await page.getByTitle('Columns layout').click();
|
||||||
|
|
||||||
|
// Assert the layout is in rows orientation
|
||||||
|
expect(await page.locator('.c-fl--rows').count()).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// Assert the frame of the first item is visible
|
||||||
|
await expect(page.locator('.c-so-view').first()).not.toHaveClass(/c-so-view--no-frame/);
|
||||||
|
|
||||||
|
// Hide the frame of the first item
|
||||||
|
await page.getByTitle('Frame visible').click();
|
||||||
|
|
||||||
|
// Assert the frame is hidden
|
||||||
|
await expect(page.locator('.c-so-view').first()).toHaveClass(/c-so-view--no-frame/);
|
||||||
|
|
||||||
|
// Assert there are 2 containers
|
||||||
|
expect(await page.locator('.c-fl-container').count()).toEqual(2);
|
||||||
|
|
||||||
|
// Add a container
|
||||||
|
await page.getByTitle('Add Container').click();
|
||||||
|
|
||||||
|
// Assert there are 3 containers
|
||||||
|
expect(await page.locator('.c-fl-container').count()).toEqual(3);
|
||||||
|
|
||||||
|
// Save Flexible Layout
|
||||||
|
await page.locator('button[title="Save"]').click();
|
||||||
|
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();
|
||||||
|
|
||||||
|
// Nav away and back
|
||||||
|
await page.goto(sineWaveObject.url);
|
||||||
|
await page.goto(flexibleLayout.url);
|
||||||
|
|
||||||
|
// Wait for the first frame to be visible so we know the layout has loaded
|
||||||
|
await expect(page.locator('.c-fl-container').nth(0)).toBeInViewport();
|
||||||
|
|
||||||
|
// Assert the settings have persisted
|
||||||
|
expect(await page.locator('.c-fl-container').count()).toEqual(3);
|
||||||
|
expect(await page.locator('.c-fl--rows').count()).toBeGreaterThan(0);
|
||||||
|
await expect(page.locator('.c-so-view').first()).toHaveClass(/c-so-view--no-frame/);
|
||||||
|
});
|
||||||
test('items in a flexible layout can be removed with object tree context menu when viewing the flexible layout', async ({
|
test('items in a flexible layout can be removed with object tree context menu when viewing the flexible layout', async ({
|
||||||
page
|
page
|
||||||
}) => {
|
}) => {
|
||||||
const treePane = page.getByRole('tree', {
|
await page.goto(flexibleLayout.url);
|
||||||
name: 'Main Tree'
|
|
||||||
});
|
|
||||||
const sineWaveGeneratorTreeItem = treePane.getByRole('treeitem', {
|
|
||||||
name: new RegExp(sineWaveObject.name)
|
|
||||||
});
|
|
||||||
// Create a Display Layout
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
|
||||||
type: 'Flexible Layout'
|
|
||||||
});
|
|
||||||
// Edit Flexible Layout
|
// Edit Flexible Layout
|
||||||
await page.locator('[title="Edit"]').click();
|
await page.locator('[title="Edit"]').click();
|
||||||
|
|
||||||
@ -121,17 +189,7 @@ test.describe('Flexible Layout', () => {
|
|||||||
type: 'issue',
|
type: 'issue',
|
||||||
description: 'https://github.com/nasa/openmct/issues/3117'
|
description: 'https://github.com/nasa/openmct/issues/3117'
|
||||||
});
|
});
|
||||||
const treePane = page.getByRole('tree', {
|
await page.goto(flexibleLayout.url);
|
||||||
name: 'Main Tree'
|
|
||||||
});
|
|
||||||
const sineWaveGeneratorTreeItem = treePane.getByRole('treeitem', {
|
|
||||||
name: new RegExp(sineWaveObject.name)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a Flexible Layout
|
|
||||||
const flexibleLayout = await createDomainObjectWithDefaults(page, {
|
|
||||||
type: 'Flexible Layout'
|
|
||||||
});
|
|
||||||
// Edit Flexible Layout
|
// Edit Flexible Layout
|
||||||
await page.locator('[title="Edit"]').click();
|
await page.locator('[title="Edit"]').click();
|
||||||
|
|
||||||
@ -167,19 +225,13 @@ test.describe('Flexible Layout', () => {
|
|||||||
const exampleImageryObject = await createDomainObjectWithDefaults(page, {
|
const exampleImageryObject = await createDomainObjectWithDefaults(page, {
|
||||||
type: 'Example Imagery'
|
type: 'Example Imagery'
|
||||||
});
|
});
|
||||||
// Create a Flexible Layout
|
|
||||||
await createDomainObjectWithDefaults(page, {
|
await page.goto(flexibleLayout.url);
|
||||||
type: 'Flexible Layout'
|
// Edit Flexible Layout
|
||||||
});
|
|
||||||
// Edit Display Layout
|
|
||||||
await page.locator('[title="Edit"]').click();
|
await page.locator('[title="Edit"]').click();
|
||||||
|
|
||||||
// Expand the 'My Items' folder in the left tree
|
// Expand the 'My Items' folder in the left tree
|
||||||
await page.locator('.c-tree__item__view-control.c-disclosure-triangle').click();
|
await page.locator('.c-tree__item__view-control.c-disclosure-triangle').click();
|
||||||
// Add the Sine Wave Generator to the Flexible Layout and save changes
|
|
||||||
const treePane = page.getByRole('tree', {
|
|
||||||
name: 'Main Tree'
|
|
||||||
});
|
|
||||||
const exampleImageryTreeItem = treePane.getByRole('treeitem', {
|
const exampleImageryTreeItem = treePane.getByRole('treeitem', {
|
||||||
name: new RegExp(exampleImageryObject.name)
|
name: new RegExp(exampleImageryObject.name)
|
||||||
});
|
});
|
||||||
|
@ -20,14 +20,14 @@
|
|||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<layout-frame
|
<LayoutFrame
|
||||||
:item="item"
|
:item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
@endMove="() => $emit('endMove')"
|
@endMove="() => $emit('endMove')"
|
||||||
>
|
>
|
||||||
<object-frame
|
<ObjectFrame
|
||||||
v-if="domainObject"
|
v-if="domainObject"
|
||||||
ref="objectFrame"
|
ref="objectFrame"
|
||||||
:domain-object="domainObject"
|
:domain-object="domainObject"
|
||||||
@ -37,7 +37,7 @@
|
|||||||
:layout-font-size="item.fontSize"
|
:layout-font-size="item.fontSize"
|
||||||
:layout-font="item.font"
|
:layout-font="item.font"
|
||||||
/>
|
/>
|
||||||
</layout-frame>
|
</LayoutFrame>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
<template v-for="(container, index) in containers" :key="`component-${container.id}`">
|
<template v-for="(container, index) in containers" :key="`component-${container.id}`">
|
||||||
<drop-hint
|
<drop-hint
|
||||||
v-if="index === 0 && containers.length > 1"
|
v-if="index === 0 && containers.length > 1"
|
||||||
:key="`hint-top-${container.id}`"
|
|
||||||
class="c-fl-frame__drop-hint"
|
class="c-fl-frame__drop-hint"
|
||||||
:index="-1"
|
:index="-1"
|
||||||
:allow-drop="allowContainerDrop"
|
:allow-drop="allowContainerDrop"
|
||||||
@ -59,7 +58,6 @@
|
|||||||
|
|
||||||
<resize-handle
|
<resize-handle
|
||||||
v-if="index !== containers.length - 1"
|
v-if="index !== containers.length - 1"
|
||||||
:key="`handle-${container.id}`"
|
|
||||||
:index="index"
|
:index="index"
|
||||||
:orientation="rowsLayout ? 'vertical' : 'horizontal'"
|
:orientation="rowsLayout ? 'vertical' : 'horizontal'"
|
||||||
:is-editing="isEditing"
|
:is-editing="isEditing"
|
||||||
@ -70,7 +68,6 @@
|
|||||||
|
|
||||||
<drop-hint
|
<drop-hint
|
||||||
v-if="containers.length > 1"
|
v-if="containers.length > 1"
|
||||||
:key="`hint-bottom-${container.id}`"
|
|
||||||
class="c-fl-frame__drop-hint"
|
class="c-fl-frame__drop-hint"
|
||||||
:index="index"
|
:index="index"
|
||||||
:allow-drop="allowContainerDrop"
|
:allow-drop="allowContainerDrop"
|
||||||
@ -137,15 +134,16 @@ export default {
|
|||||||
ResizeHandle,
|
ResizeHandle,
|
||||||
DropHint
|
DropHint
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'objectPath', 'layoutObject'],
|
inject: ['openmct', 'objectPath', 'domainObject'],
|
||||||
props: {
|
props: {
|
||||||
isEditing: Boolean
|
isEditing: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
domainObject: this.layoutObject,
|
|
||||||
newFrameLocation: [],
|
newFrameLocation: [],
|
||||||
identifierMap: {}
|
identifierMap: {},
|
||||||
|
containers: this.domainObject.configuration.containers,
|
||||||
|
rowsLayout: this.domainObject.configuration.rowsLayout
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -156,22 +154,22 @@ export default {
|
|||||||
return 'Columns';
|
return 'Columns';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
containers() {
|
|
||||||
return this.domainObject.configuration.containers;
|
|
||||||
},
|
|
||||||
rowsLayout() {
|
|
||||||
return this.domainObject.configuration.rowsLayout;
|
|
||||||
},
|
|
||||||
allContainersAreEmpty() {
|
allContainersAreEmpty() {
|
||||||
return this.containers.every((container) => container.frames.length === 0);
|
return this.containers.every((container) => container.frames.length === 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
created() {
|
||||||
this.buildIdentifierMap();
|
this.buildIdentifierMap();
|
||||||
this.composition = this.openmct.composition.get(this.domainObject);
|
this.composition = this.openmct.composition.get(this.domainObject);
|
||||||
this.composition.on('remove', this.removeChildObject);
|
this.composition.on('remove', this.removeChildObject);
|
||||||
this.composition.on('add', this.addFrame);
|
this.composition.on('add', this.addFrame);
|
||||||
this.composition.load();
|
this.composition.load();
|
||||||
|
this.openmct.objects.observe(this.domainObject, 'configuration.containers', (containers) => {
|
||||||
|
this.containers = containers;
|
||||||
|
});
|
||||||
|
this.openmct.objects.observe(this.domainObject, 'configuration.rowsLayout', (rowsLayout) => {
|
||||||
|
this.rowsLayout = rowsLayout;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
this.composition.off('remove', this.removeChildObject);
|
this.composition.off('remove', this.removeChildObject);
|
||||||
@ -211,20 +209,16 @@ export default {
|
|||||||
let container = this.containers.filter((c) => c.id === containerId)[0];
|
let container = this.containers.filter((c) => c.id === containerId)[0];
|
||||||
let containerIndex = this.containers.indexOf(container);
|
let containerIndex = this.containers.indexOf(container);
|
||||||
|
|
||||||
/*
|
// remove associated domainObjects from composition
|
||||||
remove associated domainObjects from composition
|
|
||||||
*/
|
|
||||||
container.frames.forEach((f) => {
|
container.frames.forEach((f) => {
|
||||||
this.removeFromComposition(f.domainObjectIdentifier);
|
this.removeFromComposition(f.domainObjectIdentifier);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.containers.splice(containerIndex, 1);
|
this.containers.splice(containerIndex, 1);
|
||||||
|
|
||||||
/*
|
// add a container when there are no containers in the FL,
|
||||||
add a container when there are no containers in the FL,
|
// to prevent user from not being able to add a frame via
|
||||||
to prevent user from not being able to add a frame via
|
// drag and drop.
|
||||||
drag and drop.
|
|
||||||
*/
|
|
||||||
if (this.containers.length === 0) {
|
if (this.containers.length === 0) {
|
||||||
this.containers.push(new Container(100));
|
this.containers.push(new Container(100));
|
||||||
}
|
}
|
||||||
|
@ -47,17 +47,16 @@ export default class FlexibleLayoutViewProvider {
|
|||||||
let component = null;
|
let component = null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
show: function (element, isEditing) {
|
show(element, isEditing) {
|
||||||
const { vNode, destroy } = mount(
|
const { vNode, destroy } = mount(
|
||||||
{
|
{
|
||||||
el: element,
|
|
||||||
components: {
|
components: {
|
||||||
FlexibleLayoutComponent
|
FlexibleLayoutComponent
|
||||||
},
|
},
|
||||||
provide: {
|
provide: {
|
||||||
openmct: openmct,
|
openmct,
|
||||||
objectPath,
|
objectPath,
|
||||||
layoutObject: domainObject
|
domainObject
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -75,7 +74,7 @@ export default class FlexibleLayoutViewProvider {
|
|||||||
component = vNode.componentInstance;
|
component = vNode.componentInstance;
|
||||||
_destroy = destroy;
|
_destroy = destroy;
|
||||||
},
|
},
|
||||||
getSelectionContext: function () {
|
getSelectionContext() {
|
||||||
return {
|
return {
|
||||||
item: domainObject,
|
item: domainObject,
|
||||||
addContainer: component.$refs.flexibleLayout.addContainer,
|
addContainer: component.$refs.flexibleLayout.addContainer,
|
||||||
@ -84,10 +83,10 @@ export default class FlexibleLayoutViewProvider {
|
|||||||
type: 'flexible-layout'
|
type: 'flexible-layout'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onEditModeChange: function (isEditing) {
|
onEditModeChange(isEditing) {
|
||||||
component.isEditing = isEditing;
|
component.isEditing = isEditing;
|
||||||
},
|
},
|
||||||
destroy: function (element) {
|
destroy() {
|
||||||
if (_destroy) {
|
if (_destroy) {
|
||||||
_destroy();
|
_destroy();
|
||||||
component = null;
|
component = null;
|
||||||
|
@ -33,6 +33,10 @@ describe('the plugin', function () {
|
|||||||
let mockComposition;
|
let mockComposition;
|
||||||
|
|
||||||
const testViewObject = {
|
const testViewObject = {
|
||||||
|
identifier: {
|
||||||
|
namespace: '',
|
||||||
|
key: 'test-object'
|
||||||
|
},
|
||||||
id: 'test-object',
|
id: 'test-object',
|
||||||
type: 'flexible-layout',
|
type: 'flexible-layout',
|
||||||
configuration: {
|
configuration: {
|
||||||
@ -116,6 +120,10 @@ describe('the plugin', function () {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
flexibleLayoutItem = {
|
flexibleLayoutItem = {
|
||||||
|
identifier: {
|
||||||
|
namespace: '',
|
||||||
|
key: 'test-object'
|
||||||
|
},
|
||||||
id: 'test-object',
|
id: 'test-object',
|
||||||
type: 'flexible-layout',
|
type: 'flexible-layout',
|
||||||
configuration: {
|
configuration: {
|
||||||
|
Reference in New Issue
Block a user