Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #36887 - Add Schedule a Job to new host overview #845

Merged
merged 4 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/models/concerns/api/v2/hosts_controller_extensions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Api
module V2
module HostsControllerExtensions
extend ActiveSupport::Concern
def index_node_permissions
super.merge({
jeremylenz marked this conversation as resolved.
Show resolved Hide resolved
:can_create_job_invocations => authorized_for(:controller => 'job_invocations', :action => 'create'),
})
end
end
end
end
1 change: 1 addition & 0 deletions lib/foreman_remote_execution/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ class Engine < ::Rails::Engine

ForemanRemoteExecution.register_rex_feature

::Api::V2::HostsController.include Api::V2::HostsControllerExtensions
::Api::V2::SubnetsController.include ::ForemanRemoteExecution::Concerns::Api::V2::SubnetsControllerExtensions
::Api::V2::RegistrationController.prepend ::ForemanRemoteExecution::Concerns::Api::V2::RegistrationControllerExtensions
::Api::V2::RegistrationController.include ::ForemanRemoteExecution::Concerns::Api::V2::RegistrationControllerExtensions::ApipieExtensions
Expand Down
6 changes: 4 additions & 2 deletions webpack/react_app/components/FeaturesDropdown/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { foremanUrl } from 'foremanReact/common/helpers';
import { sprintf, translate as __ } from 'foremanReact/common/I18n';
import { post } from 'foremanReact/redux/API';

export const runFeature = (hostId, feature, label) => dispatch => {
export const runFeature = (hostId, feature, label, hostSearch) => dispatch => {
const url = foremanUrl(
`/job_invocations?feature=${feature}&host_ids%5B%5D=${hostId}`
hostId
? `/job_invocations?feature=${feature}&host_ids%5B%5D=${hostId}`
: `/job_invocations?feature=${feature}&search=${hostSearch}`
);
const redirectUrl = 'job_invocations/new';

Expand Down
3 changes: 0 additions & 3 deletions webpack/react_app/components/FeaturesDropdown/constant.js

This file was deleted.

5 changes: 5 additions & 0 deletions webpack/react_app/components/FeaturesDropdown/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const REX_FEATURES_HOST_URL = host =>
`/api/v2/hosts/${host}/available_remote_execution_features`;
export const ALL_REX_FEATURES_URL = '/api/v2/remote_execution_features';
export const NEW_JOB_PAGE = '/job_invocations/new?host_ids%5B%5D';
export const ALL_HOSTS_NEW_JOB_PAGE = '/job_invocations/new?search';
67 changes: 53 additions & 14 deletions webpack/react_app/components/FeaturesDropdown/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,58 +11,83 @@ import { push } from 'connected-react-router';

import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
import { translate as __ } from 'foremanReact/common/I18n';
import { foremanUrl } from 'foremanReact/common/helpers';
import { foremanUrl, propsToCamelCase } from 'foremanReact/common/helpers';
import { STATUS } from 'foremanReact/constants';

import { REX_FEATURES_API, NEW_JOB_PAGE } from './constant';
import {
REX_FEATURES_HOST_URL,
ALL_REX_FEATURES_URL,
NEW_JOB_PAGE,
ALL_HOSTS_NEW_JOB_PAGE,
} from './constants';
import { runFeature } from './actions';
import './index.scss';

const FeaturesDropdown = ({ hostId }) => {
const FeaturesDropdown = ({
hostId,
hostSearch,
hostResponse,
selectedCount,
}) => {
const [isOpen, setIsOpen] = useState(false);
const { response, status } = useAPI(
'get',
foremanUrl(REX_FEATURES_API(hostId))
);
const isSingleHost = !!hostId; // identifies whether we're on the host details or host overview page
const rexFeaturesUrl = isSingleHost
? REX_FEATURES_HOST_URL(hostId)
: ALL_REX_FEATURES_URL;
const { response, status } = useAPI('get', foremanUrl(rexFeaturesUrl));
const dispatch = useDispatch();
// eslint-disable-next-line camelcase
const canRunJob = response?.permissions?.can_run_job;
const permissions = propsToCamelCase(
(isSingleHost ? response?.permissions : hostResponse?.response) || {}
);
const canRunJob = isSingleHost
? permissions.canRunJob
: permissions.canCreateJobInvocations;
if (!canRunJob) {
return null;
}
// eslint-disable-next-line camelcase
const features = response?.remote_execution_features;

const features = isSingleHost
? response?.remote_execution_features // eslint-disable-line camelcase
: response?.results;
const dropdownItems = features
?.filter(feature => feature.host_action_button)
?.map(({ name, label, id, description }) => (
<DropdownItem
onClick={() => dispatch(runFeature(hostId, label, name))}
onClick={() => dispatch(runFeature(hostId, label, name, hostSearch))}
key={id}
description={description}
>
{name}
</DropdownItem>
));
const newJobPageUrl = hostId
? `${NEW_JOB_PAGE}=${hostId}`
: `${ALL_HOSTS_NEW_JOB_PAGE}=${hostSearch}`;
const scheduleJob = [
<DropdownToggleAction
onClick={() => dispatch(push(`${NEW_JOB_PAGE}=${hostId}`))}
onClick={() => dispatch(push(newJobPageUrl))}
key="schedule-job-action"
>
{__('Schedule a job')}
</DropdownToggleAction>,
];

const disableDropdown = !isSingleHost && selectedCount === 0;

return (
<Dropdown
ouiaId="schedule-a-job-dropdown"
id="schedule-a-job-dropdown"
alignments={{ default: 'right' }}
onSelect={() => setIsOpen(false)}
toggle={
<DropdownToggle
ouiaId="schedule-a-job-dropdown-toggle"
id="schedule-a-job-dropdown-toggle"
splitButtonItems={scheduleJob}
toggleVariant="secondary"
onToggle={() => setIsOpen(prev => !prev)}
isDisabled={status === STATUS.PENDING}
isDisabled={status === STATUS.PENDING || disableDropdown}
splitButtonVariant="action"
/>
}
Expand All @@ -74,9 +99,23 @@ const FeaturesDropdown = ({ hostId }) => {

FeaturesDropdown.propTypes = {
hostId: PropTypes.number,
hostSearch: PropTypes.string,
selectedCount: PropTypes.number,
hostResponse: PropTypes.shape({
response: PropTypes.shape({
results: PropTypes.arrayOf(
PropTypes.shape({
can_create_job_invocations: PropTypes.bool,
})
),
}),
}),
};
FeaturesDropdown.defaultProps = {
hostId: undefined,
hostSearch: undefined,
selectedCount: 0,
hostResponse: undefined,
};

export default FeaturesDropdown;
11 changes: 11 additions & 0 deletions webpack/react_app/components/FeaturesDropdown/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#schedule-a-job-dropdown ul.pf-c-dropdown__menu {
padding-left: 0;
li {
display: unset;
a {
font-size: 16px;
color: var(--pf-c-dropdown__menu-item--Color);
font-weight: 300;
}
}
}
6 changes: 6 additions & 0 deletions webpack/react_app/extend/Fills.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ const fills = [
component: props => <FeaturesDropdown {...props} />,
weight: 1000,
},
{
slot: '_all-hosts-schedule-a-job',
name: '_all-hosts-schedule-a-job',
component: props => <FeaturesDropdown {...props} />,
weight: 1000,
},
];

const registerFills = () => {
Expand Down
Loading