[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:
Khalid Adil 2023-07-13 23:37:59 -05:00 committed by GitHub
parent 795d7a7ec7
commit cde8fbbb0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 942 additions and 26 deletions

View File

@ -401,14 +401,7 @@ async function setEndOffset(page, offset) {
async function selectInspectorTab(page, name) {
const inspectorTabs = page.getByRole('tablist');
const inspectorTab = inspectorTabs.getByTitle(name);
const inspectorTabClass = await inspectorTab.getAttribute('class');
const isSelectedInspectorTab = inspectorTabClass.includes('is-current');
// do not click a tab that is already selected or it will timeout your test
// do to a { pointer-events: none; } on selected tabs
if (!isSelectedInspectorTab) {
await inspectorTab.click();
}
await inspectorTab.click();
}
/**

View File

@ -0,0 +1,398 @@
/*****************************************************************************
* 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 tests which can quickly verify that any openmct installation is
operable and that any type of testing can proceed.
Ideally, smoke tests should make zero assumptions about how and where they are run. This makes them
more resilient to change and therefor a better indicator of failure. Smoke tests will also run quickly
as they cover a very "thin surface" of functionality.
When deciding between authoring new smoke tests or functional tests, ask yourself "would I feel
comfortable running this test during a live mission?" Avoid creating or deleting Domain Objects.
Make no assumptions about the order that elements appear in the DOM.
*/
const { test, expect } = require('../../pluginFixtures');
const { createDomainObjectWithDefaults, expandEntireTree } = require('../../appActions');
test.describe('Verify tooltips', () => {
let folder1;
let folder2;
let folder3;
let sineWaveObject1;
let sineWaveObject2;
let sineWaveObject3;
const swg1Path = 'My Items / Folder Foo / SWG 1';
const swg2Path = 'My Items / Folder Foo / Folder Bar / SWG 2';
const swg3Path = 'My Items / Folder Foo / Folder Bar / Folder Baz / SWG 3';
test.beforeEach(async ({ page, openmctConfig }) => {
await page.goto('./', { waitUntil: 'domcontentloaded' });
folder1 = await createDomainObjectWithDefaults(page, {
type: 'Folder',
name: 'Folder Foo'
});
folder2 = await createDomainObjectWithDefaults(page, {
type: 'Folder',
name: 'Folder Bar',
parent: folder1.uuid
});
folder3 = await createDomainObjectWithDefaults(page, {
type: 'Folder',
name: 'Folder Baz',
parent: folder2.uuid
});
// Create Sine Wave Generator
sineWaveObject1 = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator',
name: 'SWG 1',
parent: folder1.uuid
});
sineWaveObject1.path = swg1Path;
sineWaveObject2 = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator',
name: 'SWG 2',
parent: folder2.uuid
});
sineWaveObject2.path = swg2Path;
sineWaveObject3 = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator',
name: 'SWG 3',
parent: folder3.uuid
});
sineWaveObject3.path = swg3Path;
// Expand all folders
await expandEntireTree(page);
});
// LAD Tables - DONE
// Expanded collapsed plot legend - DONE
// Object Labels - DONE
// Display Layout headers - DONE
// Flexible Layout headers - DONE
// Tab View layout headers - DONE
// Search - DONE
// Gauge -
// Notebook Embed - DONE
// Telemetry Table -
// Timeline Objects
// Tree - DONE
// Recent Objects
test('display correct paths for LAD tables', async ({ page, openmctConfig }) => {
// Create LAD table
await createDomainObjectWithDefaults(page, {
type: 'LAD Table',
name: 'Test LAD Table'
});
// Edit LAD table
await page.locator('[title="Edit"]').click();
// Add the Sine Wave Generator to the LAD table and save changes
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-lad-table-wrapper');
await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.c-lad-table-wrapper');
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-lad-table-wrapper');
await page.locator('button[title="Save"]').click();
await page.locator('text=Save and Finish Editing').click();
await page.keyboard.down('Control');
async function getToolTip(object) {
await page.locator('.c-create-button').hover();
await page.getByRole('cell', { name: object.name }).hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
return tooltipText.replace('\n', '').trim();
}
expect(await getToolTip(sineWaveObject1)).toBe(sineWaveObject1.path);
expect(await getToolTip(sineWaveObject2)).toBe(sineWaveObject2.path);
expect(await getToolTip(sineWaveObject3)).toBe(sineWaveObject3.path);
});
test('display correct paths for expanded and collapsed plot legend items', async ({ page }) => {
// Create Overlay Plot
await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot',
name: 'Test Overlay Plots'
});
// Edit Overlay Plot
await page.locator('[title="Edit"]').click();
// Add the Sine Wave Generator to the LAD table and save changes
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.gl-plot');
await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.gl-plot');
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.gl-plot');
await page.locator('button[title="Save"]').click();
await page.locator('text=Save and Finish Editing').click();
await page.keyboard.down('Control');
async function getCollapsedLegendToolTip(object) {
await page.locator('.c-create-button').hover();
await page
.locator('.plot-series-name', { has: page.locator(`text="${object.name} Hz"`) })
.hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
return tooltipText.replace('\n', '').trim();
}
async function getExpandedLegendToolTip(object) {
await page.locator('.c-create-button').hover();
await page
.locator('.plot-series-name', { has: page.locator(`text="${object.name}"`) })
.hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
return tooltipText.replace('\n', '').trim();
}
expect(await getCollapsedLegendToolTip(sineWaveObject1)).toBe(sineWaveObject1.path);
expect(await getCollapsedLegendToolTip(sineWaveObject2)).toBe(sineWaveObject2.path);
expect(await getCollapsedLegendToolTip(sineWaveObject3)).toBe(sineWaveObject3.path);
await page.keyboard.up('Control');
await page.locator('.gl-plot-legend__view-control.c-disclosure-triangle').click();
await page.keyboard.down('Control');
expect(await getExpandedLegendToolTip(sineWaveObject1)).toBe(sineWaveObject1.path);
expect(await getExpandedLegendToolTip(sineWaveObject2)).toBe(sineWaveObject2.path);
expect(await getExpandedLegendToolTip(sineWaveObject3)).toBe(sineWaveObject3.path);
});
test('display correct paths when hovering over object labels', async ({ page }) => {
async function getObjectLabelTooltip(object) {
await page
.locator('.c-tree__item__name.c-object-label__name', {
has: page.locator(`text="${object.name}"`)
})
.click();
await page.keyboard.down('Control');
await page
.locator('.l-browse-bar__object-name.c-object-label__name', {
has: page.locator(`text="${object.name}"`)
})
.hover();
const tooltipText = await page.locator('.c-tooltip').textContent();
await page.keyboard.up('Control');
return tooltipText.replace('\n', '').trim();
}
expect(await getObjectLabelTooltip(sineWaveObject1)).toBe(sineWaveObject1.path);
expect(await getObjectLabelTooltip(sineWaveObject3)).toBe(sineWaveObject3.path);
});
test('display correct paths when hovering over display layout pane headers', async ({ page }) => {
// Create Overlay Plot
await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot',
name: 'Test Overlay Plot'
});
// Edit Overlay Plot
await page.locator('[title="Edit"]').click();
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.gl-plot');
await page.locator('button[title="Save"]').click();
await page.locator('text=Save and Finish Editing').click();
// Create Stacked Plot
await createDomainObjectWithDefaults(page, {
type: 'Stacked Plot',
name: 'Test Stacked Plot'
});
// Edit Stacked Plot
await page.locator('[title="Edit"]').click();
await page.dragAndDrop(`text=${sineWaveObject2.name}`, '.c-plot--stacked.holder');
await page.locator('button[title="Save"]').click();
await page.locator('text=Save and Finish Editing').click();
// Create Display Layout
await createDomainObjectWithDefaults(page, {
type: 'Display Layout',
name: 'Test Display Layout'
});
// Edit Display Layout
await page.locator('[title="Edit"]').click();
await page.dragAndDrop("text='Test Overlay Plot'", '.l-layout__grid-holder', {
targetPosition: { x: 0, y: 0 }
});
await page.dragAndDrop("text='Test Stacked Plot'", '.l-layout__grid-holder', {
targetPosition: { x: 0, y: 250 }
});
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.l-layout__grid-holder', {
targetPosition: { x: 500, y: 200 }
});
await page.locator('button[title="Save"]').click();
await page.locator('text=Save and Finish Editing').click();
await page.keyboard.down('Control');
await page.getByText('Test Overlay Plot').nth(2).hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe('My Items / Test Overlay Plot');
// await page.keyboard.up('Control');
// await page.locator('.c-plot-legend__view-control >> nth=0').click();
// await page.keyboard.down('Control');
// await page.locator('.plot-wrapper-expanded-legend .plot-series-name').first().hover();
// tooltipText = await page.locator('.c-tooltip').textContent();
// tooltipText = tooltipText.replace('\n', '').trim();
// expect(tooltipText).toBe(sineWaveObject1.path);
await page.getByText('Test Stacked Plot').nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe('My Items / Test Stacked Plot');
await page.getByText('SWG 3').nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(sineWaveObject3.path).toBe(tooltipText);
});
test('display correct paths when hovering over flexible object labels', async ({ page }) => {
await createDomainObjectWithDefaults(page, {
type: 'Flexible Layout',
name: 'Test Flexible Layout'
});
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-fl__container >> nth=0');
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-fl__container >> nth=1');
await page.locator('button[title="Save"]').click();
await page.locator('text=Save and Finish Editing').click();
await page.keyboard.down('Control');
await page.getByText('SWG 1').nth(2).hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject1.path);
await page.getByText('SWG 3').nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
});
test('display correct paths when hovering over tab view labels', async ({ page }) => {
await createDomainObjectWithDefaults(page, {
type: 'Tabs View',
name: 'Test Tabs View'
});
await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-tabs-view__tabs-holder');
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-tabs-view__tabs-holder');
await page.locator('button[title="Save"]').click();
await page.locator('text=Save and Finish Editing').click();
await page.keyboard.down('Control');
await page.getByText('SWG 1').nth(2).hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject1.path);
await page.getByText('SWG 3').nth(2).hover();
tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
});
test('display correct paths when hovering tree items', async ({ page }) => {
await page.keyboard.down('Control');
await page.getByText('SWG 1').nth(0).hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject1.path);
await page.getByText('SWG 3').nth(0).hover();
tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
});
test('display correct paths when hovering search items', async ({ page }) => {
await page.getByRole('searchbox', { name: 'Search Input' }).click();
await page.fill('.c-search__input', 'SWG 3');
await page.keyboard.down('Control');
await page.locator('.c-gsearch-result__title').hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
});
test('display path for source telemetry when hovering over gauge', ({ page }) => {
expect(true).toBe(true);
// await createDomainObjectWithDefaults(page, {
// type: 'Gauge',
// name: 'Test Gauge'
// });
// await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-gauge__wrapper');
// await page.keyboard.down('Control');
// await page.locator('.c-gauge__current-value-text-wrapper').hover();
// let tooltipText = await page.locator('.c-tooltip').textContent();
// tooltipText = tooltipText.replace('\n', '').trim();
// expect(tooltipText).toBe(sineWaveObject3.path);
});
test('display tooltip path for notebook embeds', async ({ page }) => {
await createDomainObjectWithDefaults(page, {
type: 'Notebook',
name: 'Test Notebook'
});
await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-notebook__drag-area');
await page.keyboard.down('Control');
await page.locator('.c-ne__embed').hover();
let tooltipText = await page.locator('.c-tooltip').textContent();
tooltipText = tooltipText.replace('\n', '').trim();
expect(tooltipText).toBe(sineWaveObject3.path);
});
// test('display tooltip path for telemetry table names', async ({ page }) => {
// await setEndOffset(page, { secs: '10' });
// await createDomainObjectWithDefaults(page, {
// type: 'Telemetry Table',
// name: 'Test Telemetry Table'
// });
// await page.dragAndDrop(`text=${sineWaveObject1.name}`, '.c-telemetry-table');
// await page.dragAndDrop(`text=${sineWaveObject3.name}`, '.c-telemetry-table');
// await page.locator('button[title="Save"]').click();
// await page.locator('text=Save and Finish Editing').click();
// // .c-telemetry-table__body
// await page.keyboard.down('Control');
// await page.locator('.noselect > [title="SWG 3"]').first().hover();
// let tooltipText = await page.locator('.c-tooltip').textContent();
// tooltipText = tooltipText.replace('\n', '').trim();
// expect(tooltipText).toBe(sineWaveObject3.path);
// });
});

