mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 02:29:24 +00:00
Compare commits
21 Commits
master
...
mct6555-v2
Author | SHA1 | Date | |
---|---|---|---|
15bab81447 | |||
cf8db0a21d | |||
bda652b3bb | |||
e7f2f4b5f6 | |||
18b5ee1340 | |||
9006c13eb4 | |||
d7b16a5a2c | |||
a76701c23a | |||
bb52291ab6 | |||
87db357b5a | |||
587c27464b | |||
e0bad2620e | |||
0222b77941 | |||
e05d812219 | |||
d51498752f | |||
a3b1fa34e4 | |||
598ebddd29 | |||
010e86bf83 | |||
e8ed10db78 | |||
fd20d392c2 | |||
841c999d16 |
@ -63,16 +63,21 @@ const STATUSES = [
|
||||
* @implements {StatusUserProvider}
|
||||
*/
|
||||
export default class ExampleUserProvider extends EventEmitter {
|
||||
constructor(openmct, { defaultStatusRole } = { defaultStatusRole: undefined }) {
|
||||
super();
|
||||
constructor(openmct, {statusRoles} = {
|
||||
statusRoles: []
|
||||
}) {
|
||||
super();
|
||||
|
||||
this.openmct = openmct;
|
||||
this.user = undefined;
|
||||
this.loggedIn = false;
|
||||
this.autoLoginUser = undefined;
|
||||
this.status = STATUSES[0];
|
||||
this.pollQuestion = undefined;
|
||||
this.defaultStatusRole = defaultStatusRole;
|
||||
this.openmct = openmct;
|
||||
this.user = undefined;
|
||||
this.loggedIn = false;
|
||||
this.autoLoginUser = undefined;
|
||||
this.statusRoleValues = statusRoles.map(x => ({
|
||||
role: x,
|
||||
status: STATUSES[0]
|
||||
}));
|
||||
this.pollQuestion = undefined;
|
||||
this.statusRoles = statusRoles;
|
||||
|
||||
this.ExampleUser = createExampleUser(this.openmct.user.User);
|
||||
this.loginPromise = undefined;
|
||||
@ -169,41 +174,126 @@ export default class ExampleUserProvider extends EventEmitter {
|
||||
return Promise.resolve(STATUSES);
|
||||
}
|
||||
|
||||
_login() {
|
||||
const id = uuid();
|
||||
|
||||
|
||||
// for testing purposes, this will skip the form, this wouldn't be used in
|
||||
// a normal authentication process
|
||||
if (this.autoLoginUser) {
|
||||
this.user = new this.ExampleUser(id, this.autoLoginUser, ['example-role']);
|
||||
this.loggedIn = true;
|
||||
canProvideStatusForRole(role) {
|
||||
return this.statusRoles.includes(role);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const formStructure = {
|
||||
title: 'Login',
|
||||
sections: [
|
||||
{
|
||||
rows: [
|
||||
{
|
||||
key: 'username',
|
||||
control: 'textfield',
|
||||
name: 'Username',
|
||||
pattern: '\\S+',
|
||||
required: true,
|
||||
cssClass: 'l-input-lg',
|
||||
value: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
buttons: {
|
||||
submit: {
|
||||
label: 'Login'
|
||||
}
|
||||
canSetPollQuestion() {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
hasRole(roleId) {
|
||||
if (!this.loggedIn) {
|
||||
Promise.resolve(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
return Promise.resolve(this.user.getRoles().includes(roleId));
|
||||
}
|
||||
|
||||
getPossibleRoles() {
|
||||
return this.user.getRoles();
|
||||
}
|
||||
|
||||
getStatusRoleForCurrentUser(role) {
|
||||
const matchedRole = this.statusRoleValues.find(x => x.role === role);
|
||||
|
||||
return Promise.resolve(matchedRole?.status);
|
||||
}
|
||||
|
||||
getAllStatusRoles() {
|
||||
return Promise.resolve(this.statusRoles);
|
||||
}
|
||||
|
||||
getStatusForRole(role) {
|
||||
const statusForRole = this.statusRoleValues.find(x => x.role === role);
|
||||
|
||||
return Promise.resolve(statusForRole?.status);
|
||||
}
|
||||
|
||||
async getDefaultStatusForRole(role) {
|
||||
const allRoles = await this.getPossibleStatuses();
|
||||
|
||||
return allRoles?.[0];
|
||||
}
|
||||
|
||||
setStatusForRole(role, status) {
|
||||
status.timestamp = Date.now();
|
||||
const matchingIndex = this.statusRoleValues.findIndex(x => x.role === role);
|
||||
this.statusRoleValues[matchingIndex].status = status;
|
||||
this.emit('statusChange', {
|
||||
role,
|
||||
status
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line require-await
|
||||
async getPollQuestion() {
|
||||
if (this.pollQuestion) {
|
||||
return this.pollQuestion;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
setPollQuestion(pollQuestion) {
|
||||
if (!pollQuestion) {
|
||||
// If the poll question is undefined, set it to a blank string.
|
||||
// This behavior better reflects how other telemetry systems
|
||||
// deal with undefined poll questions.
|
||||
pollQuestion = '';
|
||||
}
|
||||
|
||||
this.pollQuestion = {
|
||||
question: pollQuestion,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
this.emit("pollQuestionChange", this.pollQuestion);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getPossibleStatuses() {
|
||||
return Promise.resolve(STATUSES);
|
||||
}
|
||||
|
||||
_login() {
|
||||
const id = uuid();
|
||||
|
||||
// for testing purposes, this will skip the form, this wouldn't be used in
|
||||
// a normal authentication process
|
||||
if (this.autoLoginUser) {
|
||||
this.user = new this.ExampleUser(id, this.autoLoginUser, ['test-role-1', 'test-role-2', 'test-role-3', 'test-role-4']);
|
||||
this.loggedIn = true;
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const formStructure = {
|
||||
title: "Login",
|
||||
sections: [
|
||||
{
|
||||
rows: [
|
||||
{
|
||||
key: "username",
|
||||
control: "textfield",
|
||||
name: "Username",
|
||||
pattern: "\\S+",
|
||||
required: true,
|
||||
cssClass: "l-input-lg",
|
||||
value: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
buttons: {
|
||||
submit: {
|
||||
label: 'Login'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return this.openmct.forms.showForm(formStructure).then(
|
||||
(info) => {
|
||||
|
@ -21,17 +21,17 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import ExampleUserProvider from './ExampleUserProvider';
|
||||
const AUTO_LOGIN_USER = 'guest';
|
||||
const STATUS_ROLES = ['test-role-1', 'test-role-2', 'test-role-3'];
|
||||
|
||||
export default function ExampleUserPlugin(
|
||||
{ autoLoginUser, defaultStatusRole } = {
|
||||
autoLoginUser: 'guest',
|
||||
defaultStatusRole: 'test-role'
|
||||
}
|
||||
) {
|
||||
return function install(openmct) {
|
||||
const userProvider = new ExampleUserProvider(openmct, {
|
||||
defaultStatusRole
|
||||
});
|
||||
export default function ExampleUserPlugin({autoLoginUser, statusRoles} = {
|
||||
autoLoginUser: AUTO_LOGIN_USER,
|
||||
statusRoles: STATUS_ROLES
|
||||
}) {
|
||||
return function install(openmct) {
|
||||
const userProvider = new ExampleUserProvider(openmct, {
|
||||
statusRoles
|
||||
});
|
||||
|
||||
if (autoLoginUser !== undefined) {
|
||||
userProvider.autoLogin(autoLoginUser);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Overlay from './Overlay';
|
||||
import Dialog from './Dialog';
|
||||
import ProgressDialog from './ProgressDialog';
|
||||
import Selection from './Selection';
|
||||
|
||||
/**
|
||||
* The OverlayAPI is responsible for pre-pending templates to
|
||||
@ -127,9 +128,15 @@ class OverlayAPI {
|
||||
let progressDialog = new ProgressDialog(options);
|
||||
|
||||
this.showOverlay(progressDialog);
|
||||
|
||||
return progressDialog;
|
||||
}
|
||||
|
||||
selection(options) {
|
||||
let selection = new Selection(options);
|
||||
this.showOverlay(selection);
|
||||
|
||||
return selection;
|
||||
}
|
||||
}
|
||||
|
||||
export default OverlayAPI;
|
||||
|
38
src/api/overlays/Selection.js
Normal file
38
src/api/overlays/Selection.js
Normal file
@ -0,0 +1,38 @@
|
||||
import SelectionComponent from './components/SelectionComponent.vue';
|
||||
import Overlay from './Overlay';
|
||||
import Vue from 'vue';
|
||||
|
||||
class Selection extends Overlay {
|
||||
constructor({iconClass, title, message, selectionOptions, onChange, currentSelection, ...options}) {
|
||||
|
||||
let component = new Vue({
|
||||
components: {
|
||||
SelectionComponent: SelectionComponent
|
||||
},
|
||||
provide: {
|
||||
iconClass,
|
||||
title,
|
||||
message,
|
||||
selectionOptions,
|
||||
onChange,
|
||||
currentSelection
|
||||
},
|
||||
template: '<selection-component></selection-component>'
|
||||
}).$mount();
|
||||
|
||||
super({
|
||||
element: component.$el,
|
||||
size: 'fit',
|
||||
dismissable: false,
|
||||
onChange,
|
||||
currentSelection,
|
||||
...options
|
||||
});
|
||||
|
||||
this.once('destroy', () => {
|
||||
component.$destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default Selection;
|
45
src/api/overlays/components/SelectionComponent.vue
Normal file
45
src/api/overlays/components/SelectionComponent.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div class="c-message">
|
||||
<!--Uses flex-row -->
|
||||
<div
|
||||
class="c-message__icon"
|
||||
:class="['u-icon-bg-color-' + iconClass]"
|
||||
></div>
|
||||
<div class="c-message__text">
|
||||
<!-- Uses flex-column -->
|
||||
<div
|
||||
v-if="title"
|
||||
class="c-message__title"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="message"
|
||||
class="c-message__action-text"
|
||||
>
|
||||
{{ message }}
|
||||
</div>
|
||||
<select
|
||||
@change="onChange"
|
||||
>
|
||||
<option
|
||||
v-for="option in selectionOptions"
|
||||
:key="option.key"
|
||||
:value="option.key"
|
||||
:selected="option.key===currentSelection"
|
||||
>
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['iconClass', 'title', 'message', 'selectionOptions', 'currentSelection', 'onChange']
|
||||
};
|
||||
</script>
|
52
src/api/user/RoleChannel.js
Normal file
52
src/api/user/RoleChannel.js
Normal file
@ -0,0 +1,52 @@
|
||||
import { BROADCAST_CHANNEL_NAME } from './constants';
|
||||
|
||||
class RoleChannel {
|
||||
constructor(openmct, channelName = BROADCAST_CHANNEL_NAME) {
|
||||
this.openmct = openmct;
|
||||
this.channelName = channelName;
|
||||
this.roleChannel = undefined;
|
||||
}
|
||||
|
||||
createRoleChannel() {
|
||||
this.roleChannel = new BroadcastChannel(this.channelName);
|
||||
}
|
||||
subscribeToRole(cb) {
|
||||
this.roleChannel.onmessage = (event => {
|
||||
const role = event.data;
|
||||
this.openmct.user.setActiveRole(role);
|
||||
if (cb) {
|
||||
cb(role);
|
||||
}
|
||||
});
|
||||
}
|
||||
unsubscribeToRole() {
|
||||
this.roleChannel.close();
|
||||
}
|
||||
reconnect() {
|
||||
this.roleChannel.close();
|
||||
this.createRoleChannel();
|
||||
}
|
||||
|
||||
broadcastNewRole(role) {
|
||||
if (!this.roleChannel.name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
this.roleChannel.postMessage(role);
|
||||
} catch (e) {
|
||||
this.reconnect();
|
||||
this.broadcastNewRole(role);
|
||||
/** FIXME: there doesn't seem to be a reliable way to test for open/closed
|
||||
* status of a broadcast channel; channel.name exists even after the
|
||||
* channel is closed. Failure to update the subscribed tabs, should
|
||||
* not block the focused tab's selection and so it is caught here.
|
||||
* An error will often be thrown if the dialog remains open during HMR.
|
||||
**/
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default RoleChannel;
|
||||
|
38
src/api/user/SessionPersistance.js
Normal file
38
src/api/user/SessionPersistance.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2023, 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 { SESSION_STORAGE_KEY } from './constants';
|
||||
|
||||
class SessionPersistance {
|
||||
getActiveRole() {
|
||||
return sessionStorage.getItem(SESSION_STORAGE_KEY);
|
||||
}
|
||||
setActiveRole(role) {
|
||||
return sessionStorage.setItem(SESSION_STORAGE_KEY, role);
|
||||
}
|
||||
clearActiveRole() {
|
||||
return sessionStorage.removeItem(SESSION_STORAGE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
export default new SessionPersistance();
|
||||
|
@ -19,259 +19,249 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import EventEmitter from 'EventEmitter';
|
||||
import EventEmitter from "EventEmitter";
|
||||
|
||||
export default class StatusAPI extends EventEmitter {
|
||||
#userAPI;
|
||||
#openmct;
|
||||
#userAPI;
|
||||
#openmct;
|
||||
|
||||
constructor(userAPI, openmct) {
|
||||
super();
|
||||
this.#userAPI = userAPI;
|
||||
this.#openmct = openmct;
|
||||
constructor(userAPI, openmct) {
|
||||
super();
|
||||
this.#userAPI = userAPI;
|
||||
this.#openmct = openmct;
|
||||
|
||||
this.onProviderStatusChange = this.onProviderStatusChange.bind(this);
|
||||
this.onProviderPollQuestionChange = this.onProviderPollQuestionChange.bind(this);
|
||||
this.listenToStatusEvents = this.listenToStatusEvents.bind(this);
|
||||
this.onProviderStatusChange = this.onProviderStatusChange.bind(this);
|
||||
this.onProviderPollQuestionChange = this.onProviderPollQuestionChange.bind(this);
|
||||
this.listenToStatusEvents = this.listenToStatusEvents.bind(this);
|
||||
|
||||
this.#openmct.once('destroy', () => {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
this.#openmct.once('destroy', () => {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (typeof provider?.off === 'function') {
|
||||
provider.off('statusChange', this.onProviderStatusChange);
|
||||
provider.off('pollQuestionChange', this.onProviderPollQuestionChange);
|
||||
}
|
||||
});
|
||||
if (typeof provider?.off === 'function') {
|
||||
provider.off('statusChange', this.onProviderStatusChange);
|
||||
provider.off('pollQuestionChange', this.onProviderPollQuestionChange);
|
||||
}
|
||||
});
|
||||
|
||||
this.#userAPI.on('providerAdded', this.listenToStatusEvents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the currently defined operator status poll question. When presented with a status poll question, all operators will reply with their current status.
|
||||
* @returns {Promise<PollQuestion>}
|
||||
*/
|
||||
getPollQuestion() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (provider.getPollQuestion) {
|
||||
return provider.getPollQuestion();
|
||||
} else {
|
||||
this.#userAPI.error('User provider does not support polling questions');
|
||||
this.#userAPI.on('providerAdded', this.listenToStatusEvents);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a poll question for operators to respond to. When presented with a status poll question, all operators will reply with their current status.
|
||||
* @param {String} questionText - The text of the question
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
async setPollQuestion(questionText) {
|
||||
const canSetPollQuestion = await this.canSetPollQuestion();
|
||||
/**
|
||||
* Fetch the currently defined operator status poll question. When presented with a status poll question, all operators will reply with their current status.
|
||||
* @returns {Promise<PollQuestion>}
|
||||
*/
|
||||
getPollQuestion() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (canSetPollQuestion) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
const result = await provider.setPollQuestion(questionText);
|
||||
|
||||
try {
|
||||
await this.resetAllStatuses();
|
||||
} catch (error) {
|
||||
console.warn('Poll question set but unable to clear operator statuses.');
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
this.#userAPI.error('User provider does not support setting polling question');
|
||||
if (provider.getPollQuestion) {
|
||||
return provider.getPollQuestion();
|
||||
} else {
|
||||
this.#userAPI.error("User provider does not support polling questions");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the currently logged in user set the operator status poll question.
|
||||
* @returns {Promise<Boolean>}
|
||||
*/
|
||||
canSetPollQuestion() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
/**
|
||||
* Set a poll question for operators to respond to. When presented with a status poll question, all operators will reply with their current status.
|
||||
* @param {String} questionText - The text of the question
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
async setPollQuestion(questionText) {
|
||||
const canSetPollQuestion = await this.canSetPollQuestion();
|
||||
|
||||
if (provider.canSetPollQuestion) {
|
||||
return provider.canSetPollQuestion();
|
||||
} else {
|
||||
return Promise.resolve(false);
|
||||
if (canSetPollQuestion) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
const result = await provider.setPollQuestion(questionText);
|
||||
|
||||
try {
|
||||
await this.resetAllStatuses();
|
||||
} catch (error) {
|
||||
console.warn("Poll question set but unable to clear operator statuses.");
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
this.#userAPI.error("User provider does not support setting polling question");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Array<Status>>} the complete list of possible states that an operator can reply to a poll question with.
|
||||
*/
|
||||
async getPossibleStatuses() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
/**
|
||||
* Can the currently logged in user set the operator status poll question.
|
||||
* @returns {Promise<Boolean>}
|
||||
*/
|
||||
canSetPollQuestion() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (provider.getPossibleStatuses) {
|
||||
const possibleStatuses = (await provider.getPossibleStatuses()) || [];
|
||||
|
||||
return possibleStatuses.map((status) => status);
|
||||
} else {
|
||||
this.#userAPI.error('User provider cannot provide statuses');
|
||||
if (provider.canSetPollQuestion) {
|
||||
return provider.canSetPollQuestion();
|
||||
} else {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role The role to fetch the current status for.
|
||||
* @returns {Promise<Status>} the current status of the provided role
|
||||
*/
|
||||
async getStatusForRole(role) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
/**
|
||||
* @returns {Promise<Array<Status>>} the complete list of possible states that an operator can reply to a poll question with.
|
||||
*/
|
||||
async getPossibleStatuses() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (provider.getStatusForRole) {
|
||||
const status = await provider.getStatusForRole(role);
|
||||
if (provider.getPossibleStatuses) {
|
||||
const possibleStatuses = await provider.getPossibleStatuses() || [];
|
||||
|
||||
return status;
|
||||
} else {
|
||||
this.#userAPI.error('User provider does not support role status');
|
||||
return possibleStatuses.map(status => status);
|
||||
} else {
|
||||
this.#userAPI.error("User provider cannot provide statuses");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<Boolean>} true if the configured UserProvider can provide status for the given role
|
||||
* @see StatusUserProvider
|
||||
*/
|
||||
canProvideStatusForRole(role) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role The role to fetch the current status for.
|
||||
* @returns {Promise<Status>} the current status of the provided role
|
||||
*/
|
||||
async getStatusForRole(role) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (provider.canProvideStatusForRole) {
|
||||
return provider.canProvideStatusForRole(role);
|
||||
} else {
|
||||
return false;
|
||||
if (provider.getStatusForRole) {
|
||||
const status = await provider.getStatusForRole(role);
|
||||
|
||||
return status;
|
||||
} else {
|
||||
this.#userAPI.error("User provider does not support role status");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role The role to set the status for.
|
||||
* @param {Status} status The status to set for the provided role
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
setStatusForRole(role, status) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<Boolean>} true if the configured UserProvider can provide status for the given role
|
||||
* @see StatusUserProvider
|
||||
*/
|
||||
canProvideStatusForRole(role) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (provider.setStatusForRole) {
|
||||
return provider.setStatusForRole(role, status);
|
||||
} else {
|
||||
this.#userAPI.error('User provider does not support setting role status');
|
||||
if (provider.canProvideStatusForRole) {
|
||||
return Promise.resolve(provider.canProvideStatusForRole(role));
|
||||
} else {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the status of the provided role back to its default status.
|
||||
* @param {import("./UserAPI").Role} role The role to set the status for.
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
async resetStatusForRole(role) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
const defaultStatus = await this.getDefaultStatusForRole(role);
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role The role to set the status for.
|
||||
* @param {Status} status The status to set for the provided role
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
setStatusForRole(status) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (provider.setStatusForRole) {
|
||||
return provider.setStatusForRole(role, defaultStatus);
|
||||
} else {
|
||||
this.#userAPI.error('User provider does not support resetting role status');
|
||||
if (provider.setStatusForRole) {
|
||||
const activeRole = this.#userAPI.getActiveRole();
|
||||
if (!provider.canProvideStatusForRole(activeRole)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return provider.setStatusForRole(activeRole, status);
|
||||
} else {
|
||||
this.#userAPI.error("User provider does not support setting role status");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the status of all operators to their default status
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
async resetAllStatuses() {
|
||||
const allStatusRoles = await this.getAllStatusRoles();
|
||||
/**
|
||||
* Resets the status of the provided role back to its default status.
|
||||
* @param {import("./UserAPI").Role} role The role to set the status for.
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
async resetStatusForRole(role) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
const defaultStatus = await this.getDefaultStatusForRole(role);
|
||||
|
||||
return Promise.all(allStatusRoles.map((role) => this.resetStatusForRole(role)));
|
||||
}
|
||||
|
||||
/**
|
||||
* The default status. This is the status that will be used before the user has selected any status.
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<Status>} the default operator status if no other has been set.
|
||||
*/
|
||||
async getDefaultStatusForRole(role) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
const defaultStatus = await provider.getDefaultStatusForRole(role);
|
||||
|
||||
return defaultStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* All possible status roles. A status role is a user role that can provide status. In some systems
|
||||
* this may be all user roles, but there may be cases where some users are not are not polled
|
||||
* for status if they do not have a real-time operational role.
|
||||
*
|
||||
* @returns {Promise<Array<import("./UserAPI").Role>>} the default operator status if no other has been set.
|
||||
*/
|
||||
getAllStatusRoles() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (provider.getAllStatusRoles) {
|
||||
return provider.getAllStatusRoles();
|
||||
} else {
|
||||
this.#userAPI.error('User provider cannot provide all status roles');
|
||||
if (provider.setStatusForRole) {
|
||||
return provider.setStatusForRole(role, defaultStatus);
|
||||
} else {
|
||||
this.#userAPI.error("User provider does not support resetting role status");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The status role of the current user. A user may have multiple roles, but will only have one role
|
||||
* that provides status at any time.
|
||||
* @returns {Promise<import("./UserAPI").Role>} the role for which the current user can provide status.
|
||||
*/
|
||||
getStatusRoleForCurrentUser() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
/**
|
||||
* Resets the status of all operators to their default status
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
async resetAllStatuses() {
|
||||
const allStatusRoles = await this.getAllStatusRoles();
|
||||
|
||||
if (provider.getStatusRoleForCurrentUser) {
|
||||
return provider.getStatusRoleForCurrentUser();
|
||||
} else {
|
||||
this.#userAPI.error('User provider cannot provide role status for this user');
|
||||
return Promise.all(allStatusRoles.map(role => this.resetStatusForRole(role)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Boolean>} true if the configured UserProvider can provide status for the currently logged in user, false otherwise.
|
||||
* @see StatusUserProvider
|
||||
*/
|
||||
async canProvideStatusForCurrentUser() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
/**
|
||||
* The default status. This is the status that will be used before the user has selected any status.
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<Status>} the default operator status if no other has been set.
|
||||
*/
|
||||
async getDefaultStatusForRole(role) {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
const defaultStatus = await provider.getDefaultStatusForRole(role);
|
||||
|
||||
if (provider.getStatusRoleForCurrentUser) {
|
||||
const activeStatusRole = await this.#userAPI.getProvider().getStatusRoleForCurrentUser();
|
||||
const canProvideStatus = await this.canProvideStatusForRole(activeStatusRole);
|
||||
|
||||
return canProvideStatus;
|
||||
} else {
|
||||
return false;
|
||||
return defaultStatus;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private internal function that cannot be made #private because it needs to be registered as a callback to the user provider
|
||||
* @private
|
||||
*/
|
||||
listenToStatusEvents(provider) {
|
||||
if (typeof provider.on === 'function') {
|
||||
provider.on('statusChange', this.onProviderStatusChange);
|
||||
provider.on('pollQuestionChange', this.onProviderPollQuestionChange);
|
||||
/**
|
||||
* All possible status roles. A status role is a user role that can provide status. In some systems
|
||||
* this may be all user roles, but there may be cases where some users are not are not polled
|
||||
* for status if they do not have a real-time operational role.
|
||||
*
|
||||
* @returns {Promise<Array<import("./UserAPI").Role>>} the default operator status if no other has been set.
|
||||
*/
|
||||
getAllStatusRoles() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
if (provider.getAllStatusRoles) {
|
||||
return provider.getAllStatusRoles();
|
||||
} else {
|
||||
this.#userAPI.error("User provider cannot provide all status roles");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onProviderStatusChange(newStatus) {
|
||||
this.emit('statusChange', newStatus);
|
||||
}
|
||||
/**
|
||||
* @returns {Promise<Boolean>} true if the configured UserProvider can provide status for the currently logged in user, false otherwise.
|
||||
* @see StatusUserProvider
|
||||
*/
|
||||
async canProvideStatusForCurrentUser() {
|
||||
const provider = this.#userAPI.getProvider();
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onProviderPollQuestionChange(pollQuestion) {
|
||||
this.emit('pollQuestionChange', pollQuestion);
|
||||
}
|
||||
if (provider.getStatusRoleForCurrentUser) {
|
||||
const activeStatusRole = await this.#userAPI.getActiveRole();
|
||||
const canProvideStatus = await this.canProvideStatusForRole(activeStatusRole);
|
||||
|
||||
return canProvideStatus;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private internal function that cannot be made #private because it needs to be registered as a callback to the user provider
|
||||
* @private
|
||||
*/
|
||||
listenToStatusEvents(provider) {
|
||||
if (typeof provider.on === 'function') {
|
||||
provider.on('statusChange', this.onProviderStatusChange);
|
||||
provider.on('pollQuestionChange', this.onProviderPollQuestionChange);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onProviderStatusChange(newStatus) {
|
||||
this.emit('statusChange', newStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onProviderPollQuestionChange(pollQuestion) {
|
||||
this.emit('pollQuestionChange', pollQuestion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -293,4 +283,4 @@ export default class StatusAPI extends EventEmitter {
|
||||
* @property {String} key - A unique identifier for this status
|
||||
* @property {String} label - A human readable label for this status
|
||||
* @property {Number} timestamp - The time that the status was set.
|
||||
*/
|
||||
*/
|
@ -22,60 +22,59 @@
|
||||
import UserProvider from './UserProvider';
|
||||
|
||||
export default class StatusUserProvider extends UserProvider {
|
||||
/**
|
||||
* @param {('statusChange'|'pollQuestionChange')} event the name of the event to listen to
|
||||
* @param {Function} callback a function to invoke when this event occurs
|
||||
*/
|
||||
on(event, callback) {}
|
||||
/**
|
||||
* @param {('statusChange'|'pollQuestionChange')} event the name of the event to stop listen to
|
||||
* @param {Function} callback the callback function used to register the listener
|
||||
*/
|
||||
off(event, callback) {}
|
||||
/**
|
||||
* @returns {import("./StatusAPI").PollQuestion} the current status poll question
|
||||
*/
|
||||
async getPollQuestion() {}
|
||||
/**
|
||||
* @param {import("./StatusAPI").PollQuestion} pollQuestion a new poll question to set
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false
|
||||
*/
|
||||
async setPollQuestion(pollQuestion) {}
|
||||
/**
|
||||
* @returns {Promise<Boolean>} true if the current user can set the poll question, otherwise false
|
||||
*/
|
||||
async canSetPollQuestion() {}
|
||||
/**
|
||||
* @returns {Promise<Array<import("./StatusAPI").Status>>} a list of the possible statuses that an operator can be in
|
||||
*/
|
||||
async getPossibleStatuses() {}
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<import("./StatusAPI").Status}
|
||||
*/
|
||||
async getStatusForRole(role) {}
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<import("./StatusAPI").Status}
|
||||
*/
|
||||
async getDefaultStatusForRole(role) {}
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @param {*} status
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
async setStatusForRole(role, status) {}
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<Boolean} true if the user provider can provide status for the given role
|
||||
*/
|
||||
async canProvideStatusForRole(role) {}
|
||||
/**
|
||||
* @returns {Promise<Array<import("./UserAPI").Role>>} a list of all available status roles, if user permissions allow it.
|
||||
*/
|
||||
async getAllStatusRoles() {}
|
||||
/**
|
||||
* @returns {Promise<import("./UserAPI").Role>} the active status role for the currently logged in user
|
||||
*/
|
||||
async getStatusRoleForCurrentUser() {}
|
||||
/**
|
||||
* @param {('statusChange'|'pollQuestionChange')} event the name of the event to listen to
|
||||
* @param {Function} callback a function to invoke when this event occurs
|
||||
*/
|
||||
on(event, callback) {}
|
||||
/**
|
||||
* @param {('statusChange'|'pollQuestionChange')} event the name of the event to stop listen to
|
||||
* @param {Function} callback the callback function used to register the listener
|
||||
*/
|
||||
off(event, callback) {}
|
||||
/**
|
||||
* @returns {import("./StatusAPI").PollQuestion} the current status poll question
|
||||
*/
|
||||
async getPollQuestion() {}
|
||||
/**
|
||||
* @param {import("./StatusAPI").PollQuestion} pollQuestion a new poll question to set
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false
|
||||
*/
|
||||
async setPollQuestion(pollQuestion) {}
|
||||
/**
|
||||
* @returns {Promise<Boolean>} true if the current user can set the poll question, otherwise false
|
||||
*/
|
||||
async canSetPollQuestion() {}
|
||||
/**
|
||||
* @returns {Promise<Array<import("./StatusAPI").Status>>} a list of the possible statuses that an operator can be in
|
||||
*/
|
||||
async getPossibleStatuses() {}
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<import("./StatusAPI").Status}
|
||||
*/
|
||||
async getStatusForRole(role) {}
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<import("./StatusAPI").Status}
|
||||
*/
|
||||
async getDefaultStatusForRole(role) {}
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @param {*} status
|
||||
* @returns {Promise<Boolean>} true if operation was successful, otherwise false.
|
||||
*/
|
||||
async setStatusForRole(role, status) {}
|
||||
/**
|
||||
* @param {import("./UserAPI").Role} role
|
||||
* @returns {Promise<Boolean} true if the user provider can provide status for the given role
|
||||
*/
|
||||
async canProvideStatusForRole(role) {}
|
||||
/**
|
||||
* @returns {Promise<Array<import("./UserAPI").Role>>} a list of all available status roles, if user permissions allow it.
|
||||
*/
|
||||
async getAllStatusRoles() {}
|
||||
/**
|
||||
* @returns {Promise<import("./UserAPI").Role>} the active status role for the currently logged in user
|
||||
*/
|
||||
}
|
||||
|
@ -21,125 +21,173 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import EventEmitter from 'EventEmitter';
|
||||
import { MULTIPLE_PROVIDER_ERROR, NO_PROVIDER_ERROR } from './constants';
|
||||
import {
|
||||
MULTIPLE_PROVIDER_ERROR,
|
||||
NO_PROVIDER_ERROR
|
||||
} from './constants';
|
||||
import StatusAPI from './StatusAPI';
|
||||
import User from './User';
|
||||
import SessionPersistance from './SessionPersistance';
|
||||
|
||||
class UserAPI extends EventEmitter {
|
||||
/**
|
||||
* @param {OpenMCT} openmct
|
||||
* @param {UserAPIConfiguration} config
|
||||
*/
|
||||
constructor(openmct, config) {
|
||||
super();
|
||||
/**
|
||||
* @param {OpenMCT} openmct
|
||||
* @param {UserAPIConfiguration} config
|
||||
*/
|
||||
constructor(openmct, config) {
|
||||
super();
|
||||
|
||||
this._openmct = openmct;
|
||||
this._provider = undefined;
|
||||
this._openmct = openmct;
|
||||
this._provider = undefined;
|
||||
|
||||
this.User = User;
|
||||
this.status = new StatusAPI(this, openmct, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user provider for the user API. This allows you
|
||||
* to specifiy ONE user provider to be used with Open MCT.
|
||||
* @method setProvider
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @param {module:openmct.UserAPI~UserProvider} provider the new
|
||||
* user provider
|
||||
*/
|
||||
setProvider(provider) {
|
||||
if (this.hasProvider()) {
|
||||
this.error(MULTIPLE_PROVIDER_ERROR);
|
||||
this.User = User;
|
||||
this.status = new StatusAPI(this, openmct, config);
|
||||
}
|
||||
|
||||
this._provider = provider;
|
||||
this.emit('providerAdded', this._provider);
|
||||
}
|
||||
/**
|
||||
* Set the user provider for the user API. This allows you
|
||||
* to specifiy ONE user provider to be used with Open MCT.
|
||||
* @method setProvider
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @param {module:openmct.UserAPI~UserProvider} provider the new
|
||||
* user provider
|
||||
*/
|
||||
setProvider(provider) {
|
||||
if (this.hasProvider()) {
|
||||
this.error(MULTIPLE_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
getProvider() {
|
||||
return this._provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the user provider has been set.
|
||||
*
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @returns {boolean} true if the user provider exists
|
||||
*/
|
||||
hasProvider() {
|
||||
return this._provider !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user provider is set, it will return a copy of a user object from
|
||||
* the provider. If the user is not logged in, it will return undefined;
|
||||
*
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @returns {Function|Promise} user provider 'getCurrentUser' method
|
||||
* @throws Will throw an error if no user provider is set
|
||||
*/
|
||||
getCurrentUser() {
|
||||
if (!this.hasProvider()) {
|
||||
return Promise.resolve(undefined);
|
||||
} else {
|
||||
return this._provider.getCurrentUser();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user provider is set, it will return the user provider's
|
||||
* 'isLoggedIn' method
|
||||
*
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @returns {Function|Boolean} user provider 'isLoggedIn' method
|
||||
* @throws Will throw an error if no user provider is set
|
||||
*/
|
||||
isLoggedIn() {
|
||||
if (!this.hasProvider()) {
|
||||
return false;
|
||||
this._provider = provider;
|
||||
this.emit('providerAdded', this._provider);
|
||||
}
|
||||
|
||||
return this._provider.isLoggedIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user provider is set, it will return a call to it's
|
||||
* 'hasRole' method
|
||||
*
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @returns {Function|Boolean} user provider 'isLoggedIn' method
|
||||
* @param {string} roleId id of role to check for
|
||||
* @throws Will throw an error if no user provider is set
|
||||
*/
|
||||
hasRole(roleId) {
|
||||
this.noProviderCheck();
|
||||
|
||||
return this._provider.hasRole(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a provider is set and if not, will throw error
|
||||
*
|
||||
* @private
|
||||
* @throws Will throw an error if no user provider is set
|
||||
*/
|
||||
noProviderCheck() {
|
||||
if (!this.hasProvider()) {
|
||||
this.error(NO_PROVIDER_ERROR);
|
||||
getProvider() {
|
||||
return this._provider;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for throwing errors
|
||||
*
|
||||
* @private
|
||||
* @param {string} error description of error
|
||||
* @throws Will throw error passed in
|
||||
*/
|
||||
error(error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
/**
|
||||
* Return true if the user provider has been set.
|
||||
*
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @returns {boolean} true if the user provider exists
|
||||
*/
|
||||
hasProvider() {
|
||||
return this._provider !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user provider is set, it will return a copy of a user object from
|
||||
* the provider. If the user is not logged in, it will return undefined;
|
||||
*
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @returns {Function|Promise} user provider 'getCurrentUser' method
|
||||
* @throws Will throw an error if no user provider is set
|
||||
*/
|
||||
getCurrentUser() {
|
||||
if (!this.hasProvider()) {
|
||||
return Promise.resolve(undefined);
|
||||
} else {
|
||||
return this._provider.getCurrentUser();
|
||||
}
|
||||
}
|
||||
|
||||
getPossibleRoles() {
|
||||
if (!this.hasProvider()) {
|
||||
return Promise.resolve(undefined);
|
||||
} else {
|
||||
return this._provider.getPossibleRoles();
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* If a user provider is set, it will return the active role Id
|
||||
* @returns object
|
||||
*/
|
||||
getActiveRole() {
|
||||
if (!this.hasProvider()) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// get from session storage
|
||||
const sessionStorageValue = SessionPersistance.getActiveRole();
|
||||
if (sessionStorageValue === 'undefined' || sessionStorageValue === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return sessionStorageValue;
|
||||
}
|
||||
setActiveRole(role) {
|
||||
SessionPersistance.setActiveRole(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will return if a role can provide a operator status response
|
||||
* @memberof module:openmct.UserApi#
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
canProvideStatusForRole() {
|
||||
if (!this || !this.hasProvider()) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const activeRole = this.getActiveRole();
|
||||
|
||||
return this._provider.canProvideStatusForRole?.(activeRole);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user provider is set, it will return the user provider's
|
||||
* 'isLoggedIn' method
|
||||
*
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @returns {Function|Boolean} user provider 'isLoggedIn' method
|
||||
* @throws Will throw an error if no user provider is set
|
||||
*/
|
||||
isLoggedIn() {
|
||||
if (!this.hasProvider()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this._provider.isLoggedIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user provider is set, it will return a call to it's
|
||||
* 'hasRole' method
|
||||
*
|
||||
* @memberof module:openmct.UserAPI#
|
||||
* @returns {Function|Boolean} user provider 'isLoggedIn' method
|
||||
* @param {string} roleId id of role to check for
|
||||
* @throws Will throw an error if no user provider is set
|
||||
*/
|
||||
hasRole(roleId) {
|
||||
this.noProviderCheck();
|
||||
|
||||
return this._provider.hasRole(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a provider is set and if not, will throw error
|
||||
*
|
||||
* @private
|
||||
* @throws Will throw an error if no user provider is set
|
||||
*/
|
||||
noProviderCheck() {
|
||||
if (!this.hasProvider()) {
|
||||
this.error(NO_PROVIDER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for throwing errors
|
||||
*
|
||||
* @private
|
||||
* @param {string} error description of error
|
||||
* @throws Will throw error passed in
|
||||
*/
|
||||
error(error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
export default UserAPI;
|
||||
@ -159,4 +207,4 @@ export default UserAPI;
|
||||
* @property {String} statusClass The class to apply to the indicator when this status is active eg. "s-status-error"
|
||||
* @property {String} statusBgColor The background color to apply in the status summary section of the poll question popup for this status eg."#9900cc"
|
||||
* @property {String} statusFgColor The foreground color to apply in the status summary section of the poll question popup for this status eg. "#fff"
|
||||
*/
|
||||
*/
|
@ -22,3 +22,6 @@
|
||||
|
||||
export const MULTIPLE_PROVIDER_ERROR = 'Only one user provider may be set at a time.';
|
||||
export const NO_PROVIDER_ERROR = 'No user provider has been set.';
|
||||
|
||||
export const SESSION_STORAGE_KEY = 'USER_ROLE';
|
||||
export const BROADCAST_CHANNEL_NAME = 'USER_ROLE';
|
||||
|
@ -21,158 +21,169 @@
|
||||
-->
|
||||
<template>
|
||||
<div
|
||||
:style="position"
|
||||
class="c-status-poll-panel c-status-poll-panel--operator"
|
||||
@click.stop="noop"
|
||||
:style="position"
|
||||
class="c-status-poll-panel c-status-poll-panel--operator"
|
||||
@click.stop="noop"
|
||||
>
|
||||
<div class="c-status-poll-panel__section c-status-poll-panel__top">
|
||||
<div class="c-status-poll-panel__title">Status Poll</div>
|
||||
<div class="c-status-poll-panel__user-role icon-person">{{ role }}</div>
|
||||
<div class="c-status-poll-panel__updated">{{ pollQuestionUpdated }}</div>
|
||||
</div>
|
||||
|
||||
<div class="c-status-poll-panel__section c-status-poll-panel__poll-question">
|
||||
{{ currentPollQuestion }}
|
||||
</div>
|
||||
|
||||
<div class="c-status-poll-panel__section c-status-poll-panel__bottom">
|
||||
<div class="c-status-poll-panel__set-status-label">My status:</div>
|
||||
<select v-model="selectedStatus" name="setStatus" @change="changeStatus">
|
||||
<option v-for="status in allStatuses" :key="status.key" :value="status.key">
|
||||
{{ status.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="c-status-poll-panel__section c-status-poll-panel__top">
|
||||
<div
|
||||
class="c-status-poll-panel__title"
|
||||
>Status Poll</div>
|
||||
<div class="c-status-poll-panel__user-role icon-person">{{ role }}</div>
|
||||
<div class="c-status-poll-panel__updated">{{ pollQuestionUpdated }}</div>
|
||||
</div>
|
||||
|
||||
<div class="c-status-poll-panel__section c-status-poll-panel__poll-question">
|
||||
{{ currentPollQuestion }}
|
||||
</div>
|
||||
|
||||
<div class="c-status-poll-panel__section c-status-poll-panel__bottom">
|
||||
<div class="c-status-poll-panel__set-status-label">My status:</div>
|
||||
<select
|
||||
v-model="selectedStatus"
|
||||
name="setStatus"
|
||||
@change="changeStatus"
|
||||
>
|
||||
<option
|
||||
v-for="status in allStatuses"
|
||||
:key="status.key"
|
||||
:value="status.key"
|
||||
>
|
||||
{{ status.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const DEFAULT_POLL_QUESTION = 'NO POLL QUESTION';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'indicator', 'configuration'],
|
||||
props: {
|
||||
positionX: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
positionY: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
allRoles: [],
|
||||
role: '--',
|
||||
pollQuestionUpdated: '--',
|
||||
currentPollQuestion: DEFAULT_POLL_QUESTION,
|
||||
selectedStatus: undefined,
|
||||
allStatuses: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
position() {
|
||||
return {
|
||||
position: 'absolute',
|
||||
left: `${this.positionX}px`,
|
||||
top: `${this.positionY}px`
|
||||
};
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.user.status.off('statusChange', this.setStatus);
|
||||
this.openmct.user.status.off('pollQuestionChange', this.setPollQuestion);
|
||||
},
|
||||
async mounted() {
|
||||
this.unsubscribe = [];
|
||||
await this.fetchUser();
|
||||
await this.findFirstApplicableRole();
|
||||
this.fetchPossibleStatusesForUser();
|
||||
this.fetchCurrentPoll();
|
||||
this.fetchMyStatus();
|
||||
this.subscribeToMyStatus();
|
||||
this.subscribeToPollQuestion();
|
||||
},
|
||||
methods: {
|
||||
async findFirstApplicableRole() {
|
||||
this.role = await this.openmct.user.status.getStatusRoleForCurrentUser();
|
||||
},
|
||||
async fetchUser() {
|
||||
this.user = await this.openmct.user.getCurrentUser();
|
||||
},
|
||||
async fetchCurrentPoll() {
|
||||
const pollQuestion = await this.openmct.user.status.getPollQuestion();
|
||||
if (pollQuestion !== undefined) {
|
||||
this.setPollQuestion(pollQuestion);
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const DEFAULT_POLL_QUESTION = 'NO POLL QUESTION';
|
||||
export default {
|
||||
inject: ['openmct', 'indicator', 'configuration'],
|
||||
props: {
|
||||
positionX: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
positionY: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
allRoles: [],
|
||||
role: '--',
|
||||
pollQuestionUpdated: '--',
|
||||
currentPollQuestion: DEFAULT_POLL_QUESTION,
|
||||
selectedStatus: undefined,
|
||||
allStatuses: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
position() {
|
||||
return {
|
||||
position: 'absolute',
|
||||
left: `${this.positionX}px`,
|
||||
top: `${this.positionY}px`
|
||||
};
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.user.status.off('statusChange', this.setStatus);
|
||||
this.openmct.user.status.off('pollQuestionChange', this.setPollQuestion);
|
||||
},
|
||||
async mounted() {
|
||||
this.unsubscribe = [];
|
||||
await this.fetchUser();
|
||||
this.fetchPossibleStatusesForUser();
|
||||
this.fetchCurrentPoll();
|
||||
await this.fetchMyStatus();
|
||||
this.subscribeToMyStatus();
|
||||
this.subscribeToPollQuestion();
|
||||
},
|
||||
methods: {
|
||||
|
||||
async fetchUser() {
|
||||
this.user = await this.openmct.user.getCurrentUser();
|
||||
},
|
||||
async fetchCurrentPoll() {
|
||||
const pollQuestion = await this.openmct.user.status.getPollQuestion();
|
||||
if (pollQuestion !== undefined) {
|
||||
this.setPollQuestion(pollQuestion);
|
||||
}
|
||||
},
|
||||
async fetchPossibleStatusesForUser() {
|
||||
this.allStatuses = await this.openmct.user.status.getPossibleStatuses();
|
||||
},
|
||||
setPollQuestion(pollQuestion) {
|
||||
this.currentPollQuestion = pollQuestion.question;
|
||||
this.pollQuestionUpdated = new Date(pollQuestion.timestamp).toISOString();
|
||||
|
||||
this.indicator.text(pollQuestion?.question || '');
|
||||
},
|
||||
async fetchMyStatus() {
|
||||
const activeRole = await this.openmct.user.getActiveRole();
|
||||
const status = await this.openmct.user.status.getStatusForRole(activeRole);
|
||||
|
||||
if (status !== undefined) {
|
||||
this.setStatus({status});
|
||||
}
|
||||
},
|
||||
subscribeToMyStatus() {
|
||||
this.openmct.user.status.on('statusChange', this.setStatus);
|
||||
},
|
||||
subscribeToPollQuestion() {
|
||||
this.openmct.user.status.on('pollQuestionChange', this.setPollQuestion);
|
||||
},
|
||||
setStatus({status}) {
|
||||
status = this.applyStyling(status);
|
||||
this.selectedStatus = status.key;
|
||||
this.indicator.iconClass(status.iconClassPoll);
|
||||
this.indicator.statusClass(status.statusClass);
|
||||
if (this.isDefaultStatus(status)) {
|
||||
this.indicator.text(this.currentPollQuestion);
|
||||
} else {
|
||||
this.indicator.text(status.label);
|
||||
}
|
||||
},
|
||||
isDefaultStatus(status) {
|
||||
return status.key === this.allStatuses[0].key;
|
||||
},
|
||||
findStatusByKey(statusKey) {
|
||||
return this.allStatuses.find(possibleMatch => possibleMatch.key === statusKey);
|
||||
},
|
||||
async changeStatus() {
|
||||
if (!this.openmct.user.canProvideStatusForRole()) {
|
||||
this.openmct.notifications.error('Selected role is ineligible to provide operator status');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.selectedStatus !== undefined) {
|
||||
const statusObject = this.findStatusByKey(this.selectedStatus);
|
||||
|
||||
const result = await this.openmct.user.status.setStatusForRole(statusObject);
|
||||
if (result === true) {
|
||||
this.openmct.notifications.info("Successfully set operator status");
|
||||
} else {
|
||||
this.openmct.notifications.error("Unable to set operator status");
|
||||
}
|
||||
}
|
||||
},
|
||||
applyStyling(status) {
|
||||
const stylesForStatus = this.configuration?.statusStyles?.[status.label];
|
||||
|
||||
if (stylesForStatus !== undefined) {
|
||||
return {
|
||||
...status,
|
||||
...stylesForStatus
|
||||
};
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
},
|
||||
noop() {}
|
||||
}
|
||||
},
|
||||
async fetchPossibleStatusesForUser() {
|
||||
this.allStatuses = await this.openmct.user.status.getPossibleStatuses();
|
||||
},
|
||||
setPollQuestion(pollQuestion) {
|
||||
this.currentPollQuestion = pollQuestion.question;
|
||||
this.pollQuestionUpdated = new Date(pollQuestion.timestamp).toISOString();
|
||||
|
||||
this.indicator.text(pollQuestion?.question || '');
|
||||
},
|
||||
async fetchMyStatus() {
|
||||
const activeStatusRole = await this.openmct.user.status.getStatusRoleForCurrentUser();
|
||||
const status = await this.openmct.user.status.getStatusForRole(activeStatusRole);
|
||||
|
||||
if (status !== undefined) {
|
||||
this.setStatus({ status });
|
||||
}
|
||||
},
|
||||
subscribeToMyStatus() {
|
||||
this.openmct.user.status.on('statusChange', this.setStatus);
|
||||
},
|
||||
subscribeToPollQuestion() {
|
||||
this.openmct.user.status.on('pollQuestionChange', this.setPollQuestion);
|
||||
},
|
||||
setStatus({ role, status }) {
|
||||
status = this.applyStyling(status);
|
||||
this.selectedStatus = status.key;
|
||||
this.indicator.iconClass(status.iconClassPoll);
|
||||
this.indicator.statusClass(status.statusClass);
|
||||
if (this.isDefaultStatus(status)) {
|
||||
this.indicator.text(this.currentPollQuestion);
|
||||
} else {
|
||||
this.indicator.text(status.label);
|
||||
}
|
||||
},
|
||||
isDefaultStatus(status) {
|
||||
return status.key === this.allStatuses[0].key;
|
||||
},
|
||||
findStatusByKey(statusKey) {
|
||||
return this.allStatuses.find((possibleMatch) => possibleMatch.key === statusKey);
|
||||
},
|
||||
async changeStatus() {
|
||||
if (this.selectedStatus !== undefined) {
|
||||
const statusObject = this.findStatusByKey(this.selectedStatus);
|
||||
|
||||
const result = await this.openmct.user.status.setStatusForRole(this.role, statusObject);
|
||||
|
||||
if (result === true) {
|
||||
this.openmct.notifications.info('Successfully set operator status');
|
||||
} else {
|
||||
this.openmct.notifications.error('Unable to set operator status');
|
||||
}
|
||||
}
|
||||
},
|
||||
applyStyling(status) {
|
||||
const stylesForStatus = this.configuration?.statusStyles?.[status.label];
|
||||
|
||||
if (stylesForStatus !== undefined) {
|
||||
return {
|
||||
...status,
|
||||
...stylesForStatus
|
||||
};
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
},
|
||||
noop() {}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
};
|
||||
</script>
|
@ -28,22 +28,24 @@ import PollQuestionIndicator from './pollQuestion/PollQuestionIndicator';
|
||||
*/
|
||||
export default function operatorStatusPlugin(configuration) {
|
||||
return function install(openmct) {
|
||||
if (openmct.user.hasProvider()) {
|
||||
openmct.user.status.canProvideStatusForCurrentUser().then((canProvideStatus) => {
|
||||
if (canProvideStatus) {
|
||||
const operatorStatusIndicator = new OperatorStatusIndicator(openmct, configuration);
|
||||
|
||||
operatorStatusIndicator.install();
|
||||
}
|
||||
});
|
||||
if (openmct.user.hasProvider()) {
|
||||
const activeRole = openmct.user.getActiveRole();
|
||||
openmct.user.status.canProvideStatusForRole(activeRole).then(canProvideStatus => {
|
||||
if (canProvideStatus) {
|
||||
const operatorStatusIndicator = new OperatorStatusIndicator(openmct, configuration);
|
||||
|
||||
openmct.user.status.canSetPollQuestion().then((canSetPollQuestion) => {
|
||||
if (canSetPollQuestion) {
|
||||
const pollQuestionIndicator = new PollQuestionIndicator(openmct, configuration);
|
||||
operatorStatusIndicator.install();
|
||||
}
|
||||
});
|
||||
|
||||
pollQuestionIndicator.install();
|
||||
}
|
||||
});
|
||||
}
|
||||
openmct.user.status.canSetPollQuestion().then(canSetPollQuestion => {
|
||||
if (canSetPollQuestion) {
|
||||
const pollQuestionIndicator = new PollQuestionIndicator(openmct, configuration);
|
||||
|
||||
pollQuestionIndicator.install();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -21,33 +21,93 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="c-indicator icon-person c-indicator--clickable">
|
||||
<span class="label c-indicator__label">
|
||||
{{ userName }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
data() {
|
||||
return {
|
||||
userName: undefined,
|
||||
loggedIn: false
|
||||
<div class="c-indicator icon-person c-indicator--clickable">
|
||||
<span class="label c-indicator__label">
|
||||
{{ role ? `${userName}: ${role}` : userName }}
|
||||
<button @click="promptForRoleSelection">Change Role</button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RoleChannelProvider from '../../../api/user/RoleChannel';
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
data() {
|
||||
return {
|
||||
userName: undefined,
|
||||
role: undefined,
|
||||
loggedIn: false,
|
||||
roleChannelProvider: undefined
|
||||
};
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
this.getUserInfo();
|
||||
this.roleChannelProvider = new RoleChannelProvider(this.openmct);
|
||||
this.roleChannelProvider.createRoleChannel();
|
||||
this.roleChannelProvider.subscribeToRole(this.setRoleSelection);
|
||||
await this.fetchOrPromptForRole();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.roleChannelProvider.unsubscribeToRole();
|
||||
},
|
||||
methods: {
|
||||
async getUserInfo() {
|
||||
const user = await this.openmct.user.getCurrentUser();
|
||||
this.userName = user.getName();
|
||||
this.role = this.openmct.user.getActiveRole();
|
||||
this.loggedIn = this.openmct.user.isLoggedIn();
|
||||
},
|
||||
fetchOrPromptForRole() {
|
||||
const UserAPI = this.openmct.user;
|
||||
const activeRole = UserAPI.getActiveRole();
|
||||
this.role = activeRole;
|
||||
if (!activeRole) {
|
||||
this.promptForRoleSelection();
|
||||
}
|
||||
|
||||
},
|
||||
promptForRoleSelection() {
|
||||
const allRoles = this.openmct.user.getPossibleRoles();
|
||||
const selectionOptions = allRoles.map(x => ({
|
||||
key: x,
|
||||
name: x
|
||||
})).filter(this.openmct.user.canProvideStatusForRole);
|
||||
|
||||
const dialog = this.openmct.overlays.selection({
|
||||
selectionOptions,
|
||||
iconClass: 'info',
|
||||
title: 'Select Role',
|
||||
message: 'Please select your role for operator status.',
|
||||
currentSelection: this.role,
|
||||
onChange: (event) => {
|
||||
this.role = event.target.value;
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
label: 'Select',
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
dialog.dismiss();
|
||||
this.updateRole(this.role);
|
||||
this.openmct.notifications.info(`Successfully set new role to ${this.role}`);
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
setRoleSelection(role) {
|
||||
this.role = role;
|
||||
},
|
||||
|
||||
updateRole(role) {
|
||||
this.setRoleSelection(role);
|
||||
this.openmct.user.setActiveRole(role);
|
||||
// update other tabs through broadcast channel
|
||||
this.roleChannelProvider.broadcastNewRole(role);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getUserInfo();
|
||||
},
|
||||
methods: {
|
||||
getUserInfo() {
|
||||
this.openmct.user.getCurrentUser().then((user) => {
|
||||
this.userName = user.getName();
|
||||
this.loggedIn = this.openmct.user.isLoggedIn();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</script>
|
Reference in New Issue
Block a user