mirror of
https://github.com/ansible/awx.git
synced 2026-03-13 23:17:32 -02:30
Add tooltips to inventory sync status
Add tooltips to inventory sync status on Inventory List. See: https://github.com/ansible/awx/issues/7676
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import 'styled-components/macro';
|
import 'styled-components/macro';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { oneOf } from 'prop-types';
|
import { oneOf } from 'prop-types';
|
||||||
import { Label } from '@patternfly/react-core';
|
import { Label, Tooltip } from '@patternfly/react-core';
|
||||||
import {
|
import {
|
||||||
CheckCircleIcon,
|
CheckCircleIcon,
|
||||||
ExclamationCircleIcon,
|
ExclamationCircleIcon,
|
||||||
@@ -48,15 +48,19 @@ const icons = {
|
|||||||
canceled: ExclamationTriangleIcon,
|
canceled: ExclamationTriangleIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function StatusLabel({ status }) {
|
export default function StatusLabel({ status, tooltipContent = '' }) {
|
||||||
const label = status.charAt(0).toUpperCase() + status.slice(1);
|
const label = status.charAt(0).toUpperCase() + status.slice(1);
|
||||||
const color = colors[status] || 'grey';
|
const color = colors[status] || 'grey';
|
||||||
const Icon = icons[status];
|
const Icon = icons[status];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Label variant="outline" color={color} icon={Icon ? <Icon /> : null}>
|
<>
|
||||||
{label}
|
<Tooltip content={tooltipContent} position="top">
|
||||||
</Label>
|
<Label variant="outline" color={color} icon={Icon ? <Icon /> : null}>
|
||||||
|
{label}
|
||||||
|
</Label>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,19 @@ function InventoryListItem({
|
|||||||
inventory.inventory_sources_with_failures > 0 ? 'error' : 'success';
|
inventory.inventory_sources_with_failures > 0 ? 'error' : 'success';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let tooltipContent = '';
|
||||||
|
if (inventory.has_inventory_sources) {
|
||||||
|
if (inventory.inventory_sources_with_failures > 0) {
|
||||||
|
tooltipContent = i18n._(
|
||||||
|
t`${inventory.inventory_sources_with_failures} sources with sync failures.`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
tooltipContent = i18n._(t`No inventory sync failures.`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tooltipContent = i18n._(t`Not configured for inventory sync.`);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tr id={inventory.id} aria-labelledby={labelId}>
|
<Tr id={inventory.id} aria-labelledby={labelId}>
|
||||||
<Td
|
<Td
|
||||||
@@ -75,7 +88,9 @@ function InventoryListItem({
|
|||||||
)}
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td dataLabel={i18n._(t`Status`)}>
|
<Td dataLabel={i18n._(t`Status`)}>
|
||||||
{inventory.kind !== 'smart' && <StatusLabel status={syncStatus} />}
|
{inventory.kind !== 'smart' && (
|
||||||
|
<StatusLabel status={syncStatus} tooltipContent={tooltipContent} />
|
||||||
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td dataLabel={i18n._(t`Type`)}>
|
<Td dataLabel={i18n._(t`Type`)}>
|
||||||
{inventory.kind === 'smart'
|
{inventory.kind === 'smart'
|
||||||
|
|||||||
@@ -7,24 +7,33 @@ import InventoryListItem from './InventoryListItem';
|
|||||||
jest.mock('../../../api/models/Inventories');
|
jest.mock('../../../api/models/Inventories');
|
||||||
|
|
||||||
describe('<InventoryListItem />', () => {
|
describe('<InventoryListItem />', () => {
|
||||||
test('initially renders succesfully', () => {
|
const inventory = {
|
||||||
|
id: 1,
|
||||||
|
name: 'Inventory',
|
||||||
|
kind: '',
|
||||||
|
has_active_failures: true,
|
||||||
|
total_hosts: 10,
|
||||||
|
hosts_with_active_failures: 4,
|
||||||
|
has_inventory_sources: true,
|
||||||
|
total_inventory_sources: 4,
|
||||||
|
inventory_sources_with_failures: 5,
|
||||||
|
summary_fields: {
|
||||||
|
organization: {
|
||||||
|
id: 1,
|
||||||
|
name: 'Default',
|
||||||
|
},
|
||||||
|
user_capabilities: {
|
||||||
|
edit: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
test('initially renders successfully', () => {
|
||||||
mountWithContexts(
|
mountWithContexts(
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<InventoryListItem
|
<InventoryListItem
|
||||||
inventory={{
|
inventory={inventory}
|
||||||
id: 1,
|
|
||||||
name: 'Inventory',
|
|
||||||
summary_fields: {
|
|
||||||
organization: {
|
|
||||||
id: 1,
|
|
||||||
name: 'Default',
|
|
||||||
},
|
|
||||||
user_capabilities: {
|
|
||||||
edit: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
detailUrl="/inventories/inventory/1"
|
detailUrl="/inventories/inventory/1"
|
||||||
isSelected
|
isSelected
|
||||||
onSelect={() => {}}
|
onSelect={() => {}}
|
||||||
@@ -34,25 +43,50 @@ describe('<InventoryListItem />', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should render not configured tooltip', () => {
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<InventoryListItem
|
||||||
|
inventory={{ ...inventory, has_inventory_sources: false }}
|
||||||
|
detailUrl="/inventories/inventory/1"
|
||||||
|
isSelected
|
||||||
|
onSelect={() => {}}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(wrapper.find('StatusLabel').prop('tooltipContent')).toBe(
|
||||||
|
'Not configured for inventory sync.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render success tooltip', () => {
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<InventoryListItem
|
||||||
|
inventory={{ ...inventory, inventory_sources_with_failures: 0 }}
|
||||||
|
detailUrl="/inventories/inventory/1"
|
||||||
|
isSelected
|
||||||
|
onSelect={() => {}}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(wrapper.find('StatusLabel').prop('tooltipContent')).toBe(
|
||||||
|
'No inventory sync failures.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('should render prompt list item data', () => {
|
test('should render prompt list item data', () => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<InventoryListItem
|
<InventoryListItem
|
||||||
inventory={{
|
inventory={inventory}
|
||||||
id: 1,
|
|
||||||
name: 'Inventory',
|
|
||||||
kind: '',
|
|
||||||
summary_fields: {
|
|
||||||
organization: {
|
|
||||||
id: 1,
|
|
||||||
name: 'Default',
|
|
||||||
},
|
|
||||||
user_capabilities: {
|
|
||||||
edit: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
detailUrl="/inventories/inventory/1"
|
detailUrl="/inventories/inventory/1"
|
||||||
isSelected
|
isSelected
|
||||||
onSelect={() => {}}
|
onSelect={() => {}}
|
||||||
@@ -61,6 +95,9 @@ describe('<InventoryListItem />', () => {
|
|||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
expect(wrapper.find('StatusLabel').length).toBe(1);
|
expect(wrapper.find('StatusLabel').length).toBe(1);
|
||||||
|
expect(wrapper.find('StatusLabel').prop('tooltipContent')).toBe(
|
||||||
|
`${inventory.inventory_sources_with_failures} sources with sync failures.`
|
||||||
|
);
|
||||||
expect(
|
expect(
|
||||||
wrapper
|
wrapper
|
||||||
.find('Td')
|
.find('Td')
|
||||||
@@ -72,7 +109,7 @@ describe('<InventoryListItem />', () => {
|
|||||||
.find('Td')
|
.find('Td')
|
||||||
.at(2)
|
.at(2)
|
||||||
.text()
|
.text()
|
||||||
).toBe('Disabled');
|
).toBe('Error');
|
||||||
expect(
|
expect(
|
||||||
wrapper
|
wrapper
|
||||||
.find('Td')
|
.find('Td')
|
||||||
@@ -92,19 +129,7 @@ describe('<InventoryListItem />', () => {
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<InventoryListItem
|
<InventoryListItem
|
||||||
inventory={{
|
inventory={inventory}
|
||||||
id: 1,
|
|
||||||
name: 'Inventory',
|
|
||||||
summary_fields: {
|
|
||||||
organization: {
|
|
||||||
id: 1,
|
|
||||||
name: 'Default',
|
|
||||||
},
|
|
||||||
user_capabilities: {
|
|
||||||
edit: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
detailUrl="/inventories/inventory/1"
|
detailUrl="/inventories/inventory/1"
|
||||||
isSelected
|
isSelected
|
||||||
onSelect={() => {}}
|
onSelect={() => {}}
|
||||||
|
|||||||
Reference in New Issue
Block a user