Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
07de6c0
move ResizeHandle to reusable ui location
davetsay Jan 10, 2025
629f14b
Changes for user-settable swimlane heights.
charlesh88 Jan 15, 2025
52469ee
pass idEditing prop to timestrip component
davetsay Jan 15, 2025
63f3a8e
minimal POC of resizing width for a single swimlane label
davetsay Jan 15, 2025
1c77d84
resize widths for all swimlane labels
davetsay Jan 16, 2025
98127ab
make drag resizer more scalable
davetsay Jan 27, 2025
e3fe103
add resize handles to time strip views
davetsay Feb 11, 2025
03cb0ec
Changes for adjustable Time Strip view
charlesh88 Feb 13, 2025
7f14a87
WIP: use flex layout container sizing for timeline
davetsay Feb 27, 2025
a8ddf0f
working prototype for custom resizing swimlane height
davetsay Feb 27, 2025
c112302
persist swimlane height resizing
davetsay Mar 4, 2025
0b0c550
Changes for adjustable Time Strip view
charlesh88 Mar 4, 2025
9e82215
Adjustable Time Strip view: column resizing
charlesh88 Mar 4, 2025
e4d8ea8
persist vertical swimlane height
davetsay Mar 5, 2025
c38b898
persist swimlane label width
davetsay Mar 5, 2025
b94d64b
Adjustable Time Strip view: usability tweaks
charlesh88 Mar 11, 2025
c36a598
WIP move logic into setup
davetsay Mar 25, 2025
1d95bb1
Adjustable Time Strip view: usability tweaks
charlesh88 Apr 3, 2025
d6e3986
sync containers on load
davetsay Apr 25, 2025
c8177d8
WIP: allow fixed pixel heights
davetsay May 2, 2025
0e9d296
Fix main-container margin when editing
charlesh88 May 7, 2025
935ecb5
Main container and swimlane mods to support scaling swimlanes in Time…
charlesh88 May 9, 2025
8cf4de8
working resize with persistence
davetsay May 9, 2025
30d9c51
sizing is now more exact
davetsay May 30, 2025
dabbc3e
WIP: move logic into setup
davetsay Jun 10, 2025
29b50c1
move rounding excess into separate function
davetsay Jun 11, 2025
e9e7a39
explain setup objects
davetsay Jun 11, 2025
afe06c4
remove unused function
davetsay Jun 11, 2025
c13a2f5
revert removal of height, as is needed for plans
davetsay Jun 11, 2025
4404d8f
Revert "revert removal of height, as is needed for plans"
davetsay Jun 11, 2025
9a0aa87
use custom elements view
davetsay Jun 23, 2025
c9a6faa
fix for composition mod outside of view breaking containers
davetsay Jun 23, 2025
77700fa
inspector should watch for view updates to swimLaneLabelWidth
davetsay Jun 23, 2025
b9c83f1
clean up markup text/labels
davetsay Jun 25, 2025
48300cf
Fix linting error
akhenry Aug 15, 2025
35d1ef8
simplify logic using nullish coalescing operator
davetsay Aug 19, 2025
23b8936
provide read-only view of custom elements pool
davetsay Aug 19, 2025
094f049
Remove Timeline objects wrapper
davetsay Aug 19, 2025
18b798d
Fix extended line height problem
charlesh88 Aug 20, 2025
4c15fb6
update autoscale snapshots
davetsay Aug 20, 2025
ce975dc
band-aid fix for existing bug in visual tests
davetsay Aug 20, 2025
9a26f99
disable eslint error for bandaid fix
davetsay Aug 20, 2025
2b1e2fe
swimlane width tests
davetsay Aug 21, 2025
8225fba
clean up width tests
davetsay Aug 22, 2025
f16a109
remove comment and debug code
davetsay Aug 26, 2025
636fd3e
use fresh config instead of ref to same config
davetsay Aug 26, 2025
75c8488
Merge branch 'adjustable-swimlanes-merge-attempt-2' into 8005/swimlan…
davetsay Aug 27, 2025
5ea6089
limit time axis to only the current time system
davetsay Aug 29, 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
186 changes: 186 additions & 0 deletions e2e/tests/functional/plugins/timeline/timeStrip.e2e.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, 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 { createDomainObjectWithDefaults } from '../../../../appActions.js';
import { expect, test } from '../../../../pluginFixtures.js';

const MIN_CONTAINER_SIZE = 5;
const SWIM_LANE_DEFAULT_WIDTH = 200;

// Helper function to get container sizes
async function getContainerSizes(page) {
const containers = page.locator('.timeline-container');
const sizes = await containers.evaluateAll((elements) =>
elements.map((el) => parseFloat(window.getComputedStyle(el).flexGrow))
);
return sizes;
}

