mirror of
https://github.com/nasa/openmct.git
synced 2025-06-18 15:18:12 +00:00
Plan state (#4310)
* Add plan state indicators * Changes to simplify timeline view * Styling for draft plans * Adds status to Plan.vue * Adds tests * Mods for #4309 - New font and icomoon JSON file - when merging, please override with this version if any conflicts! - New glyph and bg-icon svg style for plan; - Updated glyph and bg-icon svg style for timestrip; - Modified visual approach, glyph, color for `is-status--draft`; - Updated icon usage for Plan views; - Updated description for Plan and Timestrip views; Co-authored-by: Andrew Henry <akhenry@gmail.com> Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov> Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov> Co-authored-by: Khalid Adil <khalidadil29@gmail.com> Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com> Co-authored-by: Scott Bell <scott@traclabs.com> Co-authored-by: Michael Rogers <michael@mhrogers.com>
This commit is contained in:
@ -65,6 +65,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.is-status--current {
|
||||
.is-status__indicator {
|
||||
display: block;
|
||||
|
||||
&:before {
|
||||
color: $colorFilter;
|
||||
content: $glyph-icon-asterisk;
|
||||
font-family: symbolsfont;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.is-status--draft {
|
||||
.is-status__indicator {
|
||||
display: block;
|
||||
|
||||
&:before {
|
||||
color: $colorStatusAlert;
|
||||
content: $glyph-icon-draft;
|
||||
font-family: symbolsfont;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[class*='is-status--missing'],
|
||||
&[class*='is-status--suspect']{
|
||||
[class*='__type-icon'],
|
||||
|
@ -71,7 +71,9 @@ describe("the plugin", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
mockMissingProvider = {
|
||||
get: () => Promise.resolve(missingObj)
|
||||
get: () => Promise.resolve(missingObj),
|
||||
create: () => Promise.resolve(missingObj),
|
||||
update: () => Promise.resolve(missingObj)
|
||||
};
|
||||
|
||||
activeProvider = mockMissingProvider;
|
||||
|
@ -102,21 +102,26 @@ describe('the plugin', () => {
|
||||
expect(result.identifier.key).toEqual(mockDomainObject.identifier.key);
|
||||
});
|
||||
|
||||
it('creates an object', async () => {
|
||||
const result = await openmct.objects.save(mockDomainObject);
|
||||
expect(provider.create).toHaveBeenCalled();
|
||||
expect(result).toBeTrue();
|
||||
it('creates an object', (done) => {
|
||||
openmct.objects.save(mockDomainObject).then((result) => {
|
||||
expect(provider.create).toHaveBeenCalled();
|
||||
expect(result).toBeTrue();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
xit('updates an object', async () => {
|
||||
const result = await openmct.objects.save(mockDomainObject);
|
||||
expect(result).toBeTrue();
|
||||
expect(provider.create).toHaveBeenCalled();
|
||||
//Set modified timestamp it detects a change and persists the updated model.
|
||||
mockDomainObject.modified = Date.now();
|
||||
const updatedResult = await openmct.objects.save(mockDomainObject);
|
||||
expect(updatedResult).toBeTrue();
|
||||
expect(provider.update).toHaveBeenCalled();
|
||||
it('updates an object', (done) => {
|
||||
openmct.objects.save(mockDomainObject).then((result) => {
|
||||
expect(result).toBeTrue();
|
||||
expect(provider.create).toHaveBeenCalled();
|
||||
//Set modified timestamp it detects a change and persists the updated model.
|
||||
mockDomainObject.modified = mockDomainObject.persisted + 1;
|
||||
openmct.objects.save(mockDomainObject).then((updatedResult) => {
|
||||
expect(updatedResult).toBeTrue();
|
||||
expect(provider.update).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('batches requests', () => {
|
||||
|
@ -102,6 +102,8 @@ export default {
|
||||
this.setTimeContext();
|
||||
this.resizeTimer = setInterval(this.resize, RESIZE_POLL_INTERVAL);
|
||||
this.unlisten = this.openmct.objects.observe(this.domainObject, '*', this.observeForChanges);
|
||||
this.removeStatusListener = this.openmct.status.observe(this.domainObject.identifier, this.setStatus);
|
||||
this.status = this.openmct.status.get(this.domainObject.identifier);
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.resizeTimer);
|
||||
@ -109,6 +111,10 @@ export default {
|
||||
if (this.unlisten) {
|
||||
this.unlisten();
|
||||
}
|
||||
|
||||
if (this.removeStatusListener) {
|
||||
this.removeStatusListener();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setTimeContext() {
|
||||
@ -365,6 +371,7 @@ export default {
|
||||
|
||||
const rows = Object.keys(activityRows);
|
||||
const isNested = this.options.isChildObject;
|
||||
const status = isNested ? '' : this.status;
|
||||
|
||||
if (rows.length) {
|
||||
const lastActivityRow = rows[rows.length - 1];
|
||||
@ -383,11 +390,12 @@ export default {
|
||||
return {
|
||||
heading,
|
||||
isNested,
|
||||
status,
|
||||
height: svgHeight,
|
||||
width: svgWidth
|
||||
};
|
||||
},
|
||||
template: `<swim-lane :is-nested="isNested"><template slot="label">{{heading}}</template><template slot="object"><svg :height="height" :width="width"></svg></template></swim-lane>`
|
||||
template: `<swim-lane :is-nested="isNested" :status="status"><template slot="label">{{heading}}</template><template slot="object"><svg :height="height" :width="width"></svg></template></swim-lane>`
|
||||
});
|
||||
|
||||
this.$refs.planHolder.appendChild(component.$mount().$el);
|
||||
@ -547,6 +555,13 @@ export default {
|
||||
}
|
||||
}], multiSelect);
|
||||
event.stopPropagation();
|
||||
},
|
||||
|
||||
setStatus(status) {
|
||||
this.status = status;
|
||||
if (this.xScale) {
|
||||
this.drawPlan();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ export default function PlanViewProvider(openmct) {
|
||||
return {
|
||||
key: 'plan.view',
|
||||
name: 'Plan',
|
||||
cssClass: 'icon-calendar',
|
||||
cssClass: 'icon-plan',
|
||||
canView(domainObject) {
|
||||
return domainObject.type === 'plan';
|
||||
},
|
||||
|
@ -23,14 +23,14 @@
|
||||
import PlanViewProvider from './PlanViewProvider';
|
||||
import PlanInspectorViewProvider from "./inspector/PlanInspectorViewProvider";
|
||||
|
||||
export default function () {
|
||||
export default function (configuration) {
|
||||
return function install(openmct) {
|
||||
openmct.types.addType('plan', {
|
||||
name: 'Plan',
|
||||
key: 'plan',
|
||||
description: 'A plan',
|
||||
description: 'A configurable timeline-like view for a compatible mission plan file.',
|
||||
creatable: true,
|
||||
cssClass: 'icon-calendar',
|
||||
cssClass: 'icon-plan',
|
||||
form: [
|
||||
{
|
||||
name: 'Upload Plan (JSON File)',
|
||||
|
@ -186,5 +186,18 @@ describe('the plugin', function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it ('shows the status indicator when available', (done) => {
|
||||
openmct.status.set({
|
||||
key: "test-object",
|
||||
namespace: ''
|
||||
}, 'draft');
|
||||
|
||||
Vue.nextTick(() => {
|
||||
const statusEl = element.querySelector('.c-plan__contents .is-status--draft');
|
||||
expect(statusEl).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -21,6 +21,7 @@
|
||||
*****************************************************************************/
|
||||
<template>
|
||||
<swim-lane :icon-class="item.type.definition.cssClass"
|
||||
:status="status"
|
||||
:min-height="item.height"
|
||||
:show-ucontents="item.domainObject.type === 'plan'"
|
||||
:span-rows-count="item.rowCount"
|
||||
@ -58,7 +59,8 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
domainObject: undefined,
|
||||
mutablePromise: undefined
|
||||
mutablePromise: undefined,
|
||||
status: ''
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@ -103,13 +105,27 @@ export default {
|
||||
let childContext = this.$refs.objectView.getSelectionContext();
|
||||
childContext.item = domainObject;
|
||||
this.context = childContext;
|
||||
if (this.removeSelectable) {
|
||||
this.removeSelectable();
|
||||
}
|
||||
|
||||
this.removeSelectable = this.openmct.selection.selectable(
|
||||
this.$el, this.context);
|
||||
}
|
||||
|
||||
if (this.removeStatusListener) {
|
||||
this.removeStatusListener();
|
||||
}
|
||||
|
||||
this.removeStatusListener = this.openmct.status.observe(this.domainObject.identifier, this.setStatus);
|
||||
this.status = this.openmct.status.get(this.domainObject.identifier);
|
||||
});
|
||||
},
|
||||
setActionCollection(actionCollection) {
|
||||
this.openmct.menus.actionsToMenuItems(actionCollection.getVisibleActions(), actionCollection.objectPath, actionCollection.view);
|
||||
},
|
||||
setStatus(status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -24,40 +24,31 @@
|
||||
<div ref="timelineHolder"
|
||||
class="c-timeline-holder"
|
||||
>
|
||||
<div class="c-timeline">
|
||||
<div v-for="timeSystemItem in timeSystems"
|
||||
:key="timeSystemItem.timeSystem.key"
|
||||
class="u-contents"
|
||||
>
|
||||
<swim-lane>
|
||||
<template slot="label">
|
||||
{{ timeSystemItem.timeSystem.name }}
|
||||
</template>
|
||||
<template slot="object">
|
||||
<timeline-axis :bounds="timeSystemItem.bounds"
|
||||
:time-system="timeSystemItem.timeSystem"
|
||||
:content-height="height"
|
||||
:rendering-engine="'svg'"
|
||||
/>
|
||||
</template>
|
||||
<swim-lane v-for="timeSystemItem in timeSystems"
|
||||
:key="timeSystemItem.timeSystem.key"
|
||||
>
|
||||
<template slot="label">
|
||||
{{ timeSystemItem.timeSystem.name }}
|
||||
</template>
|
||||
<template slot="object">
|
||||
<timeline-axis :bounds="timeSystemItem.bounds"
|
||||
:time-system="timeSystemItem.timeSystem"
|
||||
:content-height="height"
|
||||
:rendering-engine="'svg'"
|
||||
/>
|
||||
</template>
|
||||
|
||||
</swim-lane>
|
||||
</div>
|
||||
</swim-lane>
|
||||
|
||||
<div ref="contentHolder"
|
||||
class="u-contents c-timeline__objects c-timeline__content-holder"
|
||||
>
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.keyString"
|
||||
class="u-contents c-timeline__content"
|
||||
>
|
||||
<timeline-object-view
|
||||
class="u-contents"
|
||||
:item="item"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="contentHolder"
|
||||
class="c-timeline__objects"
|
||||
>
|
||||
<timeline-object-view
|
||||
v-for="item in items"
|
||||
:key="item.keyString"
|
||||
class="c-timeline__content"
|
||||
:item="item"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -28,7 +28,7 @@ export default function () {
|
||||
openmct.types.addType('time-strip', {
|
||||
name: 'Time Strip',
|
||||
key: 'time-strip',
|
||||
description: 'An activity timeline',
|
||||
description: 'Compose and display time-based telemetry and other object types in a timeline-like view.',
|
||||
creatable: true,
|
||||
cssClass: 'icon-timeline',
|
||||
initialize: function (domainObject) {
|
||||
|
@ -1,10 +1,12 @@
|
||||
.c-timeline-holder {
|
||||
@include abs();
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.c-plan.c-timeline-holder {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.c-timeline__objects {
|
||||
display: contents;
|
||||
}
|
||||
|
Reference in New Issue
Block a user