mirror of
https://github.com/ansible/awx.git
synced 2026-04-07 02:59:21 -02:30
Merge pull request #9225 from nixocio/ui_issue_8670
Add relaunch against failed hosts Reviewed-by: Mat Wilson <mawilson@redhat.com> https://github.com/one-t
This commit is contained in:
@@ -7,7 +7,7 @@ import { Tr, Td, ExpandableRowContent } from '@patternfly/react-table';
|
|||||||
import { RocketIcon } from '@patternfly/react-icons';
|
import { RocketIcon } from '@patternfly/react-icons';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { ActionsTd, ActionItem } from '../PaginatedTable';
|
import { ActionsTd, ActionItem } from '../PaginatedTable';
|
||||||
import LaunchButton from '../LaunchButton';
|
import { LaunchButton, ReLaunchDropDown } from '../LaunchButton';
|
||||||
import StatusLabel from '../StatusLabel';
|
import StatusLabel from '../StatusLabel';
|
||||||
import { DetailList, Detail, LaunchedByDetail } from '../DetailList';
|
import { DetailList, Detail, LaunchedByDetail } from '../DetailList';
|
||||||
import ChipGroup from '../ChipGroup';
|
import ChipGroup from '../ChipGroup';
|
||||||
@@ -83,19 +83,31 @@ function JobListItem({
|
|||||||
job.type !== 'system_job' &&
|
job.type !== 'system_job' &&
|
||||||
job.summary_fields?.user_capabilities?.start
|
job.summary_fields?.user_capabilities?.start
|
||||||
}
|
}
|
||||||
tooltip={i18n._(t`Relaunch Job`)}
|
tooltip={
|
||||||
|
job.status === 'failed' && job.type === 'job'
|
||||||
|
? i18n._(t`Relaunch using host parameters`)
|
||||||
|
: i18n._(t`Relaunch Job`)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<LaunchButton resource={job}>
|
{job.status === 'failed' && job.type === 'job' ? (
|
||||||
{({ handleRelaunch }) => (
|
<LaunchButton resource={job}>
|
||||||
<Button
|
{({ handleRelaunch }) => (
|
||||||
variant="plain"
|
<ReLaunchDropDown handleRelaunch={handleRelaunch} />
|
||||||
onClick={handleRelaunch}
|
)}
|
||||||
aria-label={i18n._(t`Relaunch`)}
|
</LaunchButton>
|
||||||
>
|
) : (
|
||||||
<RocketIcon />
|
<LaunchButton resource={job}>
|
||||||
</Button>
|
{({ handleRelaunch }) => (
|
||||||
)}
|
<Button
|
||||||
</LaunchButton>
|
variant="plain"
|
||||||
|
onClick={handleRelaunch}
|
||||||
|
aria-label={i18n._(t`Relaunch`)}
|
||||||
|
>
|
||||||
|
<RocketIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</LaunchButton>
|
||||||
|
)}
|
||||||
</ActionItem>
|
</ActionItem>
|
||||||
</ActionsTd>
|
</ActionsTd>
|
||||||
</Tr>
|
</Tr>
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ describe('<JobListItem />', () => {
|
|||||||
expect(wrapper.find('LaunchButton').length).toBe(1);
|
expect(wrapper.find('LaunchButton').length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('launch button shown to users with launch capabilities', () => {
|
||||||
|
expect(wrapper.find('LaunchButton').length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('launch button hidden from users without launch capabilities', () => {
|
test('launch button hidden from users without launch capabilities', () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<table>
|
<table>
|
||||||
@@ -92,3 +96,83 @@ describe('<JobListItem />', () => {
|
|||||||
expect(wrapper.find('Td[dataLabel="Type"]').length).toBe(1);
|
expect(wrapper.find('Td[dataLabel="Type"]').length).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('<JobListItem with failed job />', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const history = createMemoryHistory({
|
||||||
|
initialEntries: ['/jobs'],
|
||||||
|
});
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<JobListItem
|
||||||
|
job={{ ...mockJob, status: 'failed' }}
|
||||||
|
isSelected
|
||||||
|
onSelect={() => {}}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>,
|
||||||
|
{ context: { router: { history } } }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('launch button shown to users with launch capabilities', () => {
|
||||||
|
expect(wrapper.find('LaunchButton').length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('dropdown should be displayed in case of failed job', () => {
|
||||||
|
expect(wrapper.find('LaunchButton').length).toBe(1);
|
||||||
|
const dropdown = wrapper.find('Dropdown');
|
||||||
|
expect(dropdown).toHaveLength(1);
|
||||||
|
expect(dropdown.find('DropdownItem')).toHaveLength(0);
|
||||||
|
dropdown.find('button').simulate('click');
|
||||||
|
wrapper.update();
|
||||||
|
expect(wrapper.find('DropdownItem')).toHaveLength(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('dropdown should not be rendered for job type different of playbook run', () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<JobListItem
|
||||||
|
job={{
|
||||||
|
...mockJob,
|
||||||
|
status: 'failed',
|
||||||
|
type: 'project_update',
|
||||||
|
}}
|
||||||
|
onSelect={() => {}}
|
||||||
|
isSelected
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
expect(wrapper.find('LaunchButton').length).toBe(1);
|
||||||
|
expect(wrapper.find('Dropdown')).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('launch button hidden from users without launch capabilities', () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<JobListItem
|
||||||
|
job={{
|
||||||
|
...mockJob,
|
||||||
|
status: 'failed',
|
||||||
|
summary_fields: { user_capabilities: { start: false } },
|
||||||
|
}}
|
||||||
|
detailUrl={`/jobs/playbook/${mockJob.id}`}
|
||||||
|
onSelect={() => {}}
|
||||||
|
isSelected={false}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
expect(wrapper.find('LaunchButton').length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ function LaunchButton({ resource, i18n, children, history }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRelaunch = async () => {
|
const handleRelaunch = async params => {
|
||||||
let readRelaunch;
|
let readRelaunch;
|
||||||
let relaunch;
|
let relaunch;
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ function LaunchButton({ resource, i18n, children, history }) {
|
|||||||
} else if (resource.type === 'ad_hoc_command') {
|
} else if (resource.type === 'ad_hoc_command') {
|
||||||
relaunch = AdHocCommandsAPI.relaunch(resource.id);
|
relaunch = AdHocCommandsAPI.relaunch(resource.id);
|
||||||
} else if (resource.type === 'job') {
|
} else if (resource.type === 'job') {
|
||||||
relaunch = JobsAPI.relaunch(resource.id);
|
relaunch = JobsAPI.relaunch(resource.id, params || {});
|
||||||
}
|
}
|
||||||
const { data: job } = await relaunch;
|
const { data: job } = await relaunch;
|
||||||
history.push(`/jobs/${job.id}/output`);
|
history.push(`/jobs/${job.id}/output`);
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ describe('LaunchButton', () => {
|
|||||||
await act(() => button.prop('onClick')());
|
await act(() => button.prop('onClick')());
|
||||||
expect(JobsAPI.readRelaunch).toHaveBeenCalledWith(1);
|
expect(JobsAPI.readRelaunch).toHaveBeenCalledWith(1);
|
||||||
await sleep(0);
|
await sleep(0);
|
||||||
expect(JobsAPI.relaunch).toHaveBeenCalledWith(1);
|
expect(JobsAPI.relaunch).toHaveBeenCalledWith(1, {});
|
||||||
expect(history.location.pathname).toEqual('/jobs/9000/output');
|
expect(history.location.pathname).toEqual('/jobs/9000/output');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
96
awx/ui_next/src/components/LaunchButton/ReLaunchDropDown.jsx
Normal file
96
awx/ui_next/src/components/LaunchButton/ReLaunchDropDown.jsx
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import {
|
||||||
|
Dropdown,
|
||||||
|
DropdownToggle,
|
||||||
|
DropdownItem,
|
||||||
|
DropdownPosition,
|
||||||
|
DropdownSeparator,
|
||||||
|
DropdownDirection,
|
||||||
|
} from '@patternfly/react-core';
|
||||||
|
import { RocketIcon } from '@patternfly/react-icons';
|
||||||
|
|
||||||
|
function ReLaunchDropDown({ isPrimary = false, handleRelaunch, i18n }) {
|
||||||
|
const [isOpen, setIsOPen] = useState(false);
|
||||||
|
|
||||||
|
const onToggle = () => {
|
||||||
|
setIsOPen(prev => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dropdownItems = [
|
||||||
|
<DropdownItem
|
||||||
|
aria-label={i18n._(t`Relaunch on`)}
|
||||||
|
key="relaunch_on"
|
||||||
|
component="div"
|
||||||
|
isPlainText
|
||||||
|
>
|
||||||
|
{i18n._(t`Relaunch on`)}
|
||||||
|
</DropdownItem>,
|
||||||
|
<DropdownSeparator key="separator" />,
|
||||||
|
<DropdownItem
|
||||||
|
key="relaunch_all"
|
||||||
|
aria-label={i18n._(t`Relaunch all hosts`)}
|
||||||
|
component="button"
|
||||||
|
onClick={() => {
|
||||||
|
handleRelaunch({ hosts: 'all' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18n._(t`All`)}
|
||||||
|
</DropdownItem>,
|
||||||
|
|
||||||
|
<DropdownItem
|
||||||
|
key="relaunch_failed"
|
||||||
|
aria-label={i18n._(t`Relaunch failed hosts`)}
|
||||||
|
component="button"
|
||||||
|
onClick={() => {
|
||||||
|
handleRelaunch({ hosts: 'failed' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18n._(t`Failed hosts`)}
|
||||||
|
</DropdownItem>,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isPrimary) {
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
position={DropdownPosition.left}
|
||||||
|
direction={DropdownDirection.up}
|
||||||
|
isOpen={isOpen}
|
||||||
|
dropdownItems={dropdownItems}
|
||||||
|
toggle={
|
||||||
|
<DropdownToggle
|
||||||
|
toggleIndicator={null}
|
||||||
|
onToggle={onToggle}
|
||||||
|
aria-label={i18n._(`relaunch jobs`)}
|
||||||
|
id="relaunch_jobs"
|
||||||
|
isPrimary
|
||||||
|
>
|
||||||
|
{i18n._(t`Relaunch`)}
|
||||||
|
</DropdownToggle>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
isPlain
|
||||||
|
position={DropdownPosition.right}
|
||||||
|
isOpen={isOpen}
|
||||||
|
dropdownItems={dropdownItems}
|
||||||
|
toggle={
|
||||||
|
<DropdownToggle
|
||||||
|
toggleIndicator={null}
|
||||||
|
onToggle={onToggle}
|
||||||
|
aria-label={i18n._(`relaunch jobs`)}
|
||||||
|
id="relaunch_jobs"
|
||||||
|
>
|
||||||
|
<RocketIcon />
|
||||||
|
</DropdownToggle>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withI18n()(ReLaunchDropDown);
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
|
||||||
|
import ReLaunchDropDown from './ReLaunchDropDown';
|
||||||
|
|
||||||
|
describe('ReLaunchDropDown', () => {
|
||||||
|
const handleRelaunch = jest.fn();
|
||||||
|
|
||||||
|
test('expected content is rendered on initialization', () => {
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<ReLaunchDropDown handleRelaunch={handleRelaunch} />
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(wrapper.find('Dropdown')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('dropdown have expected items and callbacks', () => {
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<ReLaunchDropDown handleRelaunch={handleRelaunch} />
|
||||||
|
);
|
||||||
|
expect(wrapper.find('DropdownItem')).toHaveLength(0);
|
||||||
|
wrapper.find('button').simulate('click');
|
||||||
|
wrapper.update();
|
||||||
|
expect(wrapper.find('DropdownItem')).toHaveLength(3);
|
||||||
|
|
||||||
|
wrapper
|
||||||
|
.find('DropdownItem[aria-label="Relaunch failed hosts"]')
|
||||||
|
.simulate('click');
|
||||||
|
expect(handleRelaunch).toHaveBeenCalledWith({ hosts: 'failed' });
|
||||||
|
|
||||||
|
wrapper
|
||||||
|
.find('DropdownItem[aria-label="Relaunch all hosts"]')
|
||||||
|
.simulate('click');
|
||||||
|
expect(handleRelaunch).toHaveBeenCalledWith({ hosts: 'all' });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('dropdown isPrimary have expected items and callbacks', () => {
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<ReLaunchDropDown isPrimary handleRelaunch={handleRelaunch} />
|
||||||
|
);
|
||||||
|
expect(wrapper.find('DropdownItem')).toHaveLength(0);
|
||||||
|
wrapper.find('button').simulate('click');
|
||||||
|
wrapper.update();
|
||||||
|
expect(wrapper.find('DropdownItem')).toHaveLength(3);
|
||||||
|
|
||||||
|
wrapper
|
||||||
|
.find('DropdownItem[aria-label="Relaunch failed hosts"]')
|
||||||
|
.simulate('click');
|
||||||
|
expect(handleRelaunch).toHaveBeenCalledWith({ hosts: 'failed' });
|
||||||
|
|
||||||
|
wrapper
|
||||||
|
.find('DropdownItem[aria-label="Relaunch all hosts"]')
|
||||||
|
.simulate('click');
|
||||||
|
expect(handleRelaunch).toHaveBeenCalledWith({ hosts: 'all' });
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1 +1,2 @@
|
|||||||
export { default } from './LaunchButton';
|
export { default as LaunchButton } from './LaunchButton';
|
||||||
|
export { default as ReLaunchDropDown } from './ReLaunchDropDown';
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import CredentialChip from '../CredentialChip';
|
|||||||
import { timeOfDay, formatDateString } from '../../util/dates';
|
import { timeOfDay, formatDateString } from '../../util/dates';
|
||||||
|
|
||||||
import { JobTemplatesAPI, WorkflowJobTemplatesAPI } from '../../api';
|
import { JobTemplatesAPI, WorkflowJobTemplatesAPI } from '../../api';
|
||||||
import LaunchButton from '../LaunchButton';
|
import { LaunchButton } from '../LaunchButton';
|
||||||
import Sparkline from '../Sparkline';
|
import Sparkline from '../Sparkline';
|
||||||
import { toTitleCase } from '../../util/strings';
|
import { toTitleCase } from '../../util/strings';
|
||||||
import CopyButton from '../CopyButton';
|
import CopyButton from '../CopyButton';
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ import CredentialChip from '../../../components/CredentialChip';
|
|||||||
import { VariablesInput as _VariablesInput } from '../../../components/CodeMirrorInput';
|
import { VariablesInput as _VariablesInput } from '../../../components/CodeMirrorInput';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import LaunchButton from '../../../components/LaunchButton';
|
import {
|
||||||
|
LaunchButton,
|
||||||
|
ReLaunchDropDown,
|
||||||
|
} from '../../../components/LaunchButton';
|
||||||
import StatusIcon from '../../../components/StatusIcon';
|
import StatusIcon from '../../../components/StatusIcon';
|
||||||
import { toTitleCase } from '../../../util/strings';
|
import { toTitleCase } from '../../../util/strings';
|
||||||
import { formatDateString } from '../../../util/dates';
|
import { formatDateString } from '../../../util/dates';
|
||||||
@@ -346,7 +349,14 @@ function JobDetail({ job, i18n }) {
|
|||||||
)}
|
)}
|
||||||
<CardActionsRow>
|
<CardActionsRow>
|
||||||
{job.type !== 'system_job' &&
|
{job.type !== 'system_job' &&
|
||||||
job.summary_fields.user_capabilities.start && (
|
job.summary_fields.user_capabilities.start &&
|
||||||
|
(job.status === 'failed' && job.type === 'job' ? (
|
||||||
|
<LaunchButton resource={job}>
|
||||||
|
{({ handleRelaunch }) => (
|
||||||
|
<ReLaunchDropDown isPrimary handleRelaunch={handleRelaunch} />
|
||||||
|
)}
|
||||||
|
</LaunchButton>
|
||||||
|
) : (
|
||||||
<LaunchButton resource={job} aria-label={i18n._(t`Relaunch`)}>
|
<LaunchButton resource={job} aria-label={i18n._(t`Relaunch`)}>
|
||||||
{({ handleRelaunch }) => (
|
{({ handleRelaunch }) => (
|
||||||
<Button type="submit" onClick={handleRelaunch}>
|
<Button type="submit" onClick={handleRelaunch}>
|
||||||
@@ -354,7 +364,7 @@ function JobDetail({ job, i18n }) {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</LaunchButton>
|
</LaunchButton>
|
||||||
)}
|
))}
|
||||||
{job.summary_fields.user_capabilities.delete && (
|
{job.summary_fields.user_capabilities.delete && (
|
||||||
<DeleteButton
|
<DeleteButton
|
||||||
name={job.name}
|
name={job.name}
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ import {
|
|||||||
} from '@patternfly/react-icons';
|
} from '@patternfly/react-icons';
|
||||||
import { Badge as PFBadge, Button, Tooltip } from '@patternfly/react-core';
|
import { Badge as PFBadge, Button, Tooltip } from '@patternfly/react-core';
|
||||||
import DeleteButton from '../../../../components/DeleteButton';
|
import DeleteButton from '../../../../components/DeleteButton';
|
||||||
import LaunchButton from '../../../../components/LaunchButton';
|
import {
|
||||||
|
LaunchButton,
|
||||||
|
ReLaunchDropDown,
|
||||||
|
} from '../../../../components/LaunchButton';
|
||||||
|
|
||||||
const BadgeGroup = styled.div`
|
const BadgeGroup = styled.div`
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
@@ -125,18 +128,32 @@ const OutputToolbar = ({ i18n, job, jobStatus, onDelete, onCancel }) => {
|
|||||||
|
|
||||||
{job.type !== 'system_job' &&
|
{job.type !== 'system_job' &&
|
||||||
job.summary_fields.user_capabilities?.start && (
|
job.summary_fields.user_capabilities?.start && (
|
||||||
<Tooltip content={i18n._(t`Relaunch Job`)}>
|
<Tooltip
|
||||||
<LaunchButton resource={job} aria-label={i18n._(t`Relaunch`)}>
|
content={
|
||||||
{({ handleRelaunch }) => (
|
job.status === 'failed' && job.type === 'job'
|
||||||
<Button
|
? i18n._(t`Relaunch using host parameters`)
|
||||||
variant="plain"
|
: i18n._(t`Relaunch Job`)
|
||||||
onClick={handleRelaunch}
|
}
|
||||||
aria-label={i18n._(t`Relaunch`)}
|
>
|
||||||
>
|
{job.status === 'failed' && job.type === 'job' ? (
|
||||||
<RocketIcon />
|
<LaunchButton resource={job}>
|
||||||
</Button>
|
{({ handleRelaunch }) => (
|
||||||
)}
|
<ReLaunchDropDown handleRelaunch={handleRelaunch} />
|
||||||
</LaunchButton>
|
)}
|
||||||
|
</LaunchButton>
|
||||||
|
) : (
|
||||||
|
<LaunchButton resource={job}>
|
||||||
|
{({ handleRelaunch }) => (
|
||||||
|
<Button
|
||||||
|
variant="plain"
|
||||||
|
onClick={handleRelaunch}
|
||||||
|
aria-label={i18n._(t`Relaunch`)}
|
||||||
|
>
|
||||||
|
<RocketIcon />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</LaunchButton>
|
||||||
|
)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import DataListCell from '../../../components/DataListCell';
|
import DataListCell from '../../../components/DataListCell';
|
||||||
|
|
||||||
import LaunchButton from '../../../components/LaunchButton';
|
import { LaunchButton } from '../../../components/LaunchButton';
|
||||||
import Sparkline from '../../../components/Sparkline';
|
import Sparkline from '../../../components/Sparkline';
|
||||||
import { toTitleCase } from '../../../util/strings';
|
import { toTitleCase } from '../../../util/strings';
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
} from '../../../components/DetailList';
|
} from '../../../components/DetailList';
|
||||||
import DeleteButton from '../../../components/DeleteButton';
|
import DeleteButton from '../../../components/DeleteButton';
|
||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import LaunchButton from '../../../components/LaunchButton';
|
import { LaunchButton } from '../../../components/LaunchButton';
|
||||||
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
import { VariablesDetail } from '../../../components/CodeMirrorInput';
|
||||||
import { JobTemplatesAPI } from '../../../api';
|
import { JobTemplatesAPI } from '../../../api';
|
||||||
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
UserDateDetail,
|
UserDateDetail,
|
||||||
} from '../../../components/DetailList';
|
} from '../../../components/DetailList';
|
||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import LaunchButton from '../../../components/LaunchButton';
|
import { LaunchButton } from '../../../components/LaunchButton';
|
||||||
import Sparkline from '../../../components/Sparkline';
|
import Sparkline from '../../../components/Sparkline';
|
||||||
import { toTitleCase } from '../../../util/strings';
|
import { toTitleCase } from '../../../util/strings';
|
||||||
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
WrenchIcon,
|
WrenchIcon,
|
||||||
} from '@patternfly/react-icons';
|
} from '@patternfly/react-icons';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import LaunchButton from '../../../components/LaunchButton';
|
import { LaunchButton } from '../../../components/LaunchButton';
|
||||||
import {
|
import {
|
||||||
WorkflowDispatchContext,
|
WorkflowDispatchContext,
|
||||||
WorkflowStateContext,
|
WorkflowStateContext,
|
||||||
|
|||||||
Reference in New Issue
Block a user