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

Allow specification of swimlanes via configuration #7200

Merged
merged 25 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c980e8e
Use specified group order for plans
shefalijoshi Nov 2, 2023
e0b0388
Allow groupIds to be a function
shefalijoshi Nov 2, 2023
541a910
Fix typo in if statement
shefalijoshi Nov 3, 2023
f74408c
Check that activities are present for a given group
shefalijoshi Nov 3, 2023
49fa8a8
Change refresh to emit the new model
shefalijoshi Nov 3, 2023
f629616
Update domainobject on change
shefalijoshi Nov 3, 2023
1f06a3b
Revert changes for domainObject
shefalijoshi Nov 3, 2023
a53f557
Revert groupIds as functions. Check if groups are objects with names …
shefalijoshi Nov 3, 2023
ebbacb3
Add e2e test for plan swim lane order
shefalijoshi Nov 6, 2023
285ac08
Merge branch 'master' into timelist-swimlane-order-7196
shefalijoshi Nov 6, 2023
378bf61
Merge branch 'master' into timelist-swimlane-order-7196
shefalijoshi Nov 9, 2023
b7bbc5d
Address review comments - improve if statement
shefalijoshi Nov 30, 2023
5dd2122
Merge branch 'timelist-swimlane-order-7196' of https://github.com/nas…
shefalijoshi Nov 30, 2023
2bee84f
Move function to right util helper
shefalijoshi Nov 30, 2023
33112f4
Merge branch 'master' into timelist-swimlane-order-7196
shefalijoshi Nov 30, 2023
2e0f0dc
Merge branch 'master' into timelist-swimlane-order-7196
shefalijoshi Dec 5, 2023
83d17e0
Fix path for imported code
shefalijoshi Dec 5, 2023
c10676c
Merge branch 'master' into timelist-swimlane-order-7196
shefalijoshi Dec 5, 2023
c97e16a
Remove focused test
shefalijoshi Dec 6, 2023
178fae0
Merge branch 'timelist-swimlane-order-7196' of https://github.com/nas…
shefalijoshi Dec 6, 2023
33ebb72
Merge branch 'master' into timelist-swimlane-order-7196
shefalijoshi Dec 11, 2023
f75e9ea
Change the name of the ordered group configuration
shefalijoshi Dec 11, 2023
95f352c
Merge branch 'master' into timelist-swimlane-order-7196
shefalijoshi Dec 13, 2023
1925420
Merge branch 'master' into timelist-swimlane-order-7196
shefalijoshi Dec 14, 2023
e1ad784
Merge branch 'master' into timelist-swimlane-order-7196
shefalijoshi Dec 14, 2023
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
44 changes: 44 additions & 0 deletions e2e/helper/planningUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,30 @@ function activitiesWithinTimeBounds(start1, end1, start2, end2) {
);
}

/**
* Asserts that the swim lanes / groups in the plan view matches the order of
* groups in the plan data.
* @param {import('@playwright/test').Page} page the page
* @param {object} plan The raw plan json to assert against
* @param {string} objectUrl The URL of the object to assert against (plan or gantt chart)
*/
export async function assertPlanOrderedSwimLanes(page, plan, objectUrl) {
// Switch to the plan view
await page.goto(`${objectUrl}?view=plan.view`);
const planGroups = await page
.locator('.c-plan__contents > div > .c-swimlane__lane-label .c-object-label__name')
.all();

const groups = plan.Groups;

for (let i = 0; i < groups.length; i++) {
// Assert that the order of groups in the plan view matches the order of
// groups in the plan data
const groupName = await planGroups[i].innerText();
expect(groupName).toEqual(groups[i].name);
}
}

