mirror of
https://github.com/nasa/openmct.git
synced 2025-05-06 18:48:27 +00:00
6098 operator status indicator v11 improvements (#6112)
* Added clear poll button to clear all statuses * Clear current poll question * Added table for operator status Co-authored-by: Michael Rogers <contact@mhrogers.com> Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
parent
e0ca6200bb
commit
22621aaaf8
27
e2e/helper/addInitExampleUser.js
Normal file
27
e2e/helper/addInitExampleUser.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
// This should be used to install the Example User
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const openmct = window.openmct;
|
||||||
|
openmct.install(openmct.plugins.example.ExampleUser());
|
||||||
|
});
|
27
e2e/helper/addInitOperatorStatus.js
Normal file
27
e2e/helper/addInitOperatorStatus.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
// This should be used to install the Operator Status
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const openmct = window.openmct;
|
||||||
|
openmct.install(openmct.plugins.OperatorStatus());
|
||||||
|
});
|
@ -0,0 +1,156 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This test suite is dedicated to testing the operator status plugin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const { test, expect } = require('../../../../pluginFixtures');
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Precondition: Inject Example User, Operator Status Plugins
|
||||||
|
Verify that user 1 sees updates from user/role 2 (Not possible without openmct-yamcs implementation)
|
||||||
|
|
||||||
|
Clear Role Status of single user test
|
||||||
|
STUB (test.fixme) Rolling through each
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
test.describe('Operator Status', () => {
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
// FIXME: determine if plugins will be added to index.html or need to be injected
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
await page.addInitScript({ path: path.join(__dirname, '../../../../helper/', 'addInitExampleUser.js')});
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
await page.addInitScript({ path: path.join(__dirname, '../../../../helper/', 'addInitOperatorStatus.js')});
|
||||||
|
await page.goto('./', { waitUntil: 'networkidle' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// verify that operator status is visible
|
||||||
|
test('operator status is visible and expands when clicked', async ({ page }) => {
|
||||||
|
await expect(page.locator('div[title="Set my operator status"]')).toBeVisible();
|
||||||
|
await page.locator('div[title="Set my operator status"]').click();
|
||||||
|
|
||||||
|
// expect default status to be 'GO'
|
||||||
|
await expect(page.locator('.c-status-poll-panel')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('poll question indicator remains when blank poll set', async ({ page }) => {
|
||||||
|
await expect(page.locator('div[title="Set the current poll question"]')).toBeVisible();
|
||||||
|
await page.locator('div[title="Set the current poll question"]').click();
|
||||||
|
// set to blank
|
||||||
|
await page.getByRole('button', { name: 'Update' }).click();
|
||||||
|
|
||||||
|
// should still be visible
|
||||||
|
await expect(page.locator('div[title="Set the current poll question"]')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify that user 1 sees updates from user/role 2 (Not possible without openmct-yamcs implementation)
|
||||||
|
test('operator status table reflects answered values', async ({ page }) => {
|
||||||
|
// user navigates to operator status poll
|
||||||
|
const statusPollIndicator = page.locator('div[title="Set my operator status"]');
|
||||||
|
await statusPollIndicator.click();
|
||||||
|
|
||||||
|
// get user role value
|
||||||
|
const userRole = page.locator('.c-status-poll-panel__user-role');
|
||||||
|
const userRoleText = await userRole.innerText();
|
||||||
|
|
||||||
|
// get selected status value
|
||||||
|
const selectStatus = page.locator('select[name="setStatus"]');
|
||||||
|
await selectStatus.selectOption({ index: 1});
|
||||||
|
const initialStatusValue = await selectStatus.inputValue();
|
||||||
|
|
||||||
|
// open manage status poll
|
||||||
|
const manageStatusPollIndicator = page.locator('div[title="Set the current poll question"]');
|
||||||
|
await manageStatusPollIndicator.click();
|
||||||
|
// parse the table row values
|
||||||
|
const row = page.locator(`tr:has-text("${userRoleText}")`);
|
||||||
|
const rowValues = await row.innerText();
|
||||||
|
const rowValuesArr = rowValues.split('\t');
|
||||||
|
const COLUMN_STATUS_INDEX = 1;
|
||||||
|
// check initial set value matches status table
|
||||||
|
expect(rowValuesArr[COLUMN_STATUS_INDEX].toLowerCase())
|
||||||
|
.toEqual(initialStatusValue.toLowerCase());
|
||||||
|
|
||||||
|
// change user status
|
||||||
|
await statusPollIndicator.click();
|
||||||
|
// FIXME: might want to grab a dynamic option instead of arbitrary
|
||||||
|
await page.locator('select[name="setStatus"]').selectOption({ index: 2});
|
||||||
|
const updatedStatusValue = await selectStatus.inputValue();
|
||||||
|
// verify user status is reflected in table
|
||||||
|
await manageStatusPollIndicator.click();
|
||||||
|
|
||||||
|
const updatedRow = page.locator(`tr:has-text("${userRoleText}")`);
|
||||||
|
const updatedRowValues = await updatedRow.innerText();
|
||||||
|
const updatedRowValuesArr = updatedRowValues.split('\t');
|
||||||
|
|
||||||
|
expect(updatedRowValuesArr[COLUMN_STATUS_INDEX].toLowerCase())
|
||||||
|
.toEqual(updatedStatusValue.toLowerCase());
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test('clear poll button removes poll responses', async ({ page }) => {
|
||||||
|
// user navigates to operator status poll
|
||||||
|
const statusPollIndicator = page.locator('div[title="Set my operator status"]');
|
||||||
|
await statusPollIndicator.click();
|
||||||
|
|
||||||
|
// get user role value
|
||||||
|
const userRole = page.locator('.c-status-poll-panel__user-role');
|
||||||
|
const userRoleText = await userRole.innerText();
|
||||||
|
|
||||||
|
// get selected status value
|
||||||
|
const selectStatus = page.locator('select[name="setStatus"]');
|
||||||
|
// FIXME: might want to grab a dynamic option instead of arbitrary
|
||||||
|
await selectStatus.selectOption({ index: 1});
|
||||||
|
const initialStatusValue = await selectStatus.inputValue();
|
||||||
|
|
||||||
|
// open manage status poll
|
||||||
|
const manageStatusPollIndicator = page.locator('div[title="Set the current poll question"]');
|
||||||
|
await manageStatusPollIndicator.click();
|
||||||
|
// parse the table row values
|
||||||
|
const row = page.locator(`tr:has-text("${userRoleText}")`);
|
||||||
|
const rowValues = await row.innerText();
|
||||||
|
const rowValuesArr = rowValues.split('\t');
|
||||||
|
const COLUMN_STATUS_INDEX = 1;
|
||||||
|
// check initial set value matches status table
|
||||||
|
expect(rowValuesArr[COLUMN_STATUS_INDEX].toLowerCase())
|
||||||
|
.toEqual(initialStatusValue.toLowerCase());
|
||||||
|
|
||||||
|
// clear the poll
|
||||||
|
await page.locator('button[title="Clear the previous poll question"]').click();
|
||||||
|
|
||||||
|
const updatedRow = page.locator(`tr:has-text("${userRoleText}")`);
|
||||||
|
const updatedRowValues = await updatedRow.innerText();
|
||||||
|
const updatedRowValuesArr = updatedRowValues.split('\t');
|
||||||
|
const UNSET_VALUE_LABEL = 'Not set';
|
||||||
|
expect(updatedRowValuesArr[COLUMN_STATUS_INDEX])
|
||||||
|
.toEqual(UNSET_VALUE_LABEL);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test.fixme('iterate through all possible response values', async ({ page }) => {
|
||||||
|
// test all possible respone values for the poll
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -65,7 +65,7 @@ export default class ExampleUserProvider extends EventEmitter {
|
|||||||
this.user = undefined;
|
this.user = undefined;
|
||||||
this.loggedIn = false;
|
this.loggedIn = false;
|
||||||
this.autoLoginUser = undefined;
|
this.autoLoginUser = undefined;
|
||||||
this.status = STATUSES[1];
|
this.status = STATUSES[0];
|
||||||
this.pollQuestion = undefined;
|
this.pollQuestion = undefined;
|
||||||
this.defaultStatusRole = defaultStatusRole;
|
this.defaultStatusRole = defaultStatusRole;
|
||||||
|
|
||||||
@ -124,6 +124,7 @@ export default class ExampleUserProvider extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setStatusForRole(role, status) {
|
setStatusForRole(role, status) {
|
||||||
|
status.timestamp = Date.now();
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.emit('statusChange', {
|
this.emit('statusChange', {
|
||||||
role,
|
role,
|
||||||
@ -133,14 +134,23 @@ export default class ExampleUserProvider extends EventEmitter {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPollQuestion() {
|
// eslint-disable-next-line require-await
|
||||||
return Promise.resolve({
|
async getPollQuestion() {
|
||||||
question: 'Set "GO" if your position is ready for a boarding action on the Klingon cruiser',
|
if (this.pollQuestion) {
|
||||||
timestamp: Date.now()
|
return this.pollQuestion;
|
||||||
});
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPollQuestion(pollQuestion) {
|
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 = {
|
this.pollQuestion = {
|
||||||
question: pollQuestion,
|
question: pollQuestion,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
|
@ -291,5 +291,6 @@ export default class StatusAPI extends EventEmitter {
|
|||||||
* The Status type
|
* The Status type
|
||||||
* @typedef {Object} Status
|
* @typedef {Object} Status
|
||||||
* @property {String} key - A unique identifier for this status
|
* @property {String} key - A unique identifier for this status
|
||||||
* @property {Number} label - A human readable label for this status
|
* @property {String} label - A human readable label for this status
|
||||||
|
* @property {Number} timestamp - The time that the status was set.
|
||||||
*/
|
*/
|
||||||
|
@ -88,6 +88,14 @@
|
|||||||
padding: 3px 0;
|
padding: 3px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[class*='__label'] {
|
||||||
|
padding: 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*='__poll-table'] {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
[class*='new-question'] {
|
[class*='new-question'] {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -123,6 +131,12 @@
|
|||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&__actions {
|
||||||
|
display:flex;
|
||||||
|
flex: auto;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-indicator {
|
.c-indicator {
|
||||||
|
@ -58,6 +58,13 @@
|
|||||||
{{ entry.roleCount }}
|
{{ entry.roleCount }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="c-status-poll-report__actions">
|
||||||
|
<button
|
||||||
|
class="c-button"
|
||||||
|
title="Clear the previous poll question"
|
||||||
|
@click="clearPollQuestion"
|
||||||
|
>Clear Poll</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -74,6 +81,41 @@
|
|||||||
@click="updatePollQuestion"
|
@click="updatePollQuestion"
|
||||||
>Update</button>
|
>Update</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="c-table c-spq__poll-table">
|
||||||
|
<table class="c-table__body">
|
||||||
|
<thead class="c-table__header">
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Position
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Status
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Age
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="statusForRole in statusesForRolesViewModel"
|
||||||
|
:key="statusForRole.key"
|
||||||
|
>
|
||||||
|
<td>
|
||||||
|
{{ statusForRole.role }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
:style="{ background: statusForRole.status.statusBgColor, color: statusForRole.status.statusFgColor }"
|
||||||
|
>
|
||||||
|
{{ statusForRole.status.label }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ statusForRole.age }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -97,9 +139,11 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
pollQuestionUpdated: '--',
|
pollQuestionUpdated: '--',
|
||||||
|
pollQuestionTimestamp: undefined,
|
||||||
currentPollQuestion: '--',
|
currentPollQuestion: '--',
|
||||||
newPollQuestion: undefined,
|
newPollQuestion: undefined,
|
||||||
statusCountViewModel: []
|
statusCountViewModel: [],
|
||||||
|
statusesForRolesViewModel: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -135,9 +179,17 @@ export default {
|
|||||||
this.openmct.user.status.on('pollQuestionChange', this.setPollQuestion);
|
this.openmct.user.status.on('pollQuestionChange', this.setPollQuestion);
|
||||||
},
|
},
|
||||||
setPollQuestion(pollQuestion) {
|
setPollQuestion(pollQuestion) {
|
||||||
this.currentPollQuestion = pollQuestion.question;
|
let pollQuestionText = pollQuestion.question;
|
||||||
|
if (!pollQuestionText || pollQuestionText === '') {
|
||||||
|
pollQuestionText = '--';
|
||||||
|
this.indicator.text('No Poll Question');
|
||||||
|
} else {
|
||||||
|
this.indicator.text(pollQuestionText);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentPollQuestion = pollQuestionText;
|
||||||
|
this.pollQuestionTimestamp = pollQuestion.timestamp;
|
||||||
this.pollQuestionUpdated = new Date(pollQuestion.timestamp).toISOString();
|
this.pollQuestionUpdated = new Date(pollQuestion.timestamp).toISOString();
|
||||||
this.indicator.text(pollQuestion.question);
|
|
||||||
},
|
},
|
||||||
async updatePollQuestion() {
|
async updatePollQuestion() {
|
||||||
const result = await this.openmct.user.status.setPollQuestion(this.newPollQuestion);
|
const result = await this.openmct.user.status.setPollQuestion(this.newPollQuestion);
|
||||||
@ -149,6 +201,13 @@ export default {
|
|||||||
|
|
||||||
this.newPollQuestion = undefined;
|
this.newPollQuestion = undefined;
|
||||||
},
|
},
|
||||||
|
async clearPollQuestion() {
|
||||||
|
this.currentPollQuestion = undefined;
|
||||||
|
await Promise.all([
|
||||||
|
this.openmct.user.status.resetAllStatuses(),
|
||||||
|
this.openmct.user.status.setPollQuestion()
|
||||||
|
]);
|
||||||
|
},
|
||||||
async fetchStatusSummary() {
|
async fetchStatusSummary() {
|
||||||
const allStatuses = await this.openmct.user.status.getPossibleStatuses();
|
const allStatuses = await this.openmct.user.status.getPossibleStatuses();
|
||||||
const statusCountMap = allStatuses.reduce((statusToCountMap, status) => {
|
const statusCountMap = allStatuses.reduce((statusToCountMap, status) => {
|
||||||
@ -158,7 +217,6 @@ export default {
|
|||||||
}, {});
|
}, {});
|
||||||
const allStatusRoles = await this.openmct.user.status.getAllStatusRoles();
|
const allStatusRoles = await this.openmct.user.status.getAllStatusRoles();
|
||||||
const statusesForRoles = await Promise.all(allStatusRoles.map(role => this.openmct.user.status.getStatusForRole(role)));
|
const statusesForRoles = await Promise.all(allStatusRoles.map(role => this.openmct.user.status.getStatusForRole(role)));
|
||||||
|
|
||||||
statusesForRoles.forEach((status, i) => {
|
statusesForRoles.forEach((status, i) => {
|
||||||
const currentCount = statusCountMap[status.key];
|
const currentCount = statusCountMap[status.key];
|
||||||
statusCountMap[status.key] = currentCount + 1;
|
statusCountMap[status.key] = currentCount + 1;
|
||||||
@ -170,6 +228,51 @@ export default {
|
|||||||
roleCount: statusCountMap[status.key]
|
roleCount: statusCountMap[status.key]
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
const defaultStatuses = await Promise.all(allStatusRoles.map(role => this.openmct.user.status.getDefaultStatusForRole(role)));
|
||||||
|
this.statusesForRolesViewModel = [];
|
||||||
|
statusesForRoles.forEach((status, index) => {
|
||||||
|
const isDefaultStatus = defaultStatuses[index].key === status.key;
|
||||||
|
let statusTimestamp = status.timestamp;
|
||||||
|
if (isDefaultStatus) {
|
||||||
|
// if the default is selected, set timestamp to undefined
|
||||||
|
statusTimestamp = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.statusesForRolesViewModel.push({
|
||||||
|
status: this.applyStyling(status),
|
||||||
|
role: allStatusRoles[index],
|
||||||
|
age: this.formatStatusAge(statusTimestamp, this.pollQuestionTimestamp)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
formatStatusAge(statusTimestamp, pollQuestionTimestamp) {
|
||||||
|
if (statusTimestamp === undefined || pollQuestionTimestamp === undefined) {
|
||||||
|
return '--';
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusAgeInMs = statusTimestamp - pollQuestionTimestamp;
|
||||||
|
const absoluteTotalSeconds = Math.floor(Math.abs(statusAgeInMs) / 1000);
|
||||||
|
let hours = Math.floor(absoluteTotalSeconds / 3600);
|
||||||
|
let minutes = Math.floor((absoluteTotalSeconds - (hours * 3600)) / 60);
|
||||||
|
let secondsString = absoluteTotalSeconds - (hours * 3600) - (minutes * 60);
|
||||||
|
|
||||||
|
if (statusAgeInMs > 0 || (absoluteTotalSeconds === 0)) {
|
||||||
|
hours = `+ ${hours}`;
|
||||||
|
} else {
|
||||||
|
hours = `- ${hours}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minutes < 10) {
|
||||||
|
minutes = `0${minutes}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secondsString < 10) {
|
||||||
|
secondsString = `0${secondsString}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusAgeString = `${hours}:${minutes}:${secondsString}`;
|
||||||
|
|
||||||
|
return statusAgeString;
|
||||||
},
|
},
|
||||||
applyStyling(status) {
|
applyStyling(status) {
|
||||||
const stylesForStatus = this.configuration?.statusStyles?.[status.label];
|
const stylesForStatus = this.configuration?.statusStyles?.[status.label];
|
||||||
|
@ -51,7 +51,7 @@ export default class PollQuestionIndicator extends AbstractStatusIndicator {
|
|||||||
createIndicator() {
|
createIndicator() {
|
||||||
const pollQuestionIndicator = this.openmct.indicators.simpleIndicator();
|
const pollQuestionIndicator = this.openmct.indicators.simpleIndicator();
|
||||||
|
|
||||||
pollQuestionIndicator.text("Poll Question");
|
pollQuestionIndicator.text("No Poll Question");
|
||||||
pollQuestionIndicator.description("Set the current poll question");
|
pollQuestionIndicator.description("Set the current poll question");
|
||||||
pollQuestionIndicator.iconClass('icon-status-poll-edit');
|
pollQuestionIndicator.iconClass('icon-status-poll-edit');
|
||||||
pollQuestionIndicator.element.classList.add("c-indicator--operator-status");
|
pollQuestionIndicator.element.classList.add("c-indicator--operator-status");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user