[Tooltips] Add tooltips on hover (#6756)
* Add tooltip api, extend object api to add telemetry composition lookups, and add tooltips to gauges/notebook embeds/plot legends/object frames/object names/time strips/recent objects/search results/object tree * Add tooltips to telemetry/lad tables * Styling normalization, sanding and polishing. * Add tooltips for Conditional widgets and Tab Views * Add tests * Switch to using enum-ish consts for tooltip locations * Trim LAD table row name to account for spacing required by linting rules --------- Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com>
This commit is contained in:
@@ -24,6 +24,7 @@ define([
|
||||
'EventEmitter',
|
||||
'./api/api',
|
||||
'./api/overlays/OverlayAPI',
|
||||
'./api/tooltips/ToolTipAPI',
|
||||
'./selection/Selection',
|
||||
'./plugins/plugins',
|
||||
'./ui/registries/ViewRegistry',
|
||||
@@ -48,6 +49,7 @@ define([
|
||||
EventEmitter,
|
||||
api,
|
||||
OverlayAPI,
|
||||
ToolTipAPI,
|
||||
Selection,
|
||||
plugins,
|
||||
ViewRegistry,
|
||||
@@ -220,6 +222,8 @@ define([
|
||||
|
||||
['overlays', () => new OverlayAPI.default()],
|
||||
|
||||
['tooltips', () => new ToolTipAPI.default()],
|
||||
|
||||
['menus', () => new api.MenuAPI(this)],
|
||||
|
||||
['actions', () => new api.ActionsAPI(this)],
|
||||
|
||||
@@ -540,6 +540,40 @@ export default class ObjectAPI {
|
||||
.join('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return path of telemetry objects in the object composition
|
||||
* @param {object} identifier the identifier for the domain object to query for
|
||||
* @param {object} [telemetryIdentifier] the specific identifier for the telemetry
|
||||
* to look for in the composition, uses first object in composition otherwise
|
||||
* @returns {Array} path of telemetry object in object composition
|
||||
*/
|
||||
async getTelemetryPath(identifier, telemetryIdentifier) {
|
||||
const objectDetails = await this.get(identifier);
|
||||
const telemetryPath = [];
|
||||
if (objectDetails.composition && !['folder'].includes(objectDetails.type)) {
|
||||
let sourceTelemetry = objectDetails.composition[0];
|
||||
if (telemetryIdentifier) {
|
||||
sourceTelemetry = objectDetails.composition.find(
|
||||
(telemetrySource) =>
|
||||
this.makeKeyString(telemetrySource) === this.makeKeyString(telemetryIdentifier)
|
||||
);
|
||||
}
|
||||
const compositionElement = await this.get(sourceTelemetry);
|
||||
if (!['yamcs.telemetry', 'generator'].includes(compositionElement.type)) {
|
||||
return telemetryPath;
|
||||
}
|
||||
const telemetryKey = compositionElement.identifier.key;
|
||||
const telemetryPathObjects = await this.getOriginalPath(telemetryKey);
|
||||
telemetryPathObjects.forEach((pathObject) => {
|
||||
if (pathObject.type === 'root') {
|
||||
return;
|
||||
}
|
||||
telemetryPath.unshift(pathObject.name);
|
||||
});
|
||||
}
|
||||
return telemetryPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a domain object. Internal to ObjectAPI, won't call save after.
|
||||
* @private
|
||||
|
||||
73
src/api/tooltips/ToolTip.js
Normal file
73
src/api/tooltips/ToolTip.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************
|
||||
* 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 TooltipComponent from './components/TooltipComponent.vue';
|
||||
import EventEmitter from 'EventEmitter';
|
||||
import Vue from 'vue';
|
||||
|
||||
class Tooltip extends EventEmitter {
|
||||
constructor(
|
||||
{ toolTipText, toolTipLocation, parentElement } = {
|
||||
tooltipText: '',
|
||||
toolTipLocation: 'below',
|
||||
parentElement: null
|
||||
}
|
||||
) {
|
||||
super();
|
||||
|
||||
this.container = document.createElement('div');
|
||||
|
||||
this.component = new Vue({
|
||||
components: {
|
||||
TooltipComponent: TooltipComponent
|
||||
},
|
||||
provide: {
|
||||
toolTipText,
|
||||
toolTipLocation,
|
||||
parentElement
|
||||
},
|
||||
template: '<tooltip-component toolTipText="toolTipText"></tooltip-component>'
|
||||
});
|
||||
|
||||
this.isActive = null;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (!this.isActive) {
|
||||
return;
|
||||
}
|
||||
document.body.removeChild(this.container);
|
||||
this.component.$destroy();
|
||||
this.isActive = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
**/
|
||||
show() {
|
||||
document.body.appendChild(this.container);
|
||||
this.container.appendChild(this.component.$mount().$el);
|
||||
this.isActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
export default Tooltip;
|
||||
90
src/api/tooltips/ToolTipAPI.js
Normal file
90
src/api/tooltips/ToolTipAPI.js
Normal file
@@ -0,0 +1,90 @@
|
||||
/*****************************************************************************
|
||||
* 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 Tooltip from './ToolTip';
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @enum {String} TooltipLocation
|
||||
* @property {String} ABOVE The string for locating tooltips above an element
|
||||
* @property {String} BELOW The string for locating tooltips below an element
|
||||
* @property {String} RIGHT The pixel-spatial annotation type
|
||||
* @property {String} LEFT The temporal annotation type
|
||||
* @property {String} CENTER The plot-spatial annotation type
|
||||
*/
|
||||
const TOOLTIP_LOCATIONS = Object.freeze({
|
||||
ABOVE: 'above',
|
||||
BELOW: 'below',
|
||||
RIGHT: 'right',
|
||||
LEFT: 'left',
|
||||
CENTER: 'center'
|
||||
});
|
||||
|
||||
/**
|
||||
* The TooltipAPI is responsible for adding custom tooltips to
|
||||
* the desired elements on the screen
|
||||
*
|
||||
* @memberof api/tooltips
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
class TooltipAPI {
|
||||
constructor() {
|
||||
this.activeToolTips = [];
|
||||
this.TOOLTIP_LOCATIONS = TOOLTIP_LOCATIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private for platform-internal use
|
||||
*/
|
||||
showTooltip(tooltip) {
|
||||
for (let i = this.activeToolTips.length - 1; i > -1; i--) {
|
||||
this.activeToolTips[i].destroy();
|
||||
this.activeToolTips.splice(i, 1);
|
||||
}
|
||||
this.activeToolTips.push(tooltip);
|
||||
|
||||
tooltip.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of option properties that can be passed into the tooltip
|
||||
* @typedef {Object} TooltipOptions
|
||||
* @property {string} tooltipText text to show in the tooltip
|
||||
* @property {TOOLTIP_LOCATIONS} tooltipLocation location to show the tooltip relative to the parentElement
|
||||
* @property {HTMLElement} parentElement reference to the DOM node we're adding the tooltip to
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tooltips take an options object that consists of the string, tooltipLocation, and parentElement
|
||||
* @param {TooltipOptions} options
|
||||
*/
|
||||
tooltip(options) {
|
||||
let tooltip = new Tooltip(options);
|
||||
|
||||
this.showTooltip(tooltip);
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
}
|
||||
|
||||
export default TooltipAPI;
|
||||
61
src/api/tooltips/components/TooltipComponent.vue
Normal file
61
src/api/tooltips/components/TooltipComponent.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<template>
|
||||
<div ref="tooltip-wrapper" class="c-menu c-tooltip-wrapper" :style="toolTipLocationStyle">
|
||||
<div class="c-tooltip">
|
||||
{{ toolTipText }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['toolTipText', 'toolTipLocation', 'parentElement'],
|
||||
computed: {
|
||||
toolTipCoordinates() {
|
||||
return this.parentElement.getBoundingClientRect();
|
||||
},
|
||||
toolTipLocationStyle() {
|
||||
const { top, left, height, width } = this.toolTipCoordinates;
|
||||
let toolTipLocationStyle = {};
|
||||
|
||||
if (this.toolTipLocation === 'above') {
|
||||
toolTipLocationStyle = { top: `${top - 5}px`, left: `${left}px` };
|
||||
}
|
||||
if (this.toolTipLocation === 'below') {
|
||||
toolTipLocationStyle = { top: `${top + height}px`, left: `${left}px` };
|
||||
}
|
||||
if (this.toolTipLocation === 'right') {
|
||||
toolTipLocationStyle = { top: `${top}px`, left: `${left + width}px` };
|
||||
}
|
||||
if (this.toolTipLocation === 'left') {
|
||||
toolTipLocationStyle = { top: `${top}px`, left: `${left - width}px` };
|
||||
}
|
||||
if (this.toolTipLocation === 'center') {
|
||||
toolTipLocationStyle = { top: `${top + height / 2}px`, left: `${left + width / 2}px` };
|
||||
}
|
||||
|
||||
return toolTipLocationStyle;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
8
src/api/tooltips/components/tooltip-component.scss
Normal file
8
src/api/tooltips/components/tooltip-component.scss
Normal file
@@ -0,0 +1,8 @@
|
||||
.c-tooltip-wrapper {
|
||||
max-width: 200px;
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
|
||||
.c-tooltip {
|
||||
font-style: italic;
|
||||
}
|
||||
72
src/api/tooltips/tooltipMixins.js
Normal file
72
src/api/tooltips/tooltipMixins.js
Normal file
@@ -0,0 +1,72 @@
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
const tooltipHelpers = {
|
||||
methods: {
|
||||
async getTelemetryPathString(telemetryIdentifier) {
|
||||
let telemetryPathString = '';
|
||||
if (!this.domainObject?.identifier) {
|
||||
return;
|
||||
}
|
||||
const telemetryPath = await this.openmct.objects.getTelemetryPath(
|
||||
this.domainObject.identifier,
|
||||
telemetryIdentifier
|
||||
);
|
||||
if (telemetryPath.length) {
|
||||
telemetryPathString = telemetryPath.join(' / ');
|
||||
}
|
||||
return telemetryPathString;
|
||||
},
|
||||
async getObjectPath(objectIdentifier) {
|
||||
if (!objectIdentifier && !this.domainObject) {
|
||||
return;
|
||||
}
|
||||
const domainObjectIdentifier = objectIdentifier || this.domainObject.identifier;
|
||||
const objectPathList = await this.openmct.objects.getOriginalPath(domainObjectIdentifier);
|
||||
objectPathList.pop();
|
||||
return objectPathList
|
||||
.map((pathItem) => pathItem.name)
|
||||
.reverse()
|
||||
.join(' / ');
|
||||
},
|
||||
buildToolTip(tooltipText, tooltipLocation, elementRef) {
|
||||
if (!tooltipText || tooltipText.length < 1) {
|
||||
return;
|
||||
}
|
||||
let parentElement = this.$refs[elementRef];
|
||||
if (Array.isArray(parentElement)) {
|
||||
parentElement = parentElement[0];
|
||||
}
|
||||
this.tooltip = this.openmct.tooltips.tooltip({
|
||||
toolTipText: tooltipText,
|
||||
toolTipLocation: tooltipLocation,
|
||||
parentElement: parentElement
|
||||
});
|
||||
},
|
||||
hideToolTip() {
|
||||
this.tooltip?.destroy();
|
||||
this.tooltip = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default tooltipHelpers;
|
||||
@@ -26,7 +26,14 @@
|
||||
@click="clickedRow"
|
||||
@contextmenu.prevent="showContextMenu"
|
||||
>
|
||||
<td class="js-first-data">{{ domainObject.name }}</td>
|
||||
<td
|
||||
ref="tableCell"
|
||||
class="js-first-data"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
{{ domainObject.name }}
|
||||
</td>
|
||||
<td v-if="showTimestamp" class="js-second-data">{{ formattedTimestamp }}</td>
|
||||
<td class="js-third-data" :class="valueClasses">{{ value }}</td>
|
||||
<td v-if="hasUnits" class="js-units">
|
||||
@@ -42,8 +49,10 @@ const BLANK_VALUE = '---';
|
||||
|
||||
import identifierToString from '/src/tools/url';
|
||||
import PreviewAction from '@/ui/preview/PreviewAction.js';
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
|
||||
export default {
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct', 'currentView'],
|
||||
props: {
|
||||
domainObject: {
|
||||
@@ -259,6 +268,10 @@ export default {
|
||||
return metadata
|
||||
.values()
|
||||
.find((metadatum) => metadatum.hints.domain === undefined && metadatum.key !== 'name');
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(), BELOW, 'tableCell');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -264,7 +264,7 @@ describe('The LAD Table', () => {
|
||||
});
|
||||
|
||||
it('should show the name provided for the the telemetry producing object', () => {
|
||||
const rowName = parent.querySelector(TABLE_BODY_FIRST_ROW_FIRST_DATA).innerText;
|
||||
const rowName = parent.querySelector(TABLE_BODY_FIRST_ROW_FIRST_DATA).innerText.trim();
|
||||
|
||||
const expectedName = mockObj.telemetry.name;
|
||||
expect(rowName).toBe(expectedName);
|
||||
|
||||
@@ -21,7 +21,12 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div ref="conditionWidgetElement" class="c-condition-widget u-style-receiver js-style-receiver">
|
||||
<div
|
||||
ref="conditionWidgetElement"
|
||||
class="c-condition-widget u-style-receiver js-style-receiver"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
<component :is="urlDefined ? 'a' : 'div'" class="c-condition-widget__label-wrapper" :href="url">
|
||||
<div class="c-condition-widget__label">{{ label }}</div>
|
||||
</component>
|
||||
@@ -29,9 +34,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
const sanitizeUrl = require('@braintree/sanitize-url').sanitizeUrl;
|
||||
|
||||
export default {
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct', 'domainObject'],
|
||||
data: function () {
|
||||
return {
|
||||
@@ -116,6 +123,10 @@ export default {
|
||||
}
|
||||
|
||||
this.conditionalLabel = latestDatum.output || '';
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(), BELOW, 'conditionWidgetElement');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
<layout-frame
|
||||
:item="item"
|
||||
:grid-size="gridSize"
|
||||
:title="domainObject && domainObject.name"
|
||||
:is-editing="isEditing"
|
||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||
@endMove="() => $emit('endMove')"
|
||||
|
||||
@@ -30,12 +30,15 @@
|
||||
>
|
||||
<div
|
||||
v-if="domainObject"
|
||||
ref="telemetryViewWrapper"
|
||||
class="c-telemetry-view u-style-receiver"
|
||||
:class="[itemClasses]"
|
||||
:style="styleObject"
|
||||
:data-font-size="item.fontSize"
|
||||
:data-font="item.font"
|
||||
@contextmenu.prevent="showContextMenu"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
<div class="is-status__indicator" :title="`This item is ${status}`"></div>
|
||||
<div v-if="showLabel" class="c-telemetry-view__label">
|
||||
@@ -69,6 +72,7 @@ import {
|
||||
getDefaultNotebook,
|
||||
getNotebookSectionAndPage
|
||||
} from '@/plugins/notebook/utils/notebook-storage.js';
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
|
||||
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5];
|
||||
const DEFAULT_POSITION = [1, 1];
|
||||
@@ -97,7 +101,7 @@ export default {
|
||||
components: {
|
||||
LayoutFrame
|
||||
},
|
||||
mixins: [conditionalStylesMixin, stalenessMixin],
|
||||
mixins: [conditionalStylesMixin, stalenessMixin, tooltipHelpers],
|
||||
inject: ['openmct', 'objectPath', 'currentView'],
|
||||
props: {
|
||||
item: {
|
||||
@@ -379,6 +383,10 @@ export default {
|
||||
},
|
||||
setStatus(status) {
|
||||
this.status = status;
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(), BELOW, 'telemetryViewWrapper');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,7 +22,13 @@
|
||||
<template>
|
||||
<div class="c-gauge__wrapper js-gauge-wrapper" :class="gaugeClasses" :title="gaugeTitle">
|
||||
<template v-if="typeDial">
|
||||
<svg class="c-gauge c-dial" viewBox="0 0 10 10">
|
||||
<svg
|
||||
ref="gauge"
|
||||
class="c-gauge c-dial"
|
||||
viewBox="0 0 10 10"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
<g class="c-dial__masks">
|
||||
<mask id="gaugeValueMask">
|
||||
<path
|
||||
@@ -325,13 +331,14 @@
|
||||
<script>
|
||||
import { DIAL_VALUE_DEG_OFFSET, getLimitDegree } from '../gauge-limit-util';
|
||||
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
|
||||
const LIMIT_PADDING_IN_PERCENT = 10;
|
||||
const DEFAULT_CURRENT_VALUE = '--';
|
||||
|
||||
export default {
|
||||
name: 'Gauge',
|
||||
mixins: [stalenessMixin],
|
||||
mixins: [stalenessMixin, tooltipHelpers],
|
||||
inject: ['openmct', 'domainObject', 'composition'],
|
||||
data() {
|
||||
let gaugeController = this.domainObject.configuration.gaugeController;
|
||||
@@ -730,6 +737,10 @@ export default {
|
||||
},
|
||||
valToPercentMeter(vValue) {
|
||||
return this.round(((this.rangeHigh - vValue) / (this.rangeHigh - this.rangeLow)) * 100, 2);
|
||||
},
|
||||
async showToolTip() {
|
||||
const { CENTER } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getTelemetryPathString(), CENTER, 'gauge');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,7 +20,12 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<template>
|
||||
<div class="c-snapshot c-ne__embed">
|
||||
<div
|
||||
ref="notebookEmbed"
|
||||
class="c-snapshot c-ne__embed"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
<div v-if="embed.snapshot" class="c-ne__embed__snap-thumb" @click="openSnapshot()">
|
||||
<img :src="thumbnailImage" />
|
||||
</div>
|
||||
@@ -49,6 +54,7 @@ import RemoveDialog from '../utils/removeDialog';
|
||||
import PainterroInstance from '../utils/painterroInstance';
|
||||
import SnapshotTemplate from './snapshot-template.html';
|
||||
import objectPathToUrl from '@/tools/url';
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
|
||||
import { updateNotebookImageDomainObject } from '../utils/notebook-image';
|
||||
import ImageExporter from '../../../exporters/ImageExporter';
|
||||
@@ -56,6 +62,7 @@ import ImageExporter from '../../../exporters/ImageExporter';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default {
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct', 'snapshotContainer'],
|
||||
props: {
|
||||
embed: {
|
||||
@@ -404,6 +411,14 @@ export default {
|
||||
snapshotObject.fullSizeImage
|
||||
);
|
||||
}
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(
|
||||
await this.getObjectPath(this.embed.domainObject.identifier),
|
||||
BELOW,
|
||||
'notebookEmbed'
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,7 +29,12 @@
|
||||
@mouseover="toggleHover(true)"
|
||||
@mouseleave="toggleHover(false)"
|
||||
>
|
||||
<div class="plot-series-swatch-and-name">
|
||||
<div
|
||||
ref="series"
|
||||
class="plot-series-swatch-and-name"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
<span class="plot-series-color-swatch" :style="{ 'background-color': colorAsHexString }">
|
||||
</span>
|
||||
<span class="is-status__indicator" title="This item is missing or suspect"></span>
|
||||
@@ -59,9 +64,10 @@ import { getLimitClass } from '@/plugins/plot/chart/limitUtil';
|
||||
import eventHelpers from '../lib/eventHelpers';
|
||||
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
||||
import configStore from '../configuration/ConfigStore';
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
|
||||
export default {
|
||||
mixins: [stalenessMixin],
|
||||
mixins: [stalenessMixin, tooltipHelpers],
|
||||
inject: ['openmct', 'domainObject'],
|
||||
props: {
|
||||
seriesObject: {
|
||||
@@ -189,6 +195,14 @@ export default {
|
||||
}
|
||||
: undefined
|
||||
);
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(
|
||||
await this.getTelemetryPathString(this.seriesObject.domainObject.identifier),
|
||||
BELOW,
|
||||
'series'
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -33,7 +33,14 @@
|
||||
<span class="plot-series-color-swatch" :style="{ 'background-color': colorAsHexString }">
|
||||
</span>
|
||||
<span class="is-status__indicator" title="This item is missing or suspect"></span>
|
||||
<span class="plot-series-name">{{ name }}</span>
|
||||
<span
|
||||
ref="seriesName"
|
||||
class="plot-series-name"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
{{ name }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td v-if="showTimestampWhenExpanded">
|
||||
@@ -72,9 +79,10 @@ import { getLimitClass } from '@/plugins/plot/chart/limitUtil';
|
||||
import eventHelpers from '@/plugins/plot/lib/eventHelpers';
|
||||
import stalenessMixin from '@/ui/mixins/staleness-mixin';
|
||||
import configStore from '../configuration/ConfigStore';
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
|
||||
export default {
|
||||
mixins: [stalenessMixin],
|
||||
mixins: [stalenessMixin, tooltipHelpers],
|
||||
inject: ['openmct', 'domainObject'],
|
||||
props: {
|
||||
seriesObject: {
|
||||
@@ -205,6 +213,14 @@ export default {
|
||||
this.$emit('legendHoverChanged', {
|
||||
seriesKey: this.hover ? this.seriesObject.keyString : ''
|
||||
});
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(
|
||||
await this.getTelemetryPathString(this.seriesObject.domainObject.identifier),
|
||||
BELOW,
|
||||
'seriesName'
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -35,12 +35,15 @@
|
||||
</div>
|
||||
<div
|
||||
v-for="(tab, index) in tabsList"
|
||||
:ref="tab.keyString"
|
||||
:key="tab.keyString"
|
||||
class="c-tab c-tabs-view__tab js-tab"
|
||||
:class="{
|
||||
'is-current': isCurrent(tab)
|
||||
}"
|
||||
@click="showTab(tab, index)"
|
||||
@mouseover.ctrl="showToolTip(tab)"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
<div
|
||||
ref="tabsLabel"
|
||||
@@ -79,6 +82,7 @@
|
||||
<script>
|
||||
import ObjectView from '../../../ui/components/ObjectView.vue';
|
||||
import RemoveAction from '../../remove/RemoveAction.js';
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
import _ from 'lodash';
|
||||
|
||||
const unknownObjectType = {
|
||||
@@ -92,6 +96,7 @@ export default {
|
||||
components: {
|
||||
ObjectView
|
||||
},
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct', 'domainObject', 'composition', 'objectPath'],
|
||||
props: {
|
||||
isEditing: {
|
||||
@@ -389,6 +394,11 @@ export default {
|
||||
|
||||
this.tabWidth = this.$refs.tabs.offsetWidth + 'px';
|
||||
this.tabHeight = this.$refs.tabsHolder.offsetHeight - this.$refs.tabs.offsetHeight + 'px';
|
||||
},
|
||||
async showToolTip(tab) {
|
||||
const identifier = tab.domainObject.identifier;
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(identifier), BELOW, tab.keyString);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,13 +20,22 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<template>
|
||||
<td :title="formattedValue" @click="selectCell($event.currentTarget, columnKey)">
|
||||
<td
|
||||
ref="tableCell"
|
||||
:title="formattedValue"
|
||||
@click="selectCell($event.currentTarget, columnKey)"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
{{ formattedValue }}
|
||||
</td>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
|
||||
export default {
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
row: {
|
||||
@@ -76,6 +85,13 @@ export default {
|
||||
);
|
||||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
async showToolTip() {
|
||||
if (this.columnKey !== 'name') {
|
||||
return;
|
||||
}
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(this.row.objectKeyString), BELOW, 'tableCell');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
:min-height="item.height"
|
||||
:show-ucontents="isPlanLikeObject(item.domainObject)"
|
||||
:span-rows-count="item.rowCount"
|
||||
:domain-object="item.domainObject"
|
||||
>
|
||||
<template #label>
|
||||
{{ item.domainObject.name }}
|
||||
|
||||
@@ -578,7 +578,6 @@ select {
|
||||
&.is-current {
|
||||
background: $colorTabCurrentBg;
|
||||
color: $colorTabCurrentFg;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@import '../api/overlays/components/dialog-component.scss';
|
||||
@import '../api/overlays/components/overlay-component.scss';
|
||||
@import '../api/tooltips/components/tooltip-component.scss';
|
||||
@import '../plugins/condition/components/conditionals.scss';
|
||||
@import '../plugins/conditionWidget/components/condition-widget.scss';
|
||||
@import '../plugins/condition/components/inspector/conditional-styles.scss';
|
||||
|
||||
@@ -38,7 +38,12 @@
|
||||
<div class="c-object-label__type-icon" :class="cssClass">
|
||||
<span class="is-status__indicator" :title="`This item is ${status}`"></span>
|
||||
</div>
|
||||
<div class="c-object-label__name">
|
||||
<div
|
||||
ref="objectName"
|
||||
class="c-object-label__name"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
{{ domainObject && domainObject.name }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,6 +96,7 @@
|
||||
<script>
|
||||
import ObjectView from './ObjectView.vue';
|
||||
import NotebookMenuSwitcher from '@/plugins/notebook/components/NotebookMenuSwitcher.vue';
|
||||
import tooltipHelpers from '../../api/tooltips/tooltipMixins';
|
||||
|
||||
const SIMPLE_CONTENT_TYPES = ['clock', 'timer', 'summary-widget', 'hyperlink', 'conditionWidget'];
|
||||
const CSS_WIDTH_LESS_STR = '--width-less-than-';
|
||||
@@ -100,6 +106,7 @@ export default {
|
||||
ObjectView,
|
||||
NotebookMenuSwitcher
|
||||
},
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
domainObject: {
|
||||
@@ -225,6 +232,10 @@ export default {
|
||||
}
|
||||
|
||||
this.widthClass = wClass.trimStart();
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(), BELOW, 'objectName');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,7 +30,12 @@
|
||||
<div class="c-tree__item__type-icon c-object-label__type-icon" :class="typeClass">
|
||||
<span class="is-status__indicator" :title="`This item is ${status}`"></span>
|
||||
</div>
|
||||
<div class="c-tree__item__name c-object-label__name">
|
||||
<div
|
||||
ref="objectLabel"
|
||||
class="c-tree__item__name c-object-label__name"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
{{ domainObject.name }}
|
||||
</div>
|
||||
</a>
|
||||
@@ -40,9 +45,10 @@
|
||||
import ObjectLink from '../mixins/object-link';
|
||||
import ContextMenuGesture from '../mixins/context-menu-gesture';
|
||||
import PreviewAction from '../preview/PreviewAction.js';
|
||||
import tooltipHelpers from '../../api/tooltips/tooltipMixins';
|
||||
|
||||
export default {
|
||||
mixins: [ObjectLink, ContextMenuGesture],
|
||||
mixins: [ObjectLink, ContextMenuGesture, tooltipHelpers],
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
domainObject: {
|
||||
@@ -132,6 +138,10 @@ export default {
|
||||
},
|
||||
setStatus(status) {
|
||||
this.status = status;
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(), BELOW, 'objectLabel');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,7 +21,13 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="u-contents" :class="[{ 'c-swimlane': !isNested }, statusClass]">
|
||||
<div
|
||||
ref="swimLane"
|
||||
class="u-contents"
|
||||
:class="[{ 'c-swimlane': !isNested }, statusClass]"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
<div
|
||||
v-if="hideLabel === false"
|
||||
class="c-swimlane__lane-label c-object-label"
|
||||
@@ -47,7 +53,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
|
||||
export default {
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
@@ -96,6 +106,10 @@ export default {
|
||||
default() {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
domainObject: {
|
||||
type: Object,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -118,6 +132,12 @@ export default {
|
||||
statusClass() {
|
||||
return this.status ? `is-status--${this.status}` : '';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(), BELOW, 'swimLane');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -33,12 +33,15 @@
|
||||
<span class="is-status__indicator" :title="`This item is ${status}`"></span>
|
||||
</div>
|
||||
<span
|
||||
ref="objectName"
|
||||
class="l-browse-bar__object-name c-object-label__name"
|
||||
:class="{ 'c-input-inline': isPersistable }"
|
||||
:contenteditable="isPersistable"
|
||||
@blur="updateName"
|
||||
@keydown.enter.prevent
|
||||
@keyup.enter.prevent="updateNameOnEnterKeyPress"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
{{ domainObject.name }}
|
||||
</span>
|
||||
@@ -127,6 +130,7 @@
|
||||
<script>
|
||||
import ViewSwitcher from './ViewSwitcher.vue';
|
||||
import NotebookMenuSwitcher from '@/plugins/notebook/components/NotebookMenuSwitcher.vue';
|
||||
import tooltipHelpers from '../../api/tooltips/tooltipMixins';
|
||||
|
||||
const PLACEHOLDER_OBJECT = {};
|
||||
|
||||
@@ -135,6 +139,7 @@ export default {
|
||||
NotebookMenuSwitcher,
|
||||
ViewSwitcher
|
||||
},
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
actionCollection: {
|
||||
@@ -383,6 +388,10 @@ export default {
|
||||
},
|
||||
setStatus(status) {
|
||||
this.status = status;
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(), BELOW, 'objectName');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,11 +32,14 @@
|
||||
></div>
|
||||
<div class="c-recentobjects-listitem__body">
|
||||
<span
|
||||
ref="recentObjectName"
|
||||
class="c-recentobjects-listitem__title"
|
||||
:name="domainObject.name"
|
||||
draggable="true"
|
||||
@dragstart="dragStart"
|
||||
@click.prevent="clickedRecent"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
{{ domainObject.name }}
|
||||
</span>
|
||||
@@ -62,12 +65,14 @@
|
||||
<script>
|
||||
import ObjectPath from '../components/ObjectPath.vue';
|
||||
import PreviewAction from '../preview/PreviewAction';
|
||||
import tooltipHelpers from '../../api/tooltips/tooltipMixins';
|
||||
|
||||
export default {
|
||||
name: 'RecentObjectsListItem',
|
||||
components: {
|
||||
ObjectPath
|
||||
},
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
domainObject: {
|
||||
@@ -132,6 +137,10 @@ export default {
|
||||
},
|
||||
openAndScrollTo(navigationPath) {
|
||||
this.$emit('openAndScrollTo', navigationPath);
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(), BELOW, 'recentObjectName');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -33,11 +33,14 @@
|
||||
:aria-label="`${resultName} ${resultType} result`"
|
||||
>
|
||||
<div
|
||||
ref="resultName"
|
||||
class="c-gsearch-result__title"
|
||||
:name="resultName"
|
||||
draggable="true"
|
||||
@dragstart="dragStart"
|
||||
@click="clickedResult"
|
||||
@mouseover.ctrl="showToolTip"
|
||||
@mouseleave="hideToolTip"
|
||||
>
|
||||
{{ resultName }}
|
||||
</div>
|
||||
@@ -54,12 +57,14 @@
|
||||
import ObjectPath from '../../components/ObjectPath.vue';
|
||||
import identifierToString from '../../../tools/url';
|
||||
import PreviewAction from '../../preview/PreviewAction';
|
||||
import tooltipHelpers from '../../../api/tooltips/tooltipMixins';
|
||||
|
||||
export default {
|
||||
name: 'ObjectSearchResult',
|
||||
components: {
|
||||
ObjectPath
|
||||
},
|
||||
mixins: [tooltipHelpers],
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
result: {
|
||||
@@ -124,6 +129,10 @@ export default {
|
||||
|
||||
event.dataTransfer.setData('openmct/domain-object-path', serializedPath);
|
||||
event.dataTransfer.setData(`openmct/domain-object/${keyString}`, this.result);
|
||||
},
|
||||
async showToolTip() {
|
||||
const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS;
|
||||
this.buildToolTip(await this.getObjectPath(this.result.identifier), BELOW, 'resultName');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user