/**
* Navigate to the plan view, switch to fixed time mode,
* and set the bounds to span all activities.
Expand Down Expand Up @@ -110,3 +134,23 @@ export async function setDraftStatusForPlan(page, plan) {
await window.openmct.status.set(planObject.uuid, 'draft');
}, plan);
}

export async function addPlanGetInterceptor(page) {
await page.waitForLoadState('load');
await page.evaluate(async () => {
await window.openmct.objects.addGetInterceptor({
appliesTo: (identifier, domainObject) => {
return domainObject && domainObject.type === 'plan';
},
invoke: (identifier, object) => {
if (object) {
object.sourceMap = {
groupIds: 'Groups'
};
}

return object;
}
});
});
}
54 changes: 54 additions & 0 deletions e2e/test-data/examplePlans/ExamplePlanWithOrderedLanes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"Groups": [
{
"name": "Group 1"
},
{
"name": "Group 2"
}
],
"Group 2": [
{
"name": "Past event 3",
"start": 1660493208000,
"end": 1660503981000,
"type": "Group 2",
"color": "orange",
"textColor": "white"
},
{
"name": "Past event 4",
"start": 1660579608000,
"end": 1660624108000,
"type": "Group 2",
"color": "orange",
"textColor": "white"
},
{
"name": "Past event 5",
"start": 1660666008000,
"end": 1660681529000,
"type": "Group 2",
"color": "orange",
"textColor": "white"
}
],
"Group 1": [
{
"name": "Past event 1",
"start": 1660320408000,
"end": 1660343797000,
"type": "Group 1",
"color": "orange",
"textColor": "white"
},
{
"name": "Past event 2",
"start": 1660406808000,
"end": 1660429160000,
"type": "Group 1",
"color": "orange",
"textColor": "white"
}
]
}
17 changes: 16 additions & 1 deletion e2e/tests/functional/planning/plan.e2e.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@
*****************************************************************************/
const { test } = require('../../../pluginFixtures');
const { createPlanFromJSON } = require('../../../appActions');
const { addPlanGetInterceptor } = require('../../../helper/planningUtils.js');
const testPlan1 = require('../../../test-data/examplePlans/ExamplePlan_Small1.json');
const { assertPlanActivities } = require('../../../helper/planningUtils');
const testPlanWithOrderedLanes = require('../../../test-data/examplePlans/ExamplePlanWithOrderedLanes.json');
const {
assertPlanActivities,
assertPlanOrderedSwimLanes
} = require('../../../helper/planningUtils');