View File

@ -56,6 +56,7 @@ if (document.currentScript) {
* @property {import('./src/api/notifications/NotificationAPI').default} notifications
* @property {import('./src/api/Editor').default} editor
* @property {import('./src/api/overlays/OverlayAPI')} overlays
* @property {import('./src/api/tooltips/ToolTipAPI')} tooltips
* @property {import('./src/api/menu/MenuAPI').default} menus
* @property {import('./src/api/actions/ActionsAPI').default} actions
* @property {import('./src/api/status/StatusAPI').default} status

View File

@ -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)],

View File

@ -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

View 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;

View 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;

View 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>

View File

@ -0,0 +1,8 @@
.c-tooltip-wrapper {
max-width: 200px;
padding: $interiorMargin;
}
.c-tooltip {
font-style: italic;
}

View 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;

View File

@ -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');
}
}
};

View File

@ -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);

View File

@ -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');
}
}
};

View File

@ -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')"

View File

@ -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');
}
}
};

View File

@ -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');
}
}
};

View File

@ -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'
);
}
}
};

View File

@ -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'
);
}
}
};

View File

@ -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'
);
}
}
};

View File

@ -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);
}
}
};

View File

@ -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');
}
}
};

View File

@ -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 }}

View File

@ -578,7 +578,6 @@ select {
&.is-current {
background: $colorTabCurrentBg;
color: $colorTabCurrentFg;
pointer-events: none;
}
}

View File

@ -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';

View File

@ -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');
}
}
};

View File

@ -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');
}
}
};

View File

@ -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>

View File

@ -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');
}
}
};

View File

@ -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');
}
}
};

View File

@ -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');
}
}
};