Compare commits
	
		
			3 Commits
		
	
	
		
			status-are
			...
			add-events
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e75cc35cb7 | ||
| 
						 | 
					f216bd8769 | ||
| 
						 | 
					79a430278e | 
@@ -38,7 +38,7 @@ define([
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    IndicatorAPI.prototype.simpleIndicator = function () {
 | 
			
		||||
        return new SimpleIndicator(this.openmct);
 | 
			
		||||
        return new SimpleIndicator.default(this.openmct);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -20,82 +20,104 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(['zepto', './res/indicator-template.html'],
 | 
			
		||||
    function ($, indicatorTemplate) {
 | 
			
		||||
        const DEFAULT_ICON_CLASS = 'icon-info';
 | 
			
		||||
import EventEmitter from 'EventEmitter';
 | 
			
		||||
import indicatorTemplate from './res/indicator-template.html';
 | 
			
		||||
 | 
			
		||||
        function SimpleIndicator(openmct) {
 | 
			
		||||
            this.openmct = openmct;
 | 
			
		||||
            this.element = $(indicatorTemplate)[0];
 | 
			
		||||
            this.priority = openmct.priority.DEFAULT;
 | 
			
		||||
const DEFAULT_ICON_CLASS = 'icon-info';
 | 
			
		||||
 | 
			
		||||
            this.textElement = this.element.querySelector('.js-indicator-text');
 | 
			
		||||
class SimpleIndicator extends EventEmitter{
 | 
			
		||||
    constructor(openmct) {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
            //Set defaults
 | 
			
		||||
            this.text('New Indicator');
 | 
			
		||||
            this.description('');
 | 
			
		||||
            this.iconClass(DEFAULT_ICON_CLASS);
 | 
			
		||||
            this.statusClass('');
 | 
			
		||||
        }
 | 
			
		||||
        this.openmct = openmct;
 | 
			
		||||
        this.element = compileTemplate(indicatorTemplate)[0];
 | 
			
		||||
        this.priority = openmct.priority.DEFAULT;
 | 
			
		||||
    
 | 
			
		||||
        this.textElement = this.element.querySelector('.js-indicator-text');
 | 
			
		||||
    
 | 
			
		||||
        //Set defaults
 | 
			
		||||
        this.text('New Indicator');
 | 
			
		||||
        this.description('');
 | 
			
		||||
        this.iconClass(DEFAULT_ICON_CLASS);
 | 
			
		||||
        this.statusClass('');
 | 
			
		||||
        
 | 
			
		||||
        this.click = this.click.bind(this);
 | 
			
		||||
 | 
			
		||||
        SimpleIndicator.prototype.text = function (text) {
 | 
			
		||||
            if (text !== undefined && text !== this.textValue) {
 | 
			
		||||
                this.textValue = text;
 | 
			
		||||
                this.textElement.innerText = text;
 | 
			
		||||
 | 
			
		||||
                if (!text) {
 | 
			
		||||
                    this.element.classList.add('hidden');
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.element.classList.remove('hidden');
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.textValue;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        SimpleIndicator.prototype.description = function (description) {
 | 
			
		||||
            if (description !== undefined && description !== this.descriptionValue) {
 | 
			
		||||
                this.descriptionValue = description;
 | 
			
		||||
                this.element.title = description;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.descriptionValue;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        SimpleIndicator.prototype.iconClass = function (iconClass) {
 | 
			
		||||
            if (iconClass !== undefined && iconClass !== this.iconClassValue) {
 | 
			
		||||
                // element.classList is precious and throws errors if you try and add
 | 
			
		||||
                // or remove empty strings
 | 
			
		||||
                if (this.iconClassValue) {
 | 
			
		||||
                    this.element.classList.remove(this.iconClassValue);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (iconClass) {
 | 
			
		||||
                    this.element.classList.add(iconClass);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.iconClassValue = iconClass;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.iconClassValue;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        SimpleIndicator.prototype.statusClass = function (statusClass) {
 | 
			
		||||
            if (statusClass !== undefined && statusClass !== this.statusClassValue) {
 | 
			
		||||
                if (this.statusClassValue) {
 | 
			
		||||
                    this.element.classList.remove(this.statusClassValue);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (statusClass) {
 | 
			
		||||
                    this.element.classList.add(statusClass);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.statusClassValue = statusClass;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.statusClassValue;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return SimpleIndicator;
 | 
			
		||||
        this.element.addEventListener('click', this.click);
 | 
			
		||||
        openmct.once('destroy', () => {
 | 
			
		||||
            this.removeAllListeners();
 | 
			
		||||
            this.element.removeEventListener('click', this.click)
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
    text(text) {
 | 
			
		||||
        if (text !== undefined && text !== this.textValue) {
 | 
			
		||||
            this.textValue = text;
 | 
			
		||||
            this.textElement.innerText = text;
 | 
			
		||||
    
 | 
			
		||||
            if (!text) {
 | 
			
		||||
                this.element.classList.add('hidden');
 | 
			
		||||
            } else {
 | 
			
		||||
                this.element.classList.remove('hidden');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        return this.textValue;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    description(description) {
 | 
			
		||||
        if (description !== undefined && description !== this.descriptionValue) {
 | 
			
		||||
            this.descriptionValue = description;
 | 
			
		||||
            this.element.title = description;
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        return this.descriptionValue;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    iconClass(iconClass) {
 | 
			
		||||
        if (iconClass !== undefined && iconClass !== this.iconClassValue) {
 | 
			
		||||
            // element.classList is precious and throws errors if you try and add
 | 
			
		||||
            // or remove empty strings
 | 
			
		||||
            if (this.iconClassValue) {
 | 
			
		||||
                this.element.classList.remove(this.iconClassValue);
 | 
			
		||||
            }
 | 
			
		||||
    
 | 
			
		||||
            if (iconClass) {
 | 
			
		||||
                this.element.classList.add(iconClass);
 | 
			
		||||
            }
 | 
			
		||||
    
 | 
			
		||||
            this.iconClassValue = iconClass;
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        return this.iconClassValue;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    statusClass(statusClass) {
 | 
			
		||||
        if (statusClass !== undefined && statusClass !== this.statusClassValue) {
 | 
			
		||||
            if (this.statusClassValue) {
 | 
			
		||||
                this.element.classList.remove(this.statusClassValue);
 | 
			
		||||
            }
 | 
			
		||||
    
 | 
			
		||||
            if (statusClass) {
 | 
			
		||||
                this.element.classList.add(statusClass);
 | 
			
		||||
            }
 | 
			
		||||
    
 | 
			
		||||
            this.statusClassValue = statusClass;
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        return this.statusClassValue;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    click(event) {
 | 
			
		||||
        this.emit('click', event);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function compileTemplate(htmlTemplate) {
 | 
			
		||||
    const templateNode = document.createElement('template');
 | 
			
		||||
    templateNode.innerHTML = htmlTemplate;
 | 
			
		||||
    
 | 
			
		||||
    return templateNode.content.cloneNode(true).children;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default SimpleIndicator;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										207
									
								
								src/plugins/operatorStatus/OperatorStatus.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								src/plugins/operatorStatus/OperatorStatus.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,207 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div :style="position" class="c-menu" @click.stop="noop">
 | 
			
		||||
        <div>My Role: {{role}}</div>
 | 
			
		||||
        <div>Current Poll Question: {{currentPollQuestion}}</div>
 | 
			
		||||
        <div>Current Poll Date: {{pollQuestionUpdated}}</div>
 | 
			
		||||
        <div>My Status: {{roleStatus}}</div>
 | 
			
		||||
        <div>Set Status:
 | 
			
		||||
            <select v-model="selectedStatus" name="setStatus" @change="setStatus">
 | 
			
		||||
                <option v-for="status in allStatuses" :key="status.value" :value="status.value">{{status.label}}</option>
 | 
			
		||||
            </select>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
// TODO: Make this configuration
 | 
			
		||||
const ROLES = ['Driver'];
 | 
			
		||||
const POLL_TELEMETRY_POINT_ID = {
 | 
			
		||||
    namespace: 'taxonomy',
 | 
			
		||||
    key: '~ViperGround~OperatorStatus~PollQuestion'
 | 
			
		||||
};
 | 
			
		||||
const POLL_QUESTION_KEY = 'value';
 | 
			
		||||
 | 
			
		||||
const ROLE_STATUS_TELEMETRY_POINT_ID = {
 | 
			
		||||
    namespace: 'taxonomy',
 | 
			
		||||
    key: '~ViperGround~OperatorStatus~driverStatus'
 | 
			
		||||
};
 | 
			
		||||
const ROLE_STATUS_KEY = 'value';
 | 
			
		||||
const SET_STATUS_URL = 'http://localhost:9000/viper-proxy/viper/yamcs/api/processors/viper/realtime/parameters/ViperGround/OperatorStatus/driverStatus';
 | 
			
		||||
const STATUSES = [
 | 
			
		||||
    {
 | 
			
		||||
        value: 0,
 | 
			
		||||
        label: 'NO_STATUS'
 | 
			
		||||
    },{
 | 
			
		||||
        value: 1,
 | 
			
		||||
        label: 'NO_GO'
 | 
			
		||||
    },{
 | 
			
		||||
        value: 2,
 | 
			
		||||
        label: 'GO'
 | 
			
		||||
    },{
 | 
			
		||||
        value: 3,
 | 
			
		||||
        label: 'MAYBE'
 | 
			
		||||
    },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
    props: {
 | 
			
		||||
        positionX: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: true
 | 
			
		||||
        },
 | 
			
		||||
        positionY: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: true
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            role: '--',
 | 
			
		||||
            pollQuestionUpdated: '--',
 | 
			
		||||
            currentPollQuestion: '--',
 | 
			
		||||
            roleStatus: '--',
 | 
			
		||||
            selectedStatus: 'no-go',
 | 
			
		||||
            allStatuses: STATUSES
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    async mounted() {
 | 
			
		||||
        this.unsubscribe = [];
 | 
			
		||||
        this.fetchAllStatuses();
 | 
			
		||||
 | 
			
		||||
        await this.fetchTelemetryObjects();
 | 
			
		||||
        this.setMetadata();
 | 
			
		||||
        this.fetchCurrentPoll();
 | 
			
		||||
        this.fetchMyStatus();
 | 
			
		||||
        this.subscribeToMyStatus();
 | 
			
		||||
        this.subscribeToPollQuestion();
 | 
			
		||||
 | 
			
		||||
        this.findFirstApplicableRole();
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        fetchAllStatuses() {
 | 
			
		||||
            //this.allStatuses = openmct.user.getAllStatuses();
 | 
			
		||||
        },
 | 
			
		||||
        async fetchTelemetryObjects() {
 | 
			
		||||
            const telemetryObjects = await Promise.all([
 | 
			
		||||
                this.openmct.objects.get(ROLE_STATUS_TELEMETRY_POINT_ID),
 | 
			
		||||
                this.openmct.objects.get(POLL_TELEMETRY_POINT_ID)
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            this.roleStatusTelemetryObject = telemetryObjects[0];
 | 
			
		||||
            this.pollQuestionTelemetryObject = telemetryObjects[1];
 | 
			
		||||
        },
 | 
			
		||||
        setMetadata() {
 | 
			
		||||
            const roleStatusMetadata = openmct.telemetry.getMetadata(this.roleStatusTelemetryObject);
 | 
			
		||||
            const roleStatusMetadataValue = roleStatusMetadata.value(ROLE_STATUS_KEY);
 | 
			
		||||
 | 
			
		||||
            const pollQuestionMetadata = openmct.telemetry.getMetadata(this.pollQuestionTelemetryObject);
 | 
			
		||||
            const pollQuestionMetadataValue = pollQuestionMetadata.value(POLL_QUESTION_KEY);
 | 
			
		||||
            
 | 
			
		||||
            const timestampMetadataValue = pollQuestionMetadata.value(this.openmct.time.timeSystem().key);
 | 
			
		||||
 | 
			
		||||
            this.timestampFormatter = openmct.telemetry.getValueFormatter(timestampMetadataValue);
 | 
			
		||||
            this.statusFormatter = openmct.telemetry.getValueFormatter(roleStatusMetadataValue);
 | 
			
		||||
            this.pollQuestionFormatter = openmct.telemetry.getValueFormatter(pollQuestionMetadataValue);
 | 
			
		||||
        },
 | 
			
		||||
        async findFirstApplicableRole() {
 | 
			
		||||
            const userRolesMap = await Promise.all(ROLES.map((role) => this.openmct.user.hasRole(role)));
 | 
			
		||||
            const index = userRolesMap.findIndex((hasRole) => hasRole);
 | 
			
		||||
            
 | 
			
		||||
            this.role = ROLES[index];
 | 
			
		||||
        },
 | 
			
		||||
        async fetchCurrentPoll() {
 | 
			
		||||
            //const pollMessage = await openmct.user.getCurrentPollQuestion();
 | 
			
		||||
 | 
			
		||||
            const pollMessages = await this.openmct.telemetry.request(this.pollQuestionTelemetryObject, {
 | 
			
		||||
                strategy: 'latest',
 | 
			
		||||
                // TODO: THIS IS A HACK, NEED A WAY TO ALWAYS GET THE LAST VALUE FROM ANY TIME WINDOW (maybe getParameterValue()? What happens if there is nothing in the cache though (eg after a restart))
 | 
			
		||||
                start: 0,
 | 
			
		||||
                end: Date.now()
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (pollMessages.length > 0) {
 | 
			
		||||
                const datum = pollMessages[pollMessages.length - 1];
 | 
			
		||||
 | 
			
		||||
                this.setPollQuestionFromDatum(datum);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        },
 | 
			
		||||
        setPollQuestionFromDatum(datum) {
 | 
			
		||||
            this.currentPollQuestion = this.pollQuestionFormatter.format(datum);
 | 
			
		||||
            this.pollQuestionUpdated = this.timestampFormatter.format(datum);
 | 
			
		||||
        },
 | 
			
		||||
        async fetchMyStatus() {
 | 
			
		||||
            // const currentUser = this.openmct.user.getCurrentUser();
 | 
			
		||||
            // const status = await this.openmct.user.getStatus(currentUser);
 | 
			
		||||
 | 
			
		||||
            // TODO: Make role-specific
 | 
			
		||||
            const roleStatuses = await this.openmct.telemetry.request(this.roleStatusTelemetryObject, {
 | 
			
		||||
                strategy: 'latest',
 | 
			
		||||
                start: 0,
 | 
			
		||||
                end: Date.now()
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (roleStatuses.length > 0) {
 | 
			
		||||
                const datum = roleStatuses[roleStatuses.length - 1];
 | 
			
		||||
 | 
			
		||||
                this.setRoleStatusFromDatum(datum);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        subscribeToMyStatus() {
 | 
			
		||||
            // const currentUser = this.openmct.user.getCurrentUser();
 | 
			
		||||
            // this.openmct.user.onUserStatusChange(currentUser, this.setRoleStatus);
 | 
			
		||||
 | 
			
		||||
            this.unsubscribe.push(this.openmct.telemetry.subscribe(this.roleStatusTelemetryObject, (datum) => {
 | 
			
		||||
                this.setRoleStatusFromDatum(datum);
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        subscribeToPollQuestion() {
 | 
			
		||||
            this.unsubscribe.push(this.openmct.telemetry.subscribe(this.roleStatusTelemetryObject, (datum) => {
 | 
			
		||||
                this.setRoleStatusFromDatum(datum);
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        setRoleStatusFromDatum(datum) {
 | 
			
		||||
            this.roleStatus = this.statusFormatter.format(datum);
 | 
			
		||||
            this.selectedStatus = this.findStatus(this.roleStatus);
 | 
			
		||||
        },
 | 
			
		||||
        findStatus(status) {
 | 
			
		||||
            return (STATUSES.find(s => s.label === status) || STATUSES[0]).value;
 | 
			
		||||
        },
 | 
			
		||||
        async setStatus(status) {
 | 
			
		||||
            // Where does 'status' come from. What does it look like?
 | 
			
		||||
            // Could be provided as an enum from the user API.
 | 
			
		||||
 | 
			
		||||
            //const result = await openmct.user.setStatus(user, status);
 | 
			
		||||
 | 
			
		||||
            // const newDatum = openmct.telemetry.newDatumFromValues(this.statusDomainObject)
 | 
			
		||||
            // const result = await openmct.telemetry.setValue(this.statusDomainObject, newDatum);
 | 
			
		||||
 | 
			
		||||
            const fetchResult = await fetch(SET_STATUS_URL, {
 | 
			
		||||
                method: 'PUT',
 | 
			
		||||
                headers: {
 | 
			
		||||
                    'Content-Type': 'application/json'
 | 
			
		||||
                },
 | 
			
		||||
                body: JSON.stringify({
 | 
			
		||||
                    type: 'UINT32',
 | 
			
		||||
                    uint32Value: `${this.selectedStatus}`
 | 
			
		||||
                })
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        noop() {}
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        position() {
 | 
			
		||||
            return {
 | 
			
		||||
                position: 'absolute',
 | 
			
		||||
                left: `${this.positionX}px`,
 | 
			
		||||
                top: `${this.positionY}px`
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    beforeDestroy() {
 | 
			
		||||
        this.unsubscribe.forEach(unsubscribe => unsubscribe);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										135
									
								
								src/plugins/operatorStatus/PollQuestion.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								src/plugins/operatorStatus/PollQuestion.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div :style="position" class="c-menu" @click.stop="noop">
 | 
			
		||||
        <div>Current Poll Question: {{currentPollQuestion}}</div>
 | 
			
		||||
        <div>Current Poll Date: {{pollQuestionUpdated}}</div>
 | 
			
		||||
        <div>Set Poll Question:
 | 
			
		||||
            <input type="text" v-model="newPollQuestion" name="newPollQuestion" @change="setPollQuestion">
 | 
			
		||||
        </div>
 | 
			
		||||
        <div><button class="c-button" @click="clearAllResponses"> Clear All Responses</button></div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
const POLL_TELEMETRY_POINT_ID = {
 | 
			
		||||
    namespace: 'taxonomy',
 | 
			
		||||
    key: '~ViperGround~OperatorStatus~PollQuestion'
 | 
			
		||||
};
 | 
			
		||||
const POLL_QUESTION_KEY = 'value';
 | 
			
		||||
 | 
			
		||||
const SET_POLL_QUESTION_URL = 'http://localhost:9000/viper-proxy/viper/yamcs/api/processors/viper/realtime/parameters/ViperGround/OperatorStatus/PollQuestion';
 | 
			
		||||
const CLEAR_RESPONSES_URL = 'http://localhost:9000/viper-proxy/viper/yamcs/api/processors/viper/realtime/parameters:batchSet';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
    props: {
 | 
			
		||||
        positionX: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: true
 | 
			
		||||
        },
 | 
			
		||||
        positionY: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: true
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            pollQuestionUpdated: '--',
 | 
			
		||||
            currentPollQuestion: '--',
 | 
			
		||||
            newPollQuestion: undefined
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    async mounted() {
 | 
			
		||||
        this.unsubscribe = [];
 | 
			
		||||
        this.pollQuestionTelemetryObject = await this.openmct.objects.get(POLL_TELEMETRY_POINT_ID);
 | 
			
		||||
 | 
			
		||||
        this.setMetadata();
 | 
			
		||||
        this.fetchCurrentPoll();
 | 
			
		||||
        this.subscribeToPollQuestion();
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        setMetadata() {
 | 
			
		||||
            const pollQuestionMetadata = openmct.telemetry.getMetadata(this.pollQuestionTelemetryObject);
 | 
			
		||||
            const pollQuestionMetadataValue = pollQuestionMetadata.value(POLL_QUESTION_KEY);
 | 
			
		||||
            const timestampMetadataValue = pollQuestionMetadata.value(this.openmct.time.timeSystem().key);
 | 
			
		||||
 | 
			
		||||
            this.timestampFormatter = openmct.telemetry.getValueFormatter(timestampMetadataValue);
 | 
			
		||||
            this.pollQuestionFormatter = openmct.telemetry.getValueFormatter(pollQuestionMetadataValue);
 | 
			
		||||
        },
 | 
			
		||||
        async fetchCurrentPoll() {
 | 
			
		||||
            const pollMessages = await this.openmct.telemetry.request(this.pollQuestionTelemetryObject, {
 | 
			
		||||
                strategy: 'latest',
 | 
			
		||||
                // TODO: THIS IS A HACK, NEED A WAY TO ALWAYS GET THE LAST VALUE FROM ANY TIME WINDOW (maybe getParameterValue()? What happens if there is nothing in the cache though (eg after a restart))
 | 
			
		||||
                start: 0,
 | 
			
		||||
                end: Date.now()
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (pollMessages.length > 0) {
 | 
			
		||||
                const datum = pollMessages[pollMessages.length - 1];
 | 
			
		||||
 | 
			
		||||
                this.setPollQuestionFromDatum(datum);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        },
 | 
			
		||||
        subscribeToPollQuestion() {
 | 
			
		||||
            this.unsubscribe.push(this.openmct.telemetry.subscribe(this.pollQuestionTelemetryObject, (datum) => {
 | 
			
		||||
                this.setPollQuestionFromDatum(datum);
 | 
			
		||||
            }));
 | 
			
		||||
        },
 | 
			
		||||
        setPollQuestionFromDatum(datum) {
 | 
			
		||||
            this.currentPollQuestion = this.pollQuestionFormatter.format(datum);
 | 
			
		||||
            this.pollQuestionUpdated = this.timestampFormatter.format(datum);
 | 
			
		||||
        },
 | 
			
		||||
        async setPollQuestion() {
 | 
			
		||||
            //const response = await this.openmct.user.setPollQuestion(this.newPollQuestion);
 | 
			
		||||
 | 
			
		||||
            await fetch(SET_POLL_QUESTION_URL, {
 | 
			
		||||
                method: 'PUT',
 | 
			
		||||
                headers: {
 | 
			
		||||
                    'Content-Type': 'application/json'
 | 
			
		||||
                },
 | 
			
		||||
                body: JSON.stringify({
 | 
			
		||||
                    type: 'STRING',
 | 
			
		||||
                    stringValue: `${this.newPollQuestion}`
 | 
			
		||||
                })
 | 
			
		||||
            });
 | 
			
		||||
            this.newPollQuestion = undefined;
 | 
			
		||||
        },
 | 
			
		||||
        clearAllResponses() {
 | 
			
		||||
            //this.openmct.user.clearAllStatuses();
 | 
			
		||||
 | 
			
		||||
            fetch(CLEAR_RESPONSES_URL, {
 | 
			
		||||
                method: 'POST',
 | 
			
		||||
                headers: {
 | 
			
		||||
                    'Content-Type': 'application/json'
 | 
			
		||||
                },
 | 
			
		||||
                body: JSON.stringify({
 | 
			
		||||
                    request: [{
 | 
			
		||||
                        id: {
 | 
			
		||||
                            name: "/ViperGround/OperatorStatus/driverStatus",
 | 
			
		||||
                        },
 | 
			
		||||
                        value: {
 | 
			
		||||
                            type: 'UINT32',
 | 
			
		||||
                            uint32Value: '0'
 | 
			
		||||
                        }
 | 
			
		||||
                    //TODO: Also set all the other operator status parameters
 | 
			
		||||
                    }]
 | 
			
		||||
                })
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        noop() {}
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        position() {
 | 
			
		||||
            return {
 | 
			
		||||
                position: 'absolute',
 | 
			
		||||
                left: `${this.positionX}px`,
 | 
			
		||||
                top: `${this.positionY}px`
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    beforeDestroy() {
 | 
			
		||||
        this.unsubscribe.forEach(unsubscribe => unsubscribe);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										89
									
								
								src/plugins/operatorStatus/plugin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/plugins/operatorStatus/plugin.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Could potentially be implemented using the User API to make this "generic" (although only supported from Yamcs initially)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import OperatorStatusComponent from './OperatorStatus.vue';
 | 
			
		||||
import PollQuestionComponent from './PollQuestion.vue';
 | 
			
		||||
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
export default function operatorStatusPlugin(config) {
 | 
			
		||||
    return function install(openmct) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
            Operator Status
 | 
			
		||||
         */
 | 
			
		||||
        const operatorStatusElement = new Vue({
 | 
			
		||||
            components: {
 | 
			
		||||
                OperatorStatus: OperatorStatusComponent
 | 
			
		||||
            },
 | 
			
		||||
            provide: {
 | 
			
		||||
                openmct
 | 
			
		||||
            },
 | 
			
		||||
            data() {
 | 
			
		||||
                return {
 | 
			
		||||
                    positionX: 0,
 | 
			
		||||
                    positionY: 0
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            template: '<operator-status :positionX="positionX" :positionY="positionY" />'
 | 
			
		||||
        }).$mount();
 | 
			
		||||
 | 
			
		||||
        const operatorIndicator = openmct.indicators.simpleIndicator();
 | 
			
		||||
 | 
			
		||||
        operatorIndicator.text("My Operator Status");
 | 
			
		||||
        operatorIndicator.description("Set my operator status");
 | 
			
		||||
        operatorIndicator.iconClass('icon-check');
 | 
			
		||||
        operatorIndicator.on('click', (event) => {
 | 
			
		||||
            //Don't propagate, otherwise this event will trigger the listener below and remove itself.
 | 
			
		||||
            event.stopPropagation();
 | 
			
		||||
            document.body.appendChild(operatorStatusElement.$el);
 | 
			
		||||
            operatorStatusElement.positionX = event.clientX;
 | 
			
		||||
            operatorStatusElement.positionY = event.clientY;
 | 
			
		||||
 | 
			
		||||
            document.addEventListener('click', event => {
 | 
			
		||||
                operatorStatusElement.$el.remove();
 | 
			
		||||
            }, {once: true});
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        openmct.indicators.add(operatorIndicator);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
            Poll Question
 | 
			
		||||
         */
 | 
			
		||||
        const pollQuestionElement = new Vue({
 | 
			
		||||
            components: {
 | 
			
		||||
                PollQuestion: PollQuestionComponent
 | 
			
		||||
            },
 | 
			
		||||
            provide: {
 | 
			
		||||
                openmct
 | 
			
		||||
            },
 | 
			
		||||
            data() {
 | 
			
		||||
                return {
 | 
			
		||||
                    positionX: 0,
 | 
			
		||||
                    positionY: 0
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            template: '<poll-question :positionX="positionX" :positionY="positionY" />'
 | 
			
		||||
        }).$mount();
 | 
			
		||||
 | 
			
		||||
        const pollQuestionIndicator = openmct.indicators.simpleIndicator();
 | 
			
		||||
 | 
			
		||||
        pollQuestionIndicator.text("Poll Question");
 | 
			
		||||
        pollQuestionIndicator.description("Set the current poll question");
 | 
			
		||||
        pollQuestionIndicator.iconClass('icon-draft');
 | 
			
		||||
        pollQuestionIndicator.on('click', (event) => {
 | 
			
		||||
            //Don't propagate, otherwise this event will trigger the listener below and remove itself.
 | 
			
		||||
            event.stopPropagation();
 | 
			
		||||
            document.body.appendChild(pollQuestionElement.$el);
 | 
			
		||||
            pollQuestionElement.positionX = event.clientX;
 | 
			
		||||
            pollQuestionElement.positionY = event.clientY;
 | 
			
		||||
 | 
			
		||||
            document.addEventListener('click', event => {
 | 
			
		||||
                pollQuestionElement.$el.remove();
 | 
			
		||||
            }, {once: true});
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        openmct.indicators.add(pollQuestionIndicator);
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
@@ -76,7 +76,8 @@ define([
 | 
			
		||||
    './timer/plugin',
 | 
			
		||||
    './userIndicator/plugin',
 | 
			
		||||
    '../../example/exampleUser/plugin',
 | 
			
		||||
    './localStorage/plugin'
 | 
			
		||||
    './localStorage/plugin',
 | 
			
		||||
    './operatorStatus/plugin'
 | 
			
		||||
], function (
 | 
			
		||||
    _,
 | 
			
		||||
    UTCTimeSystem,
 | 
			
		||||
@@ -133,7 +134,8 @@ define([
 | 
			
		||||
    Timer,
 | 
			
		||||
    UserIndicator,
 | 
			
		||||
    ExampleUser,
 | 
			
		||||
    LocalStorage
 | 
			
		||||
    LocalStorage,
 | 
			
		||||
    OperatorStatus
 | 
			
		||||
) {
 | 
			
		||||
    const plugins = {};
 | 
			
		||||
 | 
			
		||||
@@ -210,6 +212,7 @@ define([
 | 
			
		||||
    plugins.DeviceClassifier = DeviceClassifier.default;
 | 
			
		||||
    plugins.UserIndicator = UserIndicator.default;
 | 
			
		||||
    plugins.LocalStorage = LocalStorage.default;
 | 
			
		||||
    plugins.OperatorStatus = OperatorStatus.default;
 | 
			
		||||
 | 
			
		||||
    return plugins;
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user