From e14b7cd0e28f0ca6f1ffbdaeca0521d33c9b024c Mon Sep 17 00:00:00 2001 From: Jamie V <jamie.j.vigliotta@nasa.gov> Date: Thu, 20 Jan 2022 13:56:17 -0800 Subject: [PATCH] [UserAPI] [UserIndicator Plugin] [ExampleUserProvider Plugin] New user api and related functionality (#4538) * Implements User API and example user plugin Co-authored-by: John Hill <john.c.hill@nasa.gov> Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com> Co-authored-by: Andrew Henry <akhenry@gmail.com> --- example/exampleUser/ExampleUserProvider.js | 110 ++++++++++++++ example/exampleUser/exampleUserCreator.js | 36 +++++ example/exampleUser/plugin.js | 29 ++++ example/exampleUser/pluginSpec.js | 55 +++++++ index.html | 7 +- src/MCT.js | 10 ++ src/api/api.js | 9 +- src/api/forms/components/FormProperties.vue | 26 +++- src/api/user/User.js | 39 +++++ src/api/user/UserAPI.js | 137 ++++++++++++++++++ src/api/user/UserAPISpec.js | 112 ++++++++++++++ src/api/user/constants.js | 24 +++ src/plugins/plugins.js | 17 ++- .../components/UserIndicator.vue | 54 +++++++ src/plugins/userIndicator/plugin.js | 56 +++++++ src/plugins/userIndicator/pluginSpec.js | 100 +++++++++++++ src/styles/_controls.scss | 1 + 17 files changed, 808 insertions(+), 14 deletions(-) create mode 100644 example/exampleUser/ExampleUserProvider.js create mode 100644 example/exampleUser/exampleUserCreator.js create mode 100644 example/exampleUser/plugin.js create mode 100644 example/exampleUser/pluginSpec.js create mode 100644 src/api/user/User.js create mode 100644 src/api/user/UserAPI.js create mode 100644 src/api/user/UserAPISpec.js create mode 100644 src/api/user/constants.js create mode 100644 src/plugins/userIndicator/components/UserIndicator.vue create mode 100644 src/plugins/userIndicator/plugin.js create mode 100644 src/plugins/userIndicator/pluginSpec.js diff --git a/example/exampleUser/ExampleUserProvider.js b/example/exampleUser/ExampleUserProvider.js new file mode 100644 index 0000000000..dc49467b1e --- /dev/null +++ b/example/exampleUser/ExampleUserProvider.js @@ -0,0 +1,110 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import EventEmitter from 'EventEmitter'; +import uuid from 'uuid'; +import createExampleUser from './exampleUserCreator'; + +export default class ExampleUserProvider extends EventEmitter { + constructor(openmct) { + super(); + + this.openmct = openmct; + this.user = undefined; + this.loggedIn = false; + this.autoLoginUser = undefined; + + this.ExampleUser = createExampleUser(this.openmct.user.User); + } + + isLoggedIn() { + return this.loggedIn; + } + + autoLogin(username) { + this.autoLoginUser = username; + } + + getCurrentUser() { + if (this.loggedIn) { + return Promise.resolve(this.user); + } + + return this._login().then(() => this.user); + } + + hasRole(roleId) { + if (!this.loggedIn) { + Promise.resolve(undefined); + } + + return Promise.resolve(this.user.getRoles().includes(roleId)); + } + + _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; + + 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) => { + this.user = new this.ExampleUser(id, info.username, ['example-role']); + this.loggedIn = true; + }, + () => { // user canceled, setting a default username + this.user = new this.ExampleUser(id, 'Pat', ['example-role']); + this.loggedIn = true; + } + ); + } +} diff --git a/example/exampleUser/exampleUserCreator.js b/example/exampleUser/exampleUserCreator.js new file mode 100644 index 0000000000..286cc611b5 --- /dev/null +++ b/example/exampleUser/exampleUserCreator.js @@ -0,0 +1,36 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +export default function createExampleUser(UserClass) { + return class ExampleUser extends UserClass { + constructor(id, name, roles) { + super(id, name); + + this.roles = roles; + this.getRoles = this.getRoles.bind(this); + } + + getRoles() { + return this.roles; + } + }; +} diff --git a/example/exampleUser/plugin.js b/example/exampleUser/plugin.js new file mode 100644 index 0000000000..ba9ee38040 --- /dev/null +++ b/example/exampleUser/plugin.js @@ -0,0 +1,29 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import ExampleUserProvider from './ExampleUserProvider'; + +export default function ExampleUserPlugin() { + return function install(openmct) { + openmct.user.setProvider(new ExampleUserProvider(openmct)); + }; +} diff --git a/example/exampleUser/pluginSpec.js b/example/exampleUser/pluginSpec.js new file mode 100644 index 0000000000..f62d157359 --- /dev/null +++ b/example/exampleUser/pluginSpec.js @@ -0,0 +1,55 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import { + createOpenMct, + resetApplicationState +} from '../../src/utils/testing'; +import ExampleUserProvider from './ExampleUserProvider'; + +describe("The Example User Plugin", () => { + let openmct; + + beforeEach(() => { + openmct = createOpenMct(); + }); + + afterEach(() => { + return resetApplicationState(openmct); + }); + + it('is not installed by default', () => { + expect(openmct.user.hasProvider()).toBeFalse(); + }); + + it('can be installed', () => { + openmct.user.on('providerAdded', (provider) => { + expect(provider).toBeInstanceOf(ExampleUserProvider); + }); + openmct.install(openmct.plugins.example.ExampleUser()); + }); + + // The rest of the functionality of the ExampleUser Plugin is + // tested in both the UserAPISpec.js and in the UserIndicatorPlugin spec. + // If that changes, those tests can be moved here. + +}); diff --git a/index.html b/index.html index fdad41c667..7cbb564cde 100644 --- a/index.html +++ b/index.html @@ -77,12 +77,13 @@ openmct.install(openmct.plugins.LocalStorage()); + + openmct.install(openmct.plugins.example.Generator()); + openmct.install(openmct.plugins.example.EventGeneratorPlugin()); + openmct.install(openmct.plugins.example.ExampleImagery()); openmct.install(openmct.plugins.Espresso()); openmct.install(openmct.plugins.MyItems()); - openmct.install(openmct.plugins.Generator()); - openmct.install(openmct.plugins.EventGeneratorPlugin()); - openmct.install(openmct.plugins.ExampleImagery()); openmct.install(openmct.plugins.PlanLayout()); openmct.install(openmct.plugins.Timeline()); openmct.install(openmct.plugins.Hyperlink()); diff --git a/src/MCT.js b/src/MCT.js index fa1848d7ad..7168bfb2cb 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -212,6 +212,15 @@ define([ */ this.indicators = new api.IndicatorAPI(this); + /** + * MCT's user awareness management, to enable user and + * role specific functionality. + * @type {module:openmct.UserAPI} + * @memberof module:openmct.MCT# + * @name user + */ + this.user = new api.UserAPI(this); + this.notifications = new api.NotificationAPI(); this.editor = new api.EditorAPI.default(this); @@ -262,6 +271,7 @@ define([ this.install(this.plugins.ObjectInterceptors()); this.install(this.plugins.NonEditableFolder()); this.install(this.plugins.DeviceClassifier()); + this.install(this.plugins.UserIndicator()); } MCT.prototype = Object.create(EventEmitter.prototype); diff --git a/src/api/api.js b/src/api/api.js index 96a2691e37..1a0174d574 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -33,7 +33,8 @@ define([ './status/StatusAPI', './telemetry/TelemetryAPI', './time/TimeAPI', - './types/TypeRegistry' + './types/TypeRegistry', + './user/UserAPI' ], function ( ActionsAPI, CompositionAPI, @@ -47,7 +48,8 @@ define([ StatusAPI, TelemetryAPI, TimeAPI, - TypeRegistry + TypeRegistry, + UserAPI ) { return { ActionsAPI: ActionsAPI.default, @@ -62,6 +64,7 @@ define([ StatusAPI: StatusAPI.default, TelemetryAPI: TelemetryAPI, TimeAPI: TimeAPI.default, - TypeRegistry: TypeRegistry + TypeRegistry: TypeRegistry, + UserAPI: UserAPI.default }; }); diff --git a/src/api/forms/components/FormProperties.vue b/src/api/forms/components/FormProperties.vue index 9ae202194f..d3caebea6c 100644 --- a/src/api/forms/components/FormProperties.vue +++ b/src/api/forms/components/FormProperties.vue @@ -60,13 +60,13 @@ class="c-button c-button--major" @click="onSave" > - OK + {{ submitLabel }} </button> <button tabindex="0" class="c-button" @click="onDismiss" > - Cancel + {{ cancelLabel }} </button> </div> </div> @@ -105,6 +105,28 @@ export default { .some(([key, value]) => { return value; }); + }, + submitLabel() { + if ( + this.model.buttons + && this.model.buttons.submit + && this.model.buttons.submit.label + ) { + return this.model.buttons.submit.label; + } + + return 'OK'; + }, + cancelLabel() { + if ( + this.model.buttons + && this.model.buttons.cancel + && this.model.buttons.cancel.label + ) { + return this.model.buttons.submit.label; + } + + return 'Cancel'; } }, mounted() { diff --git a/src/api/user/User.js b/src/api/user/User.js new file mode 100644 index 0000000000..dfb0caa0cf --- /dev/null +++ b/src/api/user/User.js @@ -0,0 +1,39 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +export default class User { + constructor(id, name) { + this.id = id; + this.name = name; + + this.getId = this.getId.bind(this); + this.getName = this.getName.bind(this); + } + + getId() { + return this.id; + } + + getName() { + return this.name; + } +} diff --git a/src/api/user/UserAPI.js b/src/api/user/UserAPI.js new file mode 100644 index 0000000000..82ff21f8d7 --- /dev/null +++ b/src/api/user/UserAPI.js @@ -0,0 +1,137 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import EventEmitter from 'EventEmitter'; +import { + MULTIPLE_PROVIDER_ERROR, + NO_PROVIDER_ERROR +} from './constants'; +import User from './User'; + +class UserAPI extends EventEmitter { + constructor(openmct) { + super(); + + this._openmct = openmct; + this._provider = undefined; + + this.User = User; + } + + /** + * 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._provider = provider; + + this.emit('providerAdded', 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() { + this._noProviderCheck(); + + 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; + } + + 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; diff --git a/src/api/user/UserAPISpec.js b/src/api/user/UserAPISpec.js new file mode 100644 index 0000000000..c70066e3f4 --- /dev/null +++ b/src/api/user/UserAPISpec.js @@ -0,0 +1,112 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import { + createOpenMct, + resetApplicationState +} from '../../utils/testing'; +import { + MULTIPLE_PROVIDER_ERROR +} from './constants'; +import ExampleUserProvider from '../../../example/exampleUser/ExampleUserProvider'; + +const USERNAME = 'Test User'; +const EXAMPLE_ROLE = 'example-role'; + +describe("The User API", () => { + let openmct; + + beforeEach(() => { + openmct = createOpenMct(); + }); + + afterEach(() => { + return resetApplicationState(openmct); + }); + + describe('with regard to user providers', () => { + + it('allows you to specify a user provider', () => { + openmct.user.on('providerAdded', (provider) => { + expect(provider).toBeInstanceOf(ExampleUserProvider); + }); + openmct.user.setProvider(new ExampleUserProvider(openmct)); + }); + + it('prevents more than one user provider from being set', () => { + openmct.user.setProvider(new ExampleUserProvider(openmct)); + + expect(() => { + openmct.user.setProvider({}); + }).toThrow(new Error(MULTIPLE_PROVIDER_ERROR)); + }); + + it('provides a check for an existing user provider', () => { + expect(openmct.user.hasProvider()).toBeFalse(); + + openmct.user.setProvider(new ExampleUserProvider(openmct)); + + expect(openmct.user.hasProvider()).toBeTrue(); + }); + }); + + describe('provides the ability', () => { + let provider; + + beforeEach(() => { + provider = new ExampleUserProvider(openmct); + provider.autoLogin(USERNAME); + }); + + it('to check if a user (not specific) is loged in', (done) => { + expect(openmct.user.isLoggedIn()).toBeFalse(); + + openmct.user.on('providerAdded', () => { + expect(openmct.user.isLoggedIn()).toBeTrue(); + done(); + }); + + // this will trigger the user indicator plugin, + // which will in turn login the user + openmct.user.setProvider(provider); + }); + + it('to get the current user', (done) => { + openmct.user.setProvider(provider); + openmct.user.getCurrentUser().then((apiUser) => { + expect(apiUser.name).toEqual(USERNAME); + }).finally(done); + }); + + it('to check if a user has a specific role (by id)', (done) => { + openmct.user.setProvider(provider); + let junkIdCheckPromise = openmct.user.hasRole('junk-id').then((hasRole) => { + expect(hasRole).toBeFalse(); + }); + let realIdCheckPromise = openmct.user.hasRole(EXAMPLE_ROLE).then((hasRole) => { + expect(hasRole).toBeTrue(); + }); + + Promise.all([junkIdCheckPromise, realIdCheckPromise]).finally(done); + }); + }); +}); diff --git a/src/api/user/constants.js b/src/api/user/constants.js new file mode 100644 index 0000000000..0f839385cb --- /dev/null +++ b/src/api/user/constants.js @@ -0,0 +1,24 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +export 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.'; diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index a9cca07336..4755895aa6 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -75,6 +75,8 @@ define([ './clock/plugin', './DeviceClassifier/plugin', './timer/plugin', + './userIndicator/plugin', + '../../example/exampleUser/plugin', './localStorage/plugin', './legacySupport/plugin.js', '../adapter/indicators/legacy-indicators-plugin' @@ -133,6 +135,8 @@ define([ Clock, DeviceClassifier, Timer, + UserIndicator, + ExampleUser, LocalStorage, LegacySupportPlugin, LegacyIndicatorsPlugin @@ -149,6 +153,12 @@ define([ }; }); + plugins.example = {}; + plugins.example.ExampleUser = ExampleUser.default; + plugins.example.ExampleImagery = ExampleImagery.default; + plugins.example.EventGeneratorPlugin = EventGeneratorPlugin.default; + plugins.example.Generator = () => GeneratorPlugin; + plugins.UTCTimeSystem = UTCTimeSystem.default; plugins.LocalTimeSystem = LocalTimeSystem; plugins.RemoteClock = RemoteClock.default; @@ -194,12 +204,6 @@ define([ }; }; - plugins.Generator = function () { - return GeneratorPlugin; - }; - - plugins.EventGeneratorPlugin = EventGeneratorPlugin.default; - plugins.ExampleImagery = ExampleImagery.default; plugins.ImageryPlugin = ImageryPlugin; plugins.Plot = PlotPlugin.default; plugins.Chart = ChartPlugin.default; @@ -243,6 +247,7 @@ define([ plugins.Clock = Clock.default; plugins.Timer = Timer.default; plugins.DeviceClassifier = DeviceClassifier.default; + plugins.UserIndicator = UserIndicator.default; plugins.LocalStorage = LocalStorage.default; plugins.LegacySupport = LegacySupportPlugin.default; plugins.LegacyIndicators = LegacyIndicatorsPlugin; diff --git a/src/plugins/userIndicator/components/UserIndicator.vue b/src/plugins/userIndicator/components/UserIndicator.vue new file mode 100644 index 0000000000..c063a88b14 --- /dev/null +++ b/src/plugins/userIndicator/components/UserIndicator.vue @@ -0,0 +1,54 @@ +<!-- + Open MCT, Copyright (c) 2014-2021, United States Government + as represented by the Administrator of the National Aeronautics and Space + Administration. All rights reserved. + + Open MCT is licensed under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + License for the specific language governing permissions and limitations + under the License. + + Open MCT includes source code licensed under additional open source + licenses. See the Open Source Licenses file (LICENSES.md) included with + this source code distribution or the Licensing information page available + at runtime from the About dialog for additional information. +--> + +<template> +<div class="c-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 + }; + }, + + mounted() { + this.getUserInfo(); + }, + methods: { + getUserInfo() { + this.openmct.user.getCurrentUser().then((user) => { + this.userName = user.getName(); + this.loggedIn = this.openmct.user.isLoggedIn(); + }); + } + } +}; +</script> diff --git a/src/plugins/userIndicator/plugin.js b/src/plugins/userIndicator/plugin.js new file mode 100644 index 0000000000..9c46d252cd --- /dev/null +++ b/src/plugins/userIndicator/plugin.js @@ -0,0 +1,56 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import UserIndicator from './components/UserIndicator.vue'; +import Vue from 'vue'; + +export default function UserIndicatorPlugin() { + + function addIndicator(openmct) { + const userIndicator = new Vue ({ + components: { + UserIndicator + }, + provide: { + openmct: openmct + }, + template: '<UserIndicator />' + }); + + openmct.indicators.add({ + key: 'user-indicator', + element: userIndicator.$mount().$el, + priority: openmct.priority.HIGH + }); + } + + return function install(openmct) { + if (openmct.user.hasProvider()) { + addIndicator(openmct); + } else { + // back up if user provider added after indicator installed + openmct.user.on('providerAdded', () => { + addIndicator(openmct); + }); + } + }; +} diff --git a/src/plugins/userIndicator/pluginSpec.js b/src/plugins/userIndicator/pluginSpec.js new file mode 100644 index 0000000000..045e0a171f --- /dev/null +++ b/src/plugins/userIndicator/pluginSpec.js @@ -0,0 +1,100 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2021, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is licensed under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import { + createOpenMct, + resetApplicationState +} from 'utils/testing'; +import Vue from 'vue'; +import ExampleUserProvider from '../../../example/exampleUser/ExampleUserProvider'; + +const USERNAME = 'Coach McGuirk'; + +describe('The User Indicator plugin', () => { + let openmct; + let element; + let child; + let appHolder; + let userIndicator; + let provider; + + beforeEach((done) => { + appHolder = document.createElement('div'); + appHolder.style.width = '640px'; + appHolder.style.height = '480px'; + document.body.appendChild(appHolder); + + element = document.createElement('div'); + child = document.createElement('div'); + element.appendChild(child); + + openmct = createOpenMct(); + openmct.on('start', done); + openmct.start(appHolder); + }); + + afterEach(() => { + return resetApplicationState(openmct); + }); + + it('will not show, if there is no user provider', () => { + userIndicator = openmct.indicators.indicatorObjects + .find(indicator => indicator.key === 'user-indicator'); + + expect(userIndicator).toBe(undefined); + }); + + describe('with a user provider installed', () => { + + beforeEach(() => { + provider = new ExampleUserProvider(openmct); + provider.autoLogin(USERNAME); + + openmct.user.setProvider(provider); + + return Vue.nextTick(); + }); + + it('exists', () => { + userIndicator = openmct.indicators.indicatorObjects + .find(indicator => indicator.key === 'user-indicator').element; + + const hasClockIndicator = userIndicator !== null && userIndicator !== undefined; + expect(hasClockIndicator).toBe(true); + }); + + it('contains the logged in user name', (done) => { + openmct.user.getCurrentUser().then(async (user) => { + await Vue.nextTick(); + + userIndicator = openmct.indicators.indicatorObjects + .find(indicator => indicator.key === 'user-indicator').element; + + const userName = userIndicator.textContent.trim(); + + expect(user.name).toEqual(USERNAME); + expect(userName).toContain(USERNAME); + }).finally(done); + }); + + }); +}); diff --git a/src/styles/_controls.scss b/src/styles/_controls.scss index 30a8de3619..0e36cb6c7d 100644 --- a/src/styles/_controls.scss +++ b/src/styles/_controls.scss @@ -273,6 +273,7 @@ input, textarea { input[type=text], input[type=search], input[type=number], +input[type=password], input[type=date], textarea { @include reactive-input();