test.describe('Plan', () => {
let plan;
Expand All @@ -36,4 +41,14 @@ test.describe('Plan', () => {
test('Displays all plan events', async ({ page }) => {
await assertPlanActivities(page, testPlan1, plan.url);
});

test('Displays plans with ordered swim lanes configuration', async ({ page }) => {
// Add configuration for swim lanes
await addPlanGetInterceptor(page);
// Create the plan
const planWithSwimLanes = await createPlanFromJSON(page, {
json: testPlanWithOrderedLanes
});
await assertPlanOrderedSwimLanes(page, testPlanWithOrderedLanes, planWithSwimLanes.url);
});
});
8 changes: 6 additions & 2 deletions src/plugins/plan/components/PlanView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import SwimLane from '@/ui/components/swim-lane/SwimLane.vue';

import TimelineAxis from '../../../ui/components/TimeSystemAxis.vue';
import PlanViewConfiguration from '../PlanViewConfiguration';
import { getContrastingColor, getValidatedData } from '../util';
import { getContrastingColor, getValidatedData, getValidatedGroups } from '../util';
import ActivityTimeline from './ActivityTimeline.vue';

const PADDING = 1;
Expand Down Expand Up @@ -416,7 +416,7 @@ export default {
return currentRow || SWIMLANE_PADDING;
},
generateActivities() {
const groupNames = Object.keys(this.planData);
const groupNames = getValidatedGroups(this.domainObject, this.planData);

if (!groupNames.length) {
return;
Expand All @@ -430,6 +430,10 @@ export default {
let currentRow = 0;

const rawActivities = this.planData[groupName];
if (rawActivities === undefined) {
return;
}

rawActivities.forEach((rawActivity) => {
if (!this.isActivityInBounds(rawActivity)) {
return;
Expand Down
51 changes: 40 additions & 11 deletions src/plugins/plan/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,7 @@

export function getValidatedData(domainObject) {
const sourceMap = domainObject.sourceMap;
const body = domainObject.selectFile?.body;
let json = {};
if (typeof body === 'string') {
try {
json = JSON.parse(body);
} catch (e) {
return json;
}
} else if (body !== undefined) {
json = body;
}
const json = getObjectJson(domainObject);

if (
sourceMap !== undefined &&
Expand Down Expand Up @@ -69,6 +59,45 @@ export function getValidatedData(domainObject) {
}
}

function getObjectJson(domainObject) {
const body = domainObject.selectFile?.body;
let json = {};
if (typeof body === 'string') {
try {
json = JSON.parse(body);
} catch (e) {
return json;
}
} else if (body !== undefined) {
json = body;
}

return json;
}

export function getValidatedGroups(domainObject, planData) {
let groupIds;
const sourceMap = domainObject.sourceMap;
const json = getObjectJson(domainObject);
if (sourceMap?.groupIds) {
const groups = json[sourceMap.groupIds];
if (groups.length && typeof groups[0] === 'object') {
const groupsWithNames = groups.filter(
(groupObj) => groupObj.name !== undefined && groupObj.name !== ''
);
groupIds = groupsWithNames.map((groupObj) => groupObj.name);
} else {
groupIds = groups;
}
}

if (groupIds === undefined) {
groupIds = Object.keys(planData);
}

return groupIds;
}

export function getContrastingColor(hexColor) {
function cutHex(h, start, end) {
const hStr = h.charAt(0) === '#' ? h.substring(1, 7) : h;
Expand Down
5 changes: 3 additions & 2 deletions src/plugins/timeline/TimelineViewLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import _ from 'lodash';
import SwimLane from '@/ui/components/swim-lane/SwimLane.vue';

import TimelineAxis from '../../ui/components/TimeSystemAxis.vue';
import { getValidatedData } from '../plan/util';
import { getValidatedData, getValidatedGroups } from '../plan/util';
import TimelineObjectView from './TimelineObjectView.vue';

const unknownObjectType = {
Expand Down Expand Up @@ -108,7 +108,8 @@ export default {
let objectPath = [domainObject].concat(this.objectPath.slice());
let rowCount = 0;
if (domainObject.type === 'plan') {
rowCount = Object.keys(getValidatedData(domainObject)).length;
const planData = getValidatedData(domainObject);
rowCount = getValidatedGroups(domainObject, planData).length;
} else if (domainObject.type === 'gantt-chart') {
rowCount = Object.keys(domainObject.configuration.swimlaneVisibility).length;
}
Expand Down
7 changes: 5 additions & 2 deletions src/plugins/timelist/TimelistComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { v4 as uuid } from 'uuid';
import { TIME_CONTEXT_EVENTS } from '../../api/time/constants';
import ListView from '../../ui/components/List/ListView.vue';
import { getPreciseDuration } from '../../utils/duration';
import { getValidatedData } from '../plan/util';
import { getValidatedData, getValidatedGroups } from '../plan/util';
import { SORT_ORDER_OPTIONS } from './constants';

const SCROLL_TIMEOUT = 10000;
Expand Down Expand Up @@ -283,10 +283,13 @@ export default {
this.planData = getValidatedData(domainObject);
},
listActivities() {
let groups = Object.keys(this.planData);
let groups = getValidatedGroups(this.domainObject, this.planData);
let activities = [];

groups.forEach((key) => {
if (this.planData[key] === undefined) {
return;
}
// Create new objects so Vue 3 can detect any changes
activities = activities.concat(JSON.parse(JSON.stringify(this.planData[key])));
});
Expand Down