// Helper function to get container heights
async function getContainerHeights(page) {
const containers = page.locator('.timeline-container');
const heights = await containers.evaluateAll((elements) => elements.map((el) => el.offsetHeight));
return heights;
}

test.describe('Timeline Swim Lane Configuration', () => {
/** @type {import('@playwright/test').Locator} */
let timeStrip;
let timeStripContentHolder;
let timeAxis;
let swimLanes;
let swimLaneLabels;
let showItemInTreeButton;
let editButton;
let treePane;
// TODO: why the extra pixel?
const fudge = 1;

test.beforeEach(async ({ page }) => {
await page.goto('/');

timeStrip = await createDomainObjectWithDefaults(page, {
type: 'Time Strip',
name: 'Time Strip'
});

// Create Swim Lanes
for (let i = 0; i <= 4; i++) {
await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot',
name: `Swim Lane ${i}`
});
}

await page.goto(timeStrip.url);
timeAxis = page.getByLabel('Time Axis');
timeStripContentHolder = page.getByLabel('Time Strip');
swimLanes = timeStripContentHolder.locator('.c-timeline__content');
swimLaneLabels = swimLanes.locator('.c-swimlane__lane-label');
showItemInTreeButton = page.getByLabel('Show selected item in tree');
editButton = page.getByRole('button', { name: 'Edit Object', exact: true });
treePane = page.getByRole('tree', {
name: 'Main Tree'
});
});

test('allows for swim lane label widths to be configured', async ({ page }) => {
// Edit the Time Strip
await editButton.click();
// Expand the 'My Items' folder in the left tree
await showItemInTreeButton.click();
// Add objects to the Time Strip
for (let i = 0; i <= 4; i++) {
const overlayPlotTreeItem = treePane.getByRole('treeitem', {
name: `Swim Lane ${i}`
});
await overlayPlotTreeItem.dragTo(timeAxis);
}

const labelCount = await swimLaneLabels.count();
await expect(labelCount).toBe(5);

await test.step(`swim lane label widths default to ${SWIM_LANE_DEFAULT_WIDTH}px`, async () => {
// Verify the swim lane label widths are identical
for (let i = 0; i < labelCount; i++) {
await expect((await swimLaneLabels.nth(i).boundingBox()).width).toBe(
SWIM_LANE_DEFAULT_WIDTH + fudge
);
}
// The Time Axis is also a swim lane and should have an identical label width
await expect((await timeAxis.locator('.c-swimlane__lane-label').boundingBox()).width).toBe(
SWIM_LANE_DEFAULT_WIDTH + fudge
);
});

await test.step('using drag and drop to resize', async () => {
let widthAfterDragRight;
let widthAfterDragLeft;
const dragDistance = 50;
const swimLaneLabelWidthHandle = page.locator('.c-swimlane__handle');
const box = await swimLaneLabelWidthHandle.first().boundingBox();
await swimLaneLabelWidthHandle.first().hover();
await page.mouse.down();
await page.mouse.move(box.x + dragDistance, box.y);
await page.mouse.up();
widthAfterDragRight = (await swimLaneLabels.nth(0).boundingBox()).width;

// Verify the swim lane label widths are identical and updated
for (let i = 0; i < labelCount; i++) {
const currentWidth = (await swimLaneLabels.nth(i).boundingBox()).width;

await expect(currentWidth).toBe(widthAfterDragRight);
await expect(currentWidth).toBeGreaterThan(SWIM_LANE_DEFAULT_WIDTH + fudge);

widthAfterDragRight = currentWidth;
}

// The Time Axis is also a swim lane and should have an identical label width
await expect((await timeAxis.locator('.c-swimlane__lane-label').boundingBox()).width).toBe(
widthAfterDragRight
);

const bigBox = await swimLaneLabelWidthHandle.first().boundingBox();
await swimLaneLabelWidthHandle.first().hover();
await page.mouse.down();
await page.mouse.move(bigBox.x - dragDistance / 2, bigBox.y);
await page.mouse.up();

widthAfterDragLeft = (await swimLaneLabels.nth(0).boundingBox()).width;

// Verify the swim lane widths are identical and updated
for (let i = 0; i < labelCount; i++) {
const currentWidth = (await swimLaneLabels.nth(i).boundingBox()).width;

await expect(currentWidth).toBe(widthAfterDragLeft);
await expect(currentWidth).toBeGreaterThan(SWIM_LANE_DEFAULT_WIDTH + fudge);
await expect(currentWidth).toBeLessThan(widthAfterDragRight);

widthAfterDragLeft = currentWidth;
}

// The Time Axis is also a swim lane and should have an identical label width
await expect((await timeAxis.locator('.c-swimlane__lane-label').boundingBox()).width).toBe(
widthAfterDragLeft
);
});

await test.step('using input entry in inspector Elements tab to resize', async () => {
const size = 100;
// Click the Elements tag in the Inspector
await page.getByRole('tab', { name: 'Elements' }).click();

const input = page.getByLabel('Swim Lane Label Width').locator('input[type="number"]');
await input.fill(`${size}`);
await input.blur();

// Verify the swim lane label widths are identical and updated
for (let i = 0; i < (await swimLaneLabels.count()); i++) {
await expect((await swimLaneLabels.nth(i).boundingBox()).width).toBe(size + fudge);
}

// The Time Axis is also a swim lane and should have an identical label width
await expect((await timeAxis.locator('.c-swimlane__lane-label').boundingBox()).width).toBe(
size + fudge
);
});
});
});
2 changes: 1 addition & 1 deletion e2e/tests/functional/ui/inspector.e2e.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ test.describe('Inspector tests', () => {
const objectInfo = await createDomainObjectWithDefaults(
page,
createOptions,
viewConfig.required ? viewConfig.required : {}
viewConfig.required ?? {}
);
await page.goto(objectInfo.url);

Expand Down
4 changes: 4 additions & 0 deletions e2e/tests/visual-a11y/planning-timestrip.visual.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ test.describe('Visual - Time Strip @a11y', () => {
//This will stabilize the state of the test and allow the SWG to render as empty
await waitForAnimations(page.getByLabel('Plot Canvas'));

// FIXME: https://github.com/nasa/openmct/issues/8005
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(500);

await percySnapshot(page, `Time Strip View (theme: ${theme}) - With SWG and Plan`);
});
});
Expand Down
6 changes: 4 additions & 2 deletions src/plugins/events/components/events-view.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
&__container {
// Holds event lines
background-color: $colorPlotBg;
//box-shadow: inset $colorPlotAreaBorder 0 0 0 1px; // Using box-shadow instead of border to not affect box size
position: absolute;
top: $m; right: 0; bottom: $m; left: 0;
}
Expand Down Expand Up @@ -77,10 +76,13 @@
}

