mirror of
https://github.com/ZwareBear/awx.git
synced 2026-05-12 15:58:38 -05:00
resolves advanced search button
This commit is contained in:
@@ -0,0 +1,62 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Plural, t } from '@lingui/macro';
|
||||||
|
import { Button, DropdownItem, Tooltip } from '@patternfly/react-core';
|
||||||
|
import { useKebabifiedMenu } from 'contexts/Kebabified';
|
||||||
|
|
||||||
|
function HealthCheckButton({ isDisabled, onClick, selectedItems }) {
|
||||||
|
const { isKebabified } = useKebabifiedMenu();
|
||||||
|
const hopNodeSelected =
|
||||||
|
selectedItems.filter((instance) => instance.node_type === 'hop').length > 0;
|
||||||
|
const hasSelectedItems = selectedItems.length > 0;
|
||||||
|
|
||||||
|
const buildTooltip = () => {
|
||||||
|
if (hopNodeSelected) {
|
||||||
|
return (
|
||||||
|
<Plural
|
||||||
|
value={hopNodeSelected}
|
||||||
|
one="Cannot run health check on a hop node. Deselect the hop node to run a health check."
|
||||||
|
other="Cannot run health check on hop nodes. Deselect the hop nodes to run health checks."
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return selectedItems.length ? (
|
||||||
|
<Plural
|
||||||
|
value={selectedItems.length}
|
||||||
|
one="Click to run a health check on the selected instance."
|
||||||
|
other="Click to run a health check on the selected instances."
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
t`Select an instance to run a health check.`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isKebabified) {
|
||||||
|
return (
|
||||||
|
<Tooltip data-cy="healthCheckTooltip" content={buildTooltip()}>
|
||||||
|
<DropdownItem
|
||||||
|
key="approve"
|
||||||
|
isDisabled={hopNodeSelected || isDisabled || !hasSelectedItems}
|
||||||
|
component="button"
|
||||||
|
onClick={onClick}
|
||||||
|
ouiaId="health-check"
|
||||||
|
>
|
||||||
|
{t`Health Check`}
|
||||||
|
</DropdownItem>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Tooltip data-cy="healthCheckTooltip" content={buildTooltip()}>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
isDisabled={hopNodeSelected || isDisabled || !hasSelectedItems}
|
||||||
|
variant="secondary"
|
||||||
|
ouiaId="health-check"
|
||||||
|
onClick={onClick}
|
||||||
|
>{t`Health Check`}</Button>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HealthCheckButton;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './HealthCheckButton';
|
||||||
+1065
-951
File diff suppressed because it is too large
Load Diff
+1215
-1021
File diff suppressed because it is too large
Load Diff
+1072
-952
File diff suppressed because it is too large
Load Diff
+1072
-950
File diff suppressed because it is too large
Load Diff
+1100
-965
File diff suppressed because it is too large
Load Diff
+1074
-951
File diff suppressed because it is too large
Load Diff
+1060
-946
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
import { Plural, t } from '@lingui/macro';
|
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import 'styled-components/macro';
|
import 'styled-components/macro';
|
||||||
|
|
||||||
@@ -16,7 +15,6 @@ import DisassociateButton from 'components/DisassociateButton';
|
|||||||
import AssociateModal from 'components/AssociateModal';
|
import AssociateModal from 'components/AssociateModal';
|
||||||
import AlertModal from 'components/AlertModal';
|
import AlertModal from 'components/AlertModal';
|
||||||
import ErrorDetail from 'components/ErrorDetail';
|
import ErrorDetail from 'components/ErrorDetail';
|
||||||
|
|
||||||
import useRequest, {
|
import useRequest, {
|
||||||
useDeleteItems,
|
useDeleteItems,
|
||||||
useDismissableError,
|
useDismissableError,
|
||||||
@@ -24,8 +22,7 @@ import useRequest, {
|
|||||||
import useSelected from 'hooks/useSelected';
|
import useSelected from 'hooks/useSelected';
|
||||||
import { InstanceGroupsAPI, InstancesAPI } from 'api';
|
import { InstanceGroupsAPI, InstancesAPI } from 'api';
|
||||||
import { getQSConfig, parseQueryString, mergeParams } from 'util/qs';
|
import { getQSConfig, parseQueryString, mergeParams } from 'util/qs';
|
||||||
|
import HealthCheckButton from 'components/HealthCheckButton/HealthCheckButton';
|
||||||
import { Button, Tooltip } from '@patternfly/react-core';
|
|
||||||
import InstanceListItem from './InstanceListItem';
|
import InstanceListItem from './InstanceListItem';
|
||||||
|
|
||||||
const QS_CONFIG = getQSConfig('instance', {
|
const QS_CONFIG = getQSConfig('instance', {
|
||||||
@@ -83,11 +80,16 @@ function InstanceList() {
|
|||||||
fetchInstances();
|
fetchInstances();
|
||||||
}, [fetchInstances]);
|
}, [fetchInstances]);
|
||||||
|
|
||||||
const { error: healthCheckError, request: fetchHealthCheck } = useRequest(
|
const {
|
||||||
|
error: healthCheckError,
|
||||||
|
request: fetchHealthCheck,
|
||||||
|
isLoading: isHealthCheckLoading,
|
||||||
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
await Promise.all(selected.map(({ id }) => InstancesAPI.healthCheck(id)));
|
await Promise.all(selected.map(({ id }) => InstancesAPI.healthCheck(id)));
|
||||||
fetchInstances();
|
fetchInstances();
|
||||||
}, [selected, fetchInstances])
|
clearSelected();
|
||||||
|
}, [selected, clearSelected, fetchInstances])
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -168,7 +170,9 @@ function InstanceList() {
|
|||||||
<>
|
<>
|
||||||
<PaginatedTable
|
<PaginatedTable
|
||||||
contentError={contentError}
|
contentError={contentError}
|
||||||
hasContentLoading={isLoading || isDisassociateLoading}
|
hasContentLoading={
|
||||||
|
isLoading || isDisassociateLoading || isHealthCheckLoading
|
||||||
|
}
|
||||||
items={instances}
|
items={instances}
|
||||||
itemCount={count}
|
itemCount={count}
|
||||||
pluralizedItemName={t`Instances`}
|
pluralizedItemName={t`Instances`}
|
||||||
@@ -182,6 +186,15 @@ function InstanceList() {
|
|||||||
key: 'hostname__icontains',
|
key: 'hostname__icontains',
|
||||||
isDefault: true,
|
isDefault: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: t`Node Type`,
|
||||||
|
key: `or__node_type`,
|
||||||
|
options: [
|
||||||
|
[`control`, t`Control`],
|
||||||
|
[`execution`, t`Execution`],
|
||||||
|
[`hybrid`, t`Hybrid`],
|
||||||
|
],
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
toolbarSortColumns={[
|
toolbarSortColumns={[
|
||||||
{
|
{
|
||||||
@@ -216,28 +229,11 @@ function InstanceList() {
|
|||||||
itemsToDisassociate={selected}
|
itemsToDisassociate={selected}
|
||||||
modalTitle={t`Disassociate instance from instance group?`}
|
modalTitle={t`Disassociate instance from instance group?`}
|
||||||
/>,
|
/>,
|
||||||
<Tooltip
|
<HealthCheckButton
|
||||||
content={
|
isDisabled={!canAdd}
|
||||||
selected.length ? (
|
onClick={fetchHealthCheck}
|
||||||
<Plural
|
selectedItems={selected}
|
||||||
value={selected.length}
|
/>,
|
||||||
one="Click to run a health check on the selected instance."
|
|
||||||
other="Click to run a health check on the selected instances."
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
t`Select an instance to run a health check.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
isDisabled={!canAdd || !selected.length}
|
|
||||||
variant="secondary"
|
|
||||||
ouiaId="health-check"
|
|
||||||
onClick={fetchHealthCheck}
|
|
||||||
>{t`Health Check`}</Button>
|
|
||||||
</div>
|
|
||||||
</Tooltip>,
|
|
||||||
]}
|
]}
|
||||||
emptyStateControls={
|
emptyStateControls={
|
||||||
canAdd ? (
|
canAdd ? (
|
||||||
@@ -253,9 +249,8 @@ function InstanceList() {
|
|||||||
<HeaderRow qsConfig={QS_CONFIG} isExpandable>
|
<HeaderRow qsConfig={QS_CONFIG} isExpandable>
|
||||||
<HeaderCell sortKey="hostname">{t`Name`}</HeaderCell>
|
<HeaderCell sortKey="hostname">{t`Name`}</HeaderCell>
|
||||||
<HeaderCell sortKey="errors">{t`Status`}</HeaderCell>
|
<HeaderCell sortKey="errors">{t`Status`}</HeaderCell>
|
||||||
<HeaderCell>{t`Running Jobs`}</HeaderCell>
|
<HeaderCell sortKey="node_type">{t`Node Type`}</HeaderCell>
|
||||||
<HeaderCell>{t`Total Jobs`}</HeaderCell>
|
<HeaderCell sortKey="capacity_adjustment">{t`Capacity Adjustment`}</HeaderCell>
|
||||||
<HeaderCell>{t`Capacity Adjustment`}</HeaderCell>
|
|
||||||
<HeaderCell>{t`Used Capacity`}</HeaderCell>
|
<HeaderCell>{t`Used Capacity`}</HeaderCell>
|
||||||
<HeaderCell>{t`Actions`}</HeaderCell>
|
<HeaderCell>{t`Actions`}</HeaderCell>
|
||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ function InstanceListItem({
|
|||||||
rowIndex,
|
rowIndex,
|
||||||
}) {
|
}) {
|
||||||
const { me = {} } = useConfig();
|
const { me = {} } = useConfig();
|
||||||
|
const { id } = useParams();
|
||||||
const [forks, setForks] = useState(
|
const [forks, setForks] = useState(
|
||||||
computeForks(
|
computeForks(
|
||||||
instance.mem_capacity,
|
instance.mem_capacity,
|
||||||
@@ -68,7 +69,6 @@ function InstanceListItem({
|
|||||||
instance.capacity_adjustment
|
instance.capacity_adjustment
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const { id } = useParams();
|
|
||||||
|
|
||||||
const labelId = `check-action-${instance.id}`;
|
const labelId = `check-action-${instance.id}`;
|
||||||
|
|
||||||
@@ -147,8 +147,7 @@ function InstanceListItem({
|
|||||||
<StatusLabel status={instance.errors ? 'error' : 'healthy'} />
|
<StatusLabel status={instance.errors ? 'error' : 'healthy'} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Td>
|
</Td>
|
||||||
<Td dataLabel={t`Running Jobs`}>{instance.jobs_running}</Td>
|
<Td dataLabel={t`Node Type`}>{instance.node_type}</Td>
|
||||||
<Td dataLabel={t`Total Jobs`}>{instance.jobs_total}</Td>
|
|
||||||
<Td dataLabel={t`Capacity Adjustment`}>
|
<Td dataLabel={t`Capacity Adjustment`}>
|
||||||
<SliderHolder data-cy="slider-holder">
|
<SliderHolder data-cy="slider-holder">
|
||||||
<div data-cy="cpu-capacity">{t`CPU ${instance.cpu_capacity}`}</div>
|
<div data-cy="cpu-capacity">{t`CPU ${instance.cpu_capacity}`}</div>
|
||||||
@@ -197,7 +196,8 @@ function InstanceListItem({
|
|||||||
<Td colSpan={7}>
|
<Td colSpan={7}>
|
||||||
<ExpandableRowContent>
|
<ExpandableRowContent>
|
||||||
<DetailList>
|
<DetailList>
|
||||||
<Detail label={t`Node Type`} value={instance.node_type} />
|
<Detail value={instance.jobs_running} label={t`Running Jobs`} />
|
||||||
|
<Detail value={instance.jobs_total} label={t`Total Jobs`} />
|
||||||
<Detail
|
<Detail
|
||||||
label={t`Policy Type`}
|
label={t`Policy Type`}
|
||||||
value={instance.managed_by_policy ? t`Auto` : t`Manual`}
|
value={instance.managed_by_policy ? t`Auto` : t`Manual`}
|
||||||
|
|||||||
@@ -274,9 +274,8 @@ describe('<InstanceListItem/>', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
expect(wrapper.find('InstanceListItem').prop('isExpanded')).toBe(true);
|
expect(wrapper.find('InstanceListItem').prop('isExpanded')).toBe(true);
|
||||||
expect(wrapper.find('Detail[label="Node Type"]').prop('value')).toBe(
|
expect(wrapper.find('Detail[label="Running Jobs"]').prop('value')).toBe(0);
|
||||||
'hybrid'
|
expect(wrapper.find('Detail[label="Total Jobs"]').prop('value')).toBe(68);
|
||||||
);
|
|
||||||
expect(wrapper.find('Detail[label="Policy Type"]').prop('value')).toBe(
|
expect(wrapper.find('Detail[label="Policy Type"]').prop('value')).toBe(
|
||||||
'Auto'
|
'Auto'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -149,19 +149,18 @@ function InstanceDetail({ setBreadcrumb }) {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Detail label={t`Node Type`} value={instance.node_type} />
|
<Detail label={t`Node Type`} value={instance.node_type} />
|
||||||
<Detail
|
|
||||||
label={t`Policy Type`}
|
|
||||||
value={instance.managed_by_policy ? t`Auto` : t`Manual`}
|
|
||||||
/>
|
|
||||||
<Detail label={t`Running Jobs`} value={instance.jobs_running} />
|
|
||||||
<Detail label={t`Total Jobs`} value={instance.jobs_total} />
|
|
||||||
{!isHopNode && (
|
{!isHopNode && (
|
||||||
<>
|
<>
|
||||||
|
<Detail
|
||||||
|
label={t`Policy Type`}
|
||||||
|
value={instance.managed_by_policy ? t`Auto` : t`Manual`}
|
||||||
|
/>
|
||||||
|
<Detail label={t`Running Jobs`} value={instance.jobs_running} />
|
||||||
|
<Detail label={t`Total Jobs`} value={instance.jobs_total} />
|
||||||
<Detail
|
<Detail
|
||||||
label={t`Last Health Check`}
|
label={t`Last Health Check`}
|
||||||
value={formatDateString(healthCheck?.last_health_check)}
|
value={formatDateString(healthCheck?.last_health_check)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Detail
|
<Detail
|
||||||
label={t`Capacity Adjustment`}
|
label={t`Capacity Adjustment`}
|
||||||
value={
|
value={
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, { useCallback, useEffect } from 'react';
|
import React, { useCallback, useEffect } from 'react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
import { Plural, t } from '@lingui/macro';
|
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import 'styled-components/macro';
|
import 'styled-components/macro';
|
||||||
|
import { PageSection, Card } from '@patternfly/react-core';
|
||||||
|
|
||||||
import useExpanded from 'hooks/useExpanded';
|
import useExpanded from 'hooks/useExpanded';
|
||||||
import DataListToolbar from 'components/DataListToolbar';
|
import DataListToolbar from 'components/DataListToolbar';
|
||||||
@@ -13,13 +13,11 @@ import PaginatedTable, {
|
|||||||
} from 'components/PaginatedTable';
|
} from 'components/PaginatedTable';
|
||||||
import AlertModal from 'components/AlertModal';
|
import AlertModal from 'components/AlertModal';
|
||||||
import ErrorDetail from 'components/ErrorDetail';
|
import ErrorDetail from 'components/ErrorDetail';
|
||||||
|
|
||||||
import useRequest, { useDismissableError } from 'hooks/useRequest';
|
import useRequest, { useDismissableError } from 'hooks/useRequest';
|
||||||
import useSelected from 'hooks/useSelected';
|
import useSelected from 'hooks/useSelected';
|
||||||
import { InstancesAPI } from 'api';
|
import { InstancesAPI } from 'api';
|
||||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||||
|
import HealthCheckButton from 'components/HealthCheckButton';
|
||||||
import { Button, Tooltip, PageSection, Card } from '@patternfly/react-core';
|
|
||||||
import InstanceListItem from './InstanceListItem';
|
import InstanceListItem from './InstanceListItem';
|
||||||
|
|
||||||
const QS_CONFIG = getQSConfig('instance', {
|
const QS_CONFIG = getQSConfig('instance', {
|
||||||
@@ -69,7 +67,11 @@ function InstanceList() {
|
|||||||
fetchInstances();
|
fetchInstances();
|
||||||
}, [fetchInstances]);
|
}, [fetchInstances]);
|
||||||
|
|
||||||
const { error: healthCheckError, request: fetchHealthCheck } = useRequest(
|
const {
|
||||||
|
error: healthCheckError,
|
||||||
|
request: fetchHealthCheck,
|
||||||
|
isLoading: isHealthCheckLoading,
|
||||||
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
selected
|
selected
|
||||||
@@ -86,38 +88,13 @@ function InstanceList() {
|
|||||||
const { expanded, isAllExpanded, handleExpand, expandAll } =
|
const { expanded, isAllExpanded, handleExpand, expandAll } =
|
||||||
useExpanded(instances);
|
useExpanded(instances);
|
||||||
|
|
||||||
const hopNodeSelected = selected.filter(
|
|
||||||
(instance) => instance.node_type === 'hop'
|
|
||||||
).length;
|
|
||||||
|
|
||||||
const buildTooltip = () => {
|
|
||||||
if (hopNodeSelected) {
|
|
||||||
return (
|
|
||||||
<Plural
|
|
||||||
value={hopNodeSelected}
|
|
||||||
one="Cannot run health check on a hop node. Deselect the hop node to run a health check."
|
|
||||||
other="Cannot run health check on hop nodes. Deselect the hop nodes to run health checks."
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return selected.length ? (
|
|
||||||
<Plural
|
|
||||||
value={selected.length}
|
|
||||||
one="Click to run a health check on the selected instance."
|
|
||||||
other="Click to run a health check on the selected instances."
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
t`Select an instance to run a health check.`
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageSection>
|
<PageSection>
|
||||||
<Card>
|
<Card>
|
||||||
<PaginatedTable
|
<PaginatedTable
|
||||||
contentError={contentError}
|
contentError={contentError}
|
||||||
hasContentLoading={isLoading}
|
hasContentLoading={isLoading || isHealthCheckLoading}
|
||||||
items={instances}
|
items={instances}
|
||||||
itemCount={count}
|
itemCount={count}
|
||||||
pluralizedItemName={t`Instances`}
|
pluralizedItemName={t`Instances`}
|
||||||
@@ -157,18 +134,10 @@ function InstanceList() {
|
|||||||
onExpandAll={expandAll}
|
onExpandAll={expandAll}
|
||||||
qsConfig={QS_CONFIG}
|
qsConfig={QS_CONFIG}
|
||||||
additionalControls={[
|
additionalControls={[
|
||||||
<Tooltip ouiaId="healthCheckTooltip" content={buildTooltip()}>
|
<HealthCheckButton
|
||||||
<div>
|
onClick={fetchHealthCheck}
|
||||||
<Button
|
selectedItems={selected}
|
||||||
isDisabled={
|
/>,
|
||||||
!selected.length || Boolean(hopNodeSelected)
|
|
||||||
}
|
|
||||||
variant="secondary"
|
|
||||||
ouiaId="health-check"
|
|
||||||
onClick={fetchHealthCheck}
|
|
||||||
>{t`Health Check`}</Button>
|
|
||||||
</div>
|
|
||||||
</Tooltip>,
|
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -179,7 +148,7 @@ function InstanceList() {
|
|||||||
<HeaderCell sortKey="node_type">{t`Node Type`}</HeaderCell>
|
<HeaderCell sortKey="node_type">{t`Node Type`}</HeaderCell>
|
||||||
<HeaderCell sortKey="capacity_adjustment">{t`Capacity Adjustment`}</HeaderCell>
|
<HeaderCell sortKey="capacity_adjustment">{t`Capacity Adjustment`}</HeaderCell>
|
||||||
<HeaderCell>{t`Used Capacity`}</HeaderCell>
|
<HeaderCell>{t`Used Capacity`}</HeaderCell>
|
||||||
<HeaderCell sortKey="enabled">{t`Actions`}</HeaderCell>
|
<HeaderCell>{t`Actions`}</HeaderCell>
|
||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
}
|
}
|
||||||
renderRow={(instance, index) => (
|
renderRow={(instance, index) => (
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ describe('<InstanceList/>', () => {
|
|||||||
expect(wrapper.find('InstanceListItem').length).toBe(4);
|
expect(wrapper.find('InstanceListItem').length).toBe(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should run health check', async () => {
|
test('Should run health check', async () => {
|
||||||
// Ensures health check button is disabled on mount
|
// Ensures health check button is disabled on mount
|
||||||
expect(
|
expect(
|
||||||
wrapper.find('Button[ouiaId="health-check"]').prop('isDisabled')
|
wrapper.find('Button[ouiaId="health-check"]').prop('isDisabled')
|
||||||
@@ -168,7 +168,7 @@ describe('<InstanceList/>', () => {
|
|||||||
);
|
);
|
||||||
expect(InstancesAPI.healthCheck).toBeCalledTimes(3);
|
expect(InstancesAPI.healthCheck).toBeCalledTimes(3);
|
||||||
});
|
});
|
||||||
test('should render health check error', async () => {
|
test('Should render health check error', async () => {
|
||||||
InstancesAPI.healthCheck.mockRejectedValue(
|
InstancesAPI.healthCheck.mockRejectedValue(
|
||||||
new Error({
|
new Error({
|
||||||
response: {
|
response: {
|
||||||
@@ -206,6 +206,8 @@ describe('<InstanceList/>', () => {
|
|||||||
expect(
|
expect(
|
||||||
wrapper.find('Button[ouiaId="health-check"]').prop('isDisabled')
|
wrapper.find('Button[ouiaId="health-check"]').prop('isDisabled')
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
expect(wrapper.find('Tooltip[ouiaId="healthCheckTooltip"]').length).toBe(1);
|
expect(wrapper.find('Tooltip[data-cy="healthCheckTooltip"]').length).toBe(
|
||||||
|
1
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -106,20 +106,25 @@ function InstanceListItem({
|
|||||||
);
|
);
|
||||||
debounceUpdateInstance({ capacity_adjustment: roundedValue });
|
debounceUpdateInstance({ capacity_adjustment: roundedValue });
|
||||||
};
|
};
|
||||||
|
const isHopNode = instance.node_type === 'hop';
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tr
|
<Tr
|
||||||
id={`instance-row-${instance.id}`}
|
id={`instance-row-${instance.id}`}
|
||||||
ouiaId={`instance-row-${instance.id}`}
|
ouiaId={`instance-row-${instance.id}`}
|
||||||
>
|
>
|
||||||
<Td
|
{isHopNode ? (
|
||||||
expand={{
|
<Td />
|
||||||
rowIndex,
|
) : (
|
||||||
isExpanded,
|
<Td
|
||||||
onToggle: onExpand,
|
expand={{
|
||||||
}}
|
rowIndex,
|
||||||
/>
|
isExpanded,
|
||||||
|
disabled: isHopNode,
|
||||||
|
onToggle: onExpand,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Td
|
<Td
|
||||||
select={{
|
select={{
|
||||||
rowIndex,
|
rowIndex,
|
||||||
@@ -133,88 +138,92 @@ function InstanceListItem({
|
|||||||
<b>{instance.hostname}</b>
|
<b>{instance.hostname}</b>
|
||||||
</Link>
|
</Link>
|
||||||
</Td>
|
</Td>
|
||||||
<Td dataLabel={t`Status`}>
|
{!instance.node_type !== 'hop' && (
|
||||||
<Tooltip
|
<Td dataLabel={t`Status`}>
|
||||||
content={
|
<Tooltip
|
||||||
<div>
|
content={
|
||||||
{t`Last Health Check`}
|
<div>
|
||||||
|
{t`Last Health Check`}
|
||||||
{formatDateString(instance.last_health_check)}
|
|
||||||
</div>
|
{formatDateString(instance.last_health_check)}
|
||||||
}
|
|
||||||
>
|
|
||||||
<StatusLabel status={instance.errors ? 'error' : 'healthy'} />
|
|
||||||
</Tooltip>
|
|
||||||
</Td>
|
|
||||||
<Td dataLabel={t`Node Type`}>{instance.node_type}</Td>
|
|
||||||
{instance.node_type !== 'hop' && (
|
|
||||||
<Td dataLabel={t`Capacity Adjustment`}>
|
|
||||||
<SliderHolder data-cy="slider-holder">
|
|
||||||
<div data-cy="cpu-capacity">{t`CPU ${instance.cpu_capacity}`}</div>
|
|
||||||
<SliderForks data-cy="slider-forks">
|
|
||||||
<div data-cy="number-forks">
|
|
||||||
<Plural value={forks} one="# fork" other="# forks" />
|
|
||||||
</div>
|
</div>
|
||||||
<Slider
|
}
|
||||||
areCustomStepsContinuous
|
>
|
||||||
max={1}
|
<StatusLabel status={instance.errors ? 'error' : 'healthy'} />
|
||||||
min={0}
|
</Tooltip>
|
||||||
step={0.1}
|
</Td>
|
||||||
value={instance.capacity_adjustment}
|
)}
|
||||||
onChange={handleChangeValue}
|
<Td dataLabel={t`Node Type`}>{instance.node_type}</Td>
|
||||||
isDisabled={!me?.is_superuser || !instance.enabled}
|
{!isHopNode && (
|
||||||
data-cy="slider"
|
<>
|
||||||
|
<Td dataLabel={t`Capacity Adjustment`}>
|
||||||
|
<SliderHolder data-cy="slider-holder">
|
||||||
|
<div data-cy="cpu-capacity">{t`CPU ${instance.cpu_capacity}`}</div>
|
||||||
|
<SliderForks data-cy="slider-forks">
|
||||||
|
<div data-cy="number-forks">
|
||||||
|
<Plural value={forks} one="# fork" other="# forks" />
|
||||||
|
</div>
|
||||||
|
<Slider
|
||||||
|
areCustomStepsContinuous
|
||||||
|
max={1}
|
||||||
|
min={0}
|
||||||
|
step={0.1}
|
||||||
|
value={instance.capacity_adjustment}
|
||||||
|
onChange={handleChangeValue}
|
||||||
|
isDisabled={!me?.is_superuser || !instance.enabled}
|
||||||
|
data-cy="slider"
|
||||||
|
/>
|
||||||
|
</SliderForks>
|
||||||
|
<div data-cy="mem-capacity">{t`RAM ${instance.mem_capacity}`}</div>
|
||||||
|
</SliderHolder>
|
||||||
|
</Td>
|
||||||
|
|
||||||
|
<Td
|
||||||
|
dataLabel={t`Instance group used capacity`}
|
||||||
|
css="--pf-c-table--cell--MinWidth: 175px;"
|
||||||
|
>
|
||||||
|
{usedCapacity(instance)}
|
||||||
|
</Td>
|
||||||
|
|
||||||
|
<ActionsTd
|
||||||
|
dataLabel={t`Actions`}
|
||||||
|
css="--pf-c-table--cell--Width: 125px"
|
||||||
|
>
|
||||||
|
<ActionItem visible>
|
||||||
|
<InstanceToggle
|
||||||
|
css="display: inline-flex;"
|
||||||
|
fetchInstances={fetchInstances}
|
||||||
|
instance={instance}
|
||||||
/>
|
/>
|
||||||
</SliderForks>
|
</ActionItem>
|
||||||
<div data-cy="mem-capacity">{t`RAM ${instance.mem_capacity}`}</div>
|
</ActionsTd>
|
||||||
</SliderHolder>
|
</>
|
||||||
</Td>
|
|
||||||
)}
|
|
||||||
{instance.node_type !== 'hop' && (
|
|
||||||
<Td
|
|
||||||
dataLabel={t`Instance group used capacity`}
|
|
||||||
css="--pf-c-table--cell--MinWidth: 175px;"
|
|
||||||
>
|
|
||||||
{usedCapacity(instance)}
|
|
||||||
</Td>
|
|
||||||
)}
|
|
||||||
{instance.node_type !== 'hop' && (
|
|
||||||
<ActionsTd
|
|
||||||
dataLabel={t`Actions`}
|
|
||||||
css="--pf-c-table--cell--Width: 125px"
|
|
||||||
>
|
|
||||||
<ActionItem visible>
|
|
||||||
<InstanceToggle
|
|
||||||
css="display: inline-flex;"
|
|
||||||
fetchInstances={fetchInstances}
|
|
||||||
instance={instance}
|
|
||||||
/>
|
|
||||||
</ActionItem>
|
|
||||||
</ActionsTd>
|
|
||||||
)}
|
)}
|
||||||
</Tr>
|
</Tr>
|
||||||
<Tr
|
{!isHopNode && (
|
||||||
ouiaId={`instance-row-${instance.id}-expanded`}
|
<Tr
|
||||||
isExpanded={isExpanded}
|
ouiaId={`instance-row-${instance.id}-expanded`}
|
||||||
>
|
isExpanded={isExpanded}
|
||||||
<Td colSpan={2} />
|
>
|
||||||
<Td colSpan={7}>
|
<Td colSpan={2} />
|
||||||
<ExpandableRowContent>
|
<Td colSpan={7}>
|
||||||
<DetailList>
|
<ExpandableRowContent>
|
||||||
<Detail value={instance.jobs_running} label={t`Running Jobs`} />
|
<DetailList>
|
||||||
<Detail value={instance.jobs_total} label={t`Total Jobs`} />
|
<Detail value={instance.jobs_running} label={t`Running Jobs`} />
|
||||||
<Detail
|
<Detail value={instance.jobs_total} label={t`Total Jobs`} />
|
||||||
label={t`Policy Type`}
|
<Detail
|
||||||
value={instance.managed_by_policy ? t`Auto` : t`Manual`}
|
label={t`Policy Type`}
|
||||||
/>
|
value={instance.managed_by_policy ? t`Auto` : t`Manual`}
|
||||||
<Detail
|
/>
|
||||||
label={t`Last Health Check`}
|
<Detail
|
||||||
value={formatDateString(instance.last_health_check)}
|
label={t`Last Health Check`}
|
||||||
/>
|
value={formatDateString(instance.last_health_check)}
|
||||||
</DetailList>
|
/>
|
||||||
</ExpandableRowContent>
|
</DetailList>
|
||||||
</Td>
|
</ExpandableRowContent>
|
||||||
</Tr>
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
)}
|
||||||
{updateError && (
|
{updateError && (
|
||||||
<AlertModal
|
<AlertModal
|
||||||
variant="error"
|
variant="error"
|
||||||
|
|||||||
@@ -17,17 +17,14 @@ function Instances() {
|
|||||||
}
|
}
|
||||||
setBreadcrumbConfig({
|
setBreadcrumbConfig({
|
||||||
'/instances': t`Instances`,
|
'/instances': t`Instances`,
|
||||||
[`/instances/${instance.id}`]: t`${instance.hostname}`,
|
[`/instances/${instance.id}`]: `${instance.hostname}`,
|
||||||
[`/instances/${instance.id}/details`]: t`Details`,
|
[`/instances/${instance.id}/details`]: t`Details`,
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ScreenHeader
|
<ScreenHeader streamType="instance" breadcrumbConfig={breadcrumbConfig} />
|
||||||
streamType="instances"
|
|
||||||
breadcrumbConfig={breadcrumbConfig}
|
|
||||||
/>
|
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/instances/:id">
|
<Route path="/instances/:id">
|
||||||
<Instance setBreadcrumb={buildBreadcrumbConfig} />
|
<Instance setBreadcrumb={buildBreadcrumbConfig} />
|
||||||
|
|||||||
Reference in New Issue
Block a user