mirror of
https://github.com/nasa/openmct.git
synced 2025-06-06 01:11:41 +00:00
Timestrip plan Inspection (#3863)
* Stub in static HTML for Timestrip Activity Inspection - Added static markup with placeholder values and display logic; - Refined approach for Links; * Refactor duration formatting * Display activity name when it's available * Don't use indices for keys * Don't show properties with no labels
This commit is contained in:
parent
2a1e322230
commit
96dd581a67
@ -1,3 +1,25 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2020, 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.
|
||||||
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div ref="plan"
|
<div ref="plan"
|
||||||
class="c-plan c-timeline-holder"
|
class="c-plan c-timeline-holder"
|
||||||
@ -28,7 +50,6 @@ import SwimLane from "@/ui/components/swim-lane/SwimLane.vue";
|
|||||||
import { getValidatedPlan } from "./util";
|
import { getValidatedPlan } from "./util";
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
|
|
||||||
//TODO: UI direction needed for the following property values
|
|
||||||
const PADDING = 1;
|
const PADDING = 1;
|
||||||
const OUTER_TEXT_PADDING = 12;
|
const OUTER_TEXT_PADDING = 12;
|
||||||
const INNER_TEXT_PADDING = 17;
|
const INNER_TEXT_PADDING = 17;
|
||||||
@ -281,7 +302,9 @@ export default {
|
|||||||
exceeds: {
|
exceeds: {
|
||||||
start: this.xScale(this.viewBounds.start) > this.xScale(activity.start),
|
start: this.xScale(this.viewBounds.start) > this.xScale(activity.start),
|
||||||
end: this.xScale(this.viewBounds.end) < this.xScale(activity.end)
|
end: this.xScale(this.viewBounds.end) < this.xScale(activity.end)
|
||||||
}
|
},
|
||||||
|
start: activity.start,
|
||||||
|
end: activity.end
|
||||||
},
|
},
|
||||||
textLines: textLines,
|
textLines: textLines,
|
||||||
textStart: textStart,
|
textStart: textStart,
|
||||||
@ -339,6 +362,9 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
SwimLane
|
SwimLane
|
||||||
},
|
},
|
||||||
|
provide: {
|
||||||
|
openmct: this.openmct
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
heading,
|
heading,
|
||||||
@ -376,7 +402,6 @@ export default {
|
|||||||
activityRows.forEach((row) => {
|
activityRows.forEach((row) => {
|
||||||
const items = activitiesByRow[row];
|
const items = activitiesByRow[row];
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
//TODO: Don't draw the left-border of the rectangle if the activity started before viewBounds.start
|
|
||||||
this.plotActivity(item, parseInt(row, 10), groupSVG);
|
this.plotActivity(item, parseInt(row, 10), groupSVG);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -399,6 +424,9 @@ export default {
|
|||||||
element.setAttributeNS(null, key, attributes[key]);
|
element.setAttributeNS(null, key, attributes[key]);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
getNSAttributesForElement(element, attribute) {
|
||||||
|
return element.getAttributeNS(null, attribute);
|
||||||
|
},
|
||||||
// Experimental for now - unused
|
// Experimental for now - unused
|
||||||
addForeignElement(svgElement, label, x, y) {
|
addForeignElement(svgElement, label, x, y) {
|
||||||
let foreign = document.createElementNS('http://www.w3.org/2000/svg', "foreignObject");
|
let foreign = document.createElementNS('http://www.w3.org/2000/svg', "foreignObject");
|
||||||
@ -443,6 +471,10 @@ export default {
|
|||||||
fill: activity.color
|
fill: activity.color
|
||||||
});
|
});
|
||||||
|
|
||||||
|
rectElement.addEventListener('click', (event) => {
|
||||||
|
this.setSelectionForActivity(event.currentTarget, activity, event.metaKey);
|
||||||
|
});
|
||||||
|
|
||||||
svgElement.appendChild(rectElement);
|
svgElement.appendChild(rectElement);
|
||||||
|
|
||||||
item.textLines.forEach((line, index) => {
|
item.textLines.forEach((line, index) => {
|
||||||
@ -456,6 +488,9 @@ export default {
|
|||||||
|
|
||||||
const textNode = document.createTextNode(line);
|
const textNode = document.createTextNode(line);
|
||||||
textElement.appendChild(textNode);
|
textElement.appendChild(textNode);
|
||||||
|
textElement.addEventListener('click', (event) => {
|
||||||
|
this.setSelectionForActivity(event.currentTarget, activity, event.metaKey);
|
||||||
|
});
|
||||||
svgElement.appendChild(textElement);
|
svgElement.appendChild(textElement);
|
||||||
});
|
});
|
||||||
// this.addForeignElement(svgElement, activity.name, item.textStart, item.textY - LINE_HEIGHT);
|
// this.addForeignElement(svgElement, activity.name, item.textStart, item.textY - LINE_HEIGHT);
|
||||||
@ -482,6 +517,22 @@ export default {
|
|||||||
const cBrightness = ((hR * 299) + (hG * 587) + (hB * 114)) / 1000;
|
const cBrightness = ((hR * 299) + (hG * 587) + (hB * 114)) / 1000;
|
||||||
|
|
||||||
return cBrightness > cThreshold ? "#000000" : "#ffffff";
|
return cBrightness > cThreshold ? "#000000" : "#ffffff";
|
||||||
|
},
|
||||||
|
setSelectionForActivity(element, activity, multiSelect) {
|
||||||
|
this.openmct.selection.select([{
|
||||||
|
element: element,
|
||||||
|
context: {
|
||||||
|
type: 'activity',
|
||||||
|
activity: activity
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
element: this.openmct.layout.$refs.browseObject.$el,
|
||||||
|
context: {
|
||||||
|
item: this.domainObject,
|
||||||
|
supportsMultiSelect: true
|
||||||
|
}
|
||||||
|
}], multiSelect);
|
||||||
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
52
src/plugins/plan/inspector/ActivityProperty.vue
Normal file
52
src/plugins/plan/inspector/ActivityProperty.vue
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2020, 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<li class="c-inspect-properties__row">
|
||||||
|
<div class="c-inspect-properties__label">
|
||||||
|
{{ label }}
|
||||||
|
</div>
|
||||||
|
<div class="c-inspect-properties__value">
|
||||||
|
{{ value }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
206
src/plugins/plan/inspector/PlanActivitiesView.vue
Normal file
206
src/plugins/plan/inspector/PlanActivitiesView.vue
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2021, 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.
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="c-inspector__properties c-inspect-properties">
|
||||||
|
<plan-activity-view v-for="activity in activities"
|
||||||
|
:key="activity.id"
|
||||||
|
:activity="activity"
|
||||||
|
:heading="heading"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PlanActivityView from "./PlanActivityView.vue";
|
||||||
|
import { getPreciseDuration } from "utils/duration";
|
||||||
|
import uuid from 'uuid';
|
||||||
|
|
||||||
|
const propertyLabels = {
|
||||||
|
'start': 'Start DateTime',
|
||||||
|
'end': 'End DateTime',
|
||||||
|
'duration': 'Duration',
|
||||||
|
'earliestStart': 'Earliest Start',
|
||||||
|
'latestEnd': 'Latest End',
|
||||||
|
'gap': 'Gap',
|
||||||
|
'overlap': 'Overlap',
|
||||||
|
'totalTime': 'Total Time'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
PlanActivityView
|
||||||
|
},
|
||||||
|
inject: ['openmct', 'selection'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
name: '',
|
||||||
|
activities: [],
|
||||||
|
heading: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.setFormatters();
|
||||||
|
this.getPlanData(this.selection);
|
||||||
|
this.getActivities();
|
||||||
|
this.openmct.selection.on('change', this.updateSelection);
|
||||||
|
this.openmct.time.on('timeSystem', this.setFormatters);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.openmct.selection.off('change', this.updateSelection);
|
||||||
|
this.openmct.time.off('timeSystem', this.setFormatters);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setFormatters() {
|
||||||
|
let timeSystem = this.openmct.time.timeSystem();
|
||||||
|
this.timeFormatter = this.openmct.telemetry.getValueFormatter({
|
||||||
|
format: timeSystem.timeFormat
|
||||||
|
}).formatter;
|
||||||
|
},
|
||||||
|
updateSelection(newSelection) {
|
||||||
|
this.getPlanData(newSelection);
|
||||||
|
this.getActivities();
|
||||||
|
},
|
||||||
|
getPlanData(selection) {
|
||||||
|
this.selectedActivities = [];
|
||||||
|
selection.forEach((selectionItem) => {
|
||||||
|
if (selectionItem[0].context.type === 'activity') {
|
||||||
|
const activity = selectionItem[0].context.activity;
|
||||||
|
if (activity) {
|
||||||
|
this.selectedActivities.push(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getActivities() {
|
||||||
|
if (this.selectedActivities.length <= 1) {
|
||||||
|
this.heading = 'Time';
|
||||||
|
this.setSingleActivityProperties();
|
||||||
|
} else {
|
||||||
|
this.heading = 'Convex Hull';
|
||||||
|
this.setMultipleActivityProperties();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setSingleActivityProperties() {
|
||||||
|
this.activities.splice(0);
|
||||||
|
this.selectedActivities.forEach((selectedActivity, index) => {
|
||||||
|
const activity = {
|
||||||
|
id: uuid(),
|
||||||
|
start: {
|
||||||
|
label: propertyLabels.start,
|
||||||
|
value: this.formatTime(selectedActivity.start)
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
label: propertyLabels.end,
|
||||||
|
value: this.formatTime(selectedActivity.end)
|
||||||
|
},
|
||||||
|
duration: {
|
||||||
|
label: propertyLabels.duration,
|
||||||
|
value: this.formatDuration(selectedActivity.end - selectedActivity.start)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.$set(this.activities, index, activity);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
sortFn(a, b) {
|
||||||
|
const numA = parseInt(a.start, 10);
|
||||||
|
const numB = parseInt(b.start, 10);
|
||||||
|
if (numA > numB) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numA < numB) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
setMultipleActivityProperties() {
|
||||||
|
this.activities.splice(0);
|
||||||
|
|
||||||
|
let earliestStart;
|
||||||
|
let latestEnd;
|
||||||
|
let gap;
|
||||||
|
let overlap;
|
||||||
|
|
||||||
|
//Sort by start time
|
||||||
|
let selectedActivities = this.selectedActivities.sort(this.sortFn);
|
||||||
|
selectedActivities.forEach((selectedActivity, index) => {
|
||||||
|
if (selectedActivities.length === 2 && index > 0) {
|
||||||
|
const previous = selectedActivities[index - 1];
|
||||||
|
//they're on different rows so there must be overlap
|
||||||
|
if (previous.end > selectedActivity.start) {
|
||||||
|
overlap = previous.end - selectedActivity.start;
|
||||||
|
} else if (previous.end < selectedActivity.start) {
|
||||||
|
gap = selectedActivity.start - previous.end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index > 0) {
|
||||||
|
earliestStart = Math.min(earliestStart, selectedActivity.start);
|
||||||
|
latestEnd = Math.max(latestEnd, selectedActivity.end);
|
||||||
|
} else {
|
||||||
|
earliestStart = selectedActivity.start;
|
||||||
|
latestEnd = selectedActivity.end;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let totalTime = latestEnd - earliestStart;
|
||||||
|
|
||||||
|
const activity = {
|
||||||
|
id: uuid(),
|
||||||
|
'earliestStart': {
|
||||||
|
label: propertyLabels.earliestStart,
|
||||||
|
value: this.formatTime(earliestStart)
|
||||||
|
},
|
||||||
|
'latestEnd': {
|
||||||
|
label: propertyLabels.latestEnd,
|
||||||
|
value: this.formatTime(latestEnd)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (gap) {
|
||||||
|
activity.gap = {
|
||||||
|
label: propertyLabels.gap,
|
||||||
|
value: this.formatDuration(gap)
|
||||||
|
};
|
||||||
|
} else if (overlap) {
|
||||||
|
activity.overlap = {
|
||||||
|
label: propertyLabels.overlap,
|
||||||
|
value: this.formatDuration(overlap)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
activity.totalTime = {
|
||||||
|
label: propertyLabels.totalTime,
|
||||||
|
value: this.formatDuration(totalTime)
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$set(this.activities, 0, activity);
|
||||||
|
},
|
||||||
|
formatDuration(duration) {
|
||||||
|
return getPreciseDuration(duration);
|
||||||
|
},
|
||||||
|
formatTime(time) {
|
||||||
|
return this.timeFormatter.format(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
84
src/plugins/plan/inspector/PlanActivityView.vue
Normal file
84
src/plugins/plan/inspector/PlanActivityView.vue
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2020, 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="timeProperties.length"
|
||||||
|
class="u-contents"
|
||||||
|
>
|
||||||
|
<div class="c-inspect-properties__header">
|
||||||
|
{{ heading }}
|
||||||
|
</div>
|
||||||
|
<ul v-for="timeProperty in timeProperties"
|
||||||
|
:key="timeProperty.id"
|
||||||
|
class="c-inspect-properties__section"
|
||||||
|
>
|
||||||
|
<activity-property :label="timeProperty.label"
|
||||||
|
:value="timeProperty.value"
|
||||||
|
/>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ActivityProperty from './ActivityProperty.vue';
|
||||||
|
import uuid from 'uuid';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ActivityProperty
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
activity: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
heading: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
timeProperties: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.setProperties();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setProperties() {
|
||||||
|
Object.keys(this.activity).forEach((key) => {
|
||||||
|
if (this.activity[key].label) {
|
||||||
|
const label = this.activity[key].label;
|
||||||
|
const value = String(this.activity[key].value);
|
||||||
|
|
||||||
|
this.$set(this.timeProperties, this.timeProperties.length, {
|
||||||
|
id: uuid(),
|
||||||
|
label,
|
||||||
|
value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
69
src/plugins/plan/inspector/PlanInspectorViewProvider.js
Normal file
69
src/plugins/plan/inspector/PlanInspectorViewProvider.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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 PlanActivitiesView from "./PlanActivitiesView.vue";
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default function PlanInspectorViewProvider(openmct) {
|
||||||
|
return {
|
||||||
|
key: 'plan-inspector',
|
||||||
|
name: 'Plan Inspector View',
|
||||||
|
canView: function (selection) {
|
||||||
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let context = selection[0][0].context;
|
||||||
|
|
||||||
|
return context
|
||||||
|
&& context.type === 'activity';
|
||||||
|
},
|
||||||
|
view: function (selection) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (element) {
|
||||||
|
component = new Vue({
|
||||||
|
el: element,
|
||||||
|
components: {
|
||||||
|
PlanActivitiesView: PlanActivitiesView
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
selection: selection
|
||||||
|
},
|
||||||
|
template: '<plan-activities-view></plan-activities-view>'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
if (component) {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
priority: function () {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -1,3 +1,25 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
.c-plan {
|
.c-plan {
|
||||||
svg {
|
svg {
|
||||||
text-rendering: geometricPrecision;
|
text-rendering: geometricPrecision;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import PlanViewProvider from './PlanViewProvider';
|
import PlanViewProvider from './PlanViewProvider';
|
||||||
|
import PlanInspectorViewProvider from "./inspector/PlanInspectorViewProvider";
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return function install(openmct) {
|
return function install(openmct) {
|
||||||
@ -44,6 +45,7 @@ export default function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
openmct.objectViews.addProvider(new PlanViewProvider(openmct));
|
openmct.objectViews.addProvider(new PlanViewProvider(openmct));
|
||||||
|
openmct.inspectorViews.addProvider(new PlanInspectorViewProvider(openmct));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,25 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
export function getValidatedPlan(domainObject) {
|
export function getValidatedPlan(domainObject) {
|
||||||
let body = domainObject.selectFile.body;
|
let body = domainObject.selectFile.body;
|
||||||
let json = {};
|
let json = {};
|
||||||
|
@ -39,9 +39,8 @@ const DEFAULT_DURATION_FORMATTER = 'duration';
|
|||||||
const LOCAL_STORAGE_HISTORY_KEY_FIXED = 'tcHistory';
|
const LOCAL_STORAGE_HISTORY_KEY_FIXED = 'tcHistory';
|
||||||
const LOCAL_STORAGE_HISTORY_KEY_REALTIME = 'tcHistoryRealtime';
|
const LOCAL_STORAGE_HISTORY_KEY_REALTIME = 'tcHistoryRealtime';
|
||||||
const DEFAULT_RECORDS = 10;
|
const DEFAULT_RECORDS = 10;
|
||||||
const ONE_MINUTE = 60 * 1000;
|
|
||||||
const ONE_HOUR = ONE_MINUTE * 60;
|
import { getDuration } from "utils/duration";
|
||||||
const ONE_DAY = ONE_HOUR * 24;
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'configuration'],
|
inject: ['openmct', 'configuration'],
|
||||||
@ -143,7 +142,7 @@ export default {
|
|||||||
let description = `${startTime} - ${this.formatTime(timespan.end)}`;
|
let description = `${startTime} - ${this.formatTime(timespan.end)}`;
|
||||||
|
|
||||||
if (this.timeSystem.isUTCBased && !this.openmct.time.clock()) {
|
if (this.timeSystem.isUTCBased && !this.openmct.time.clock()) {
|
||||||
name = `${startTime} ${this.getDuration(timespan.end - timespan.start)}`;
|
name = `${startTime} ${getDuration(timespan.end - timespan.start)}`;
|
||||||
} else {
|
} else {
|
||||||
name = description;
|
name = description;
|
||||||
}
|
}
|
||||||
@ -176,41 +175,6 @@ export default {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getDuration(numericDuration) {
|
|
||||||
let result;
|
|
||||||
let age;
|
|
||||||
|
|
||||||
if (numericDuration > ONE_DAY - 1) {
|
|
||||||
age = this.normalizeAge((numericDuration / ONE_DAY).toFixed(2));
|
|
||||||
result = `+ ${age} day`;
|
|
||||||
|
|
||||||
if (age !== 1) {
|
|
||||||
result += 's';
|
|
||||||
}
|
|
||||||
} else if (numericDuration > ONE_HOUR - 1) {
|
|
||||||
age = this.normalizeAge((numericDuration / ONE_HOUR).toFixed(2));
|
|
||||||
result = `+ ${age} hour`;
|
|
||||||
|
|
||||||
if (age !== 1) {
|
|
||||||
result += 's';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
age = this.normalizeAge((numericDuration / ONE_MINUTE).toFixed(2));
|
|
||||||
result = `+ ${age} min`;
|
|
||||||
|
|
||||||
if (age !== 1) {
|
|
||||||
result += 's';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
normalizeAge(num) {
|
|
||||||
const hundredtized = num * 100;
|
|
||||||
const isWhole = hundredtized % 100 === 0;
|
|
||||||
|
|
||||||
return isWhole ? hundredtized / 100 : num;
|
|
||||||
},
|
|
||||||
getHistoryFromLocalStorage() {
|
getHistoryFromLocalStorage() {
|
||||||
const localStorageHistory = localStorage.getItem(this.storageKey);
|
const localStorageHistory = localStorage.getItem(this.storageKey);
|
||||||
const history = localStorageHistory ? JSON.parse(localStorageHistory) : undefined;
|
const history = localStorageHistory ? JSON.parse(localStorageHistory) : undefined;
|
||||||
|
@ -20,7 +20,12 @@
|
|||||||
<span class="c-object-label__type-icon"
|
<span class="c-object-label__type-icon"
|
||||||
:class="typeCssClass"
|
:class="typeCssClass"
|
||||||
></span>
|
></span>
|
||||||
<span class="c-object-label__name">Layout Object</span>
|
<span v-if="!activity"
|
||||||
|
class="c-object-label__name"
|
||||||
|
>Layout Object</span>
|
||||||
|
<span v-else
|
||||||
|
class="c-object-label__name"
|
||||||
|
>{{ activity.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="multiSelect"
|
<div v-if="multiSelect"
|
||||||
@ -37,6 +42,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
domainObject: {},
|
domainObject: {},
|
||||||
|
activity: undefined,
|
||||||
keyString: undefined,
|
keyString: undefined,
|
||||||
multiSelect: false,
|
multiSelect: false,
|
||||||
itemsSelected: 0,
|
itemsSelected: 0,
|
||||||
@ -51,6 +57,10 @@ export default {
|
|||||||
return this.openmct.types.get(this.item.type);
|
return this.openmct.types.get(this.item.type);
|
||||||
},
|
},
|
||||||
typeCssClass() {
|
typeCssClass() {
|
||||||
|
if (this.activity) {
|
||||||
|
return 'icon-activity';
|
||||||
|
}
|
||||||
|
|
||||||
if (this.type.definition.cssClass === undefined) {
|
if (this.type.definition.cssClass === undefined) {
|
||||||
return 'icon-object';
|
return 'icon-object';
|
||||||
}
|
}
|
||||||
@ -97,7 +107,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.multiSelect = false;
|
this.multiSelect = false;
|
||||||
this.domainObject = selection[0][0].context.item;
|
this.domainObject = selection[0][0].context.item;
|
||||||
|
this.activity = selection[0][0].context.activity;
|
||||||
if (this.domainObject) {
|
if (this.domainObject) {
|
||||||
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
this.status = this.openmct.status.get(this.keyString);
|
this.status = this.openmct.status.get(this.keyString);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-inspector__properties c-inspect-properties">
|
<div v-if="!activity"
|
||||||
|
class="c-inspector__properties c-inspect-properties"
|
||||||
|
>
|
||||||
<div class="c-inspect-properties__header">
|
<div class="c-inspect-properties__header">
|
||||||
Details
|
Details
|
||||||
</div>
|
</div>
|
||||||
@ -81,6 +83,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
domainObject: {},
|
domainObject: {},
|
||||||
|
activity: undefined,
|
||||||
multiSelect: false
|
multiSelect: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -157,6 +160,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.multiSelect = false;
|
this.multiSelect = false;
|
||||||
this.domainObject = selection[0][0].context.item;
|
this.domainObject = selection[0][0].context.item;
|
||||||
|
this.activity = selection[0][0].context.activity;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
formatTime(unixTime) {
|
formatTime(unixTime) {
|
||||||
|
85
src/utils/duration.js
Normal file
85
src/utils/duration.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
const ONE_MINUTE = 60 * 1000;
|
||||||
|
const ONE_HOUR = ONE_MINUTE * 60;
|
||||||
|
const ONE_DAY = ONE_HOUR * 24;
|
||||||
|
|
||||||
|
function normalizeAge(num) {
|
||||||
|
const hundredtized = num * 100;
|
||||||
|
const isWhole = hundredtized % 100 === 0;
|
||||||
|
|
||||||
|
return isWhole ? hundredtized / 100 : num;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toDoubleDigits(num) {
|
||||||
|
if (num >= 10) {
|
||||||
|
return num;
|
||||||
|
} else {
|
||||||
|
return `0${num}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDuration(numericDuration) {
|
||||||
|
let result;
|
||||||
|
let age;
|
||||||
|
|
||||||
|
if (numericDuration > ONE_DAY - 1) {
|
||||||
|
age = normalizeAge((numericDuration / ONE_DAY)).toFixed(2);
|
||||||
|
result = `+ ${age} day`;
|
||||||
|
|
||||||
|
if (age !== 1) {
|
||||||
|
result += 's';
|
||||||
|
}
|
||||||
|
} else if (numericDuration > ONE_HOUR - 1) {
|
||||||
|
age = normalizeAge((numericDuration / ONE_HOUR).toFixed(2));
|
||||||
|
result = `+ ${age} hour`;
|
||||||
|
|
||||||
|
if (age !== 1) {
|
||||||
|
result += 's';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
age = normalizeAge((numericDuration / ONE_MINUTE).toFixed(2));
|
||||||
|
result = `+ ${age} min`;
|
||||||
|
|
||||||
|
if (age !== 1) {
|
||||||
|
result += 's';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPreciseDuration(numericDuration) {
|
||||||
|
let result;
|
||||||
|
|
||||||
|
const days = toDoubleDigits(Math.floor((numericDuration) / (24 * 60 * 60 * 1000)));
|
||||||
|
let remaining = (numericDuration) % (24 * 60 * 60 * 1000);
|
||||||
|
const hours = toDoubleDigits(Math.floor((remaining) / (60 * 60 * 1000)));
|
||||||
|
remaining = (remaining) % (60 * 60 * 1000);
|
||||||
|
const minutes = toDoubleDigits(Math.floor((remaining) / (60 * 1000)));
|
||||||
|
remaining = (remaining) % (60 * 1000);
|
||||||
|
const seconds = toDoubleDigits(Math.floor((remaining) / (1000)));
|
||||||
|
result = `${days}:${hours}:${minutes}:${seconds}`;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user