// Extended event lines
.c-timeline__overlay-lines__extended-line-container {
display: contents;
}

.c-timeline__event-line--extended {
@include abs();
width: $eventLineW;
opacity: 0.4;

&.--hilite {
opacity: 0.8;
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/flexibleLayout/components/ContainerComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@
</template>

<script>
import ResizeHandle from '@/ui/layout/ResizeHandle/ResizeHandle.vue';
import DropHint from './DropHint.vue';
import FrameComponent from './FrameComponent.vue';
import ResizeHandle from './ResizeHandle.vue';
const MIN_FRAME_SIZE = 5;
Expand Down
7 changes: 4 additions & 3 deletions src/plugins/flexibleLayout/components/FlexibleLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@
</template>

<script>
import Container from '../utils/container.js';
import Frame from '../utils/frame.js';
import Container from '@/ui/layout/Container.js';
import Frame from '@/ui/layout/Frame.js';
import ResizeHandle from '@/ui/layout/ResizeHandle/ResizeHandle.vue';
import ContainerComponent from './ContainerComponent.vue';
import DropHint from './DropHint.vue';
import ResizeHandle from './ResizeHandle.vue';
const MIN_CONTAINER_SIZE = 5;
Expand Down
35 changes: 3 additions & 32 deletions src/plugins/flexibleLayout/components/flexible-layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -247,46 +247,17 @@
}

&__resize-handle {
$size: 2px;
$size: 1px;
$margin: 3px;
$marginHov: 0;
$grippyThickness: $size + 6;
$grippyLen: $grippyThickness * 2;

@include resizeHandleStyle($size, $margin);

display: flex;
flex-direction: column;
flex: 0 0 ($margin * 2) + $size;

&:before {
// The visible resize line
background-color: $editUIColor;
content: '';
display: block;
flex: 1 1 auto;
min-height: $size;
min-width: $size;
}

&.vertical {
padding: $margin $size;
&:hover {
cursor: row-resize;
}
}

&.horizontal {
padding: $size $margin;
&:hover {
cursor: col-resize;
}
}

&:hover {
&:before {
// The visible resize line
background-color: $editUIColorHov;
}
}
}

// Hide the resize-handles in first and last c-fl-frame elements
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/flexibleLayout/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/

import Container from '@/ui/layout/Container.js';

import flexibleLayoutStylesInterceptor from './flexibleLayoutStylesInterceptor.js';
import FlexibleLayoutViewProvider from './flexibleLayoutViewProvider.js';
import ToolBarProvider from './toolbarProvider.js';
import Container from './utils/container.js';

export default function plugin() {
return function install(openmct) {
Expand Down
1 change: 1 addition & 0 deletions src/plugins/inspectorViews/elements/ElementItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
:object-path="[elementObject, domainObject]"
@context-click-active="setContextClickState"
/>
<slot name="content"></slot>
</div>
</li>
<li v-else :aria-label="`${elementObject.name} Element Item`">
Expand Down
Loading