diff --git a/app/controllers/ui_ansible_roles_controller.rb b/app/controllers/ui_ansible_roles_controller.rb index 364bedc97..78bb4aaff 100644 --- a/app/controllers/ui_ansible_roles_controller.rb +++ b/app/controllers/ui_ansible_roles_controller.rb @@ -1,4 +1,7 @@ class UiAnsibleRolesController < ::Api::V2::BaseController + + before_action :find_resource, :only => [:destroy] + def resource_name(resource = 'AnsibleRole') super resource end @@ -7,6 +10,12 @@ def index @ui_ansible_roles = resource_scope_for_index(:permission => :view_ansible_roles) end + api :DELETE, '/ui_ansible_roles/:id', N_('Deletes Ansible role') + param :id, :identifier, :required => true + def destroy + AnsibleRole.find_by(id: params[:id]).destroy + end + # restore original method from find_common to ignore resource nesting def resource_scope(**kwargs) @resource_scope ||= scope_for(resource_class, **kwargs) diff --git a/app/views/ansible_roles/index.html.erb b/app/views/ansible_roles/index.html.erb index def0fd832..35dcda643 100644 --- a/app/views/ansible_roles/index.html.erb +++ b/app/views/ansible_roles/index.html.erb @@ -1,47 +1,9 @@ +<%= webpacked_plugins_js_for :foreman_ansible %> +<%= webpacked_plugins_css_for :foreman_ansible %> + <% title _("Ansible Roles") %> <% title_actions ansible_proxy_import(hash_for_import_ansible_roles_path), documentation_button('#4.1ImportingRoles', :root_url => ansible_doc_url) %> - - - - - - - - - - - - - <% @ansible_roles.each do |role| %> - - - - - - - - - <% end %> - -
<%= sort :name, :as => s_("Role|Name") %><%= _("Hostgroups") %><%= _("Hosts") %><%= _("Variables") %><%= sort :updated_at, :as => _("Imported at") %><%= _("Actions") %>
<%= role.name %><%= link_to role.hostgroups.count, hostgroups_path(:search => "ansible_role = #{role.name}") %><%= link_to role.hosts.count, hosts_path(:search => "ansible_role = #{role.name}")%><%= link_to(role.ansible_variables.count, ansible_variables_path(:search => "ansible_role = #{role}")) %><%= import_time role %> - <% - links = [ - link_to( - _('Variables'), - ansible_variables_path(:search => "ansible_role = #{role}") - ), - display_delete_if_authorized( - hash_for_ansible_role_path(:id => role). - merge(:auth_object => role, :authorizer => authorizer), - :data => { :confirm => _("Delete %s?") % role.name }, - :action => :delete - ) - ] - %> - <%= action_buttons(*links) %> -
- <%= will_paginate_with_info @ansible_roles %> diff --git a/app/views/ui_ansible_roles/show.json.rabl b/app/views/ui_ansible_roles/show.json.rabl index a90699275..441681175 100644 --- a/app/views/ui_ansible_roles/show.json.rabl +++ b/app/views/ui_ansible_roles/show.json.rabl @@ -1,3 +1,18 @@ object @ansible_role -extends "api/v2/ansible_roles/show" +attributes :id, :name +code :hostgroupsCount do |role| + role.hostgroups.count +end +code :hostsCount do |role| + role.hosts.count +end +code :variablesCount do |role| + role.ansible_variables.count +end +code :importTime do |role| + import_time(role) +end +code :can_delete do |role| + authorized_for(:controller => UiAnsibleRolesController, :action => :destroy) +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 1a0431e4f..82a75d00e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,7 +60,7 @@ end end - resources :ui_ansible_roles, :only => [:index] + resources :ui_ansible_roles, :only => [:index, :destroy] resources :ansible_variables, :except => [:show] do resources :lookup_values, :only => [:index, :create, :update, :destroy] @@ -117,4 +117,5 @@ match '/ansible/hostgroups' => 'react#index', :via => [:get] match '/ansible/hostgroups/*page' => 'react#index', :via => [:get] + match '/ansible/ansible_roles' => 'react#index', :via => [:get] end diff --git a/webpack/components/AnsibleRoles/AnsibleRolesPage.js b/webpack/components/AnsibleRoles/AnsibleRolesPage.js new file mode 100644 index 000000000..93a634de1 --- /dev/null +++ b/webpack/components/AnsibleRoles/AnsibleRolesPage.js @@ -0,0 +1,34 @@ +import React from 'react'; +import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableIndexPage'; +import { translate as __ } from 'foremanReact/common/I18n'; +import { getDocsURL } from 'foremanReact/common/helpers'; +import { AnsibleRolesImportButton } from './components/AnsibleRolesImportButton'; +import { getActions } from '../AnsibleRoles/AnsibleRolesPageHelpers'; + +export const AnsibleRolesPage = () => ( + Primary + } + customHelpURL={getDocsURL( + 'Managing_Configurations_Ansible', + 'Importing_Ansible_Roles_and_Variables_ansible' + )} + rowKebabItems={getActions} + columns={{ + importTime: { title: __('Imported at'), isSorted: true }, + variablesCount: { title: __('Variables') }, + hostsCount: { title: __('Hosts') }, + hostgroupsCount: { title: __('Hostgroups') }, + name: { title: __('Name'), isSorted: true }, + }} + /> +); diff --git a/webpack/components/AnsibleRoles/AnsibleRolesPageHelpers.js b/webpack/components/AnsibleRoles/AnsibleRolesPageHelpers.js new file mode 100644 index 000000000..b8a263816 --- /dev/null +++ b/webpack/components/AnsibleRoles/AnsibleRolesPageHelpers.js @@ -0,0 +1,38 @@ +import React from 'react'; +import { translate as __ } from 'foremanReact/common/I18n'; + +export const getActions = ({ id, name, canDelete, ...item }) => [ + { + title: ( + + {__('View Hostgroups')} + + ), + isDisabled: false, + }, + { + title: ( + + {__('View Hosts')} + + ), + isDisabled: false, + }, + { + title: ( + + {__('View Variables')} + + ), + isDisabled: false, + }, +]; + +const hostgroupsUrl = roleName => `/hostgroups${searchString(roleName)}`; +const hostsUrl = roleName => `/hosts${searchString(roleName)}`; +const variablesUrl = roleName => `ansible_variables${searchString(roleName)}`; +const searchString = roleName => + `?search=${encodeURIComponent(`ansible_role = ${roleName}`)}`; + +export const importUrl = (proxyName, proxyId) => + `ansible_roles/import?proxy=${encodeURIComponent(`${proxyId}-${proxyName}`)}`; diff --git a/webpack/components/AnsibleRoles/components/AnsibleRolesImportButton.js b/webpack/components/AnsibleRoles/components/AnsibleRolesImportButton.js new file mode 100644 index 000000000..ca77c79d8 --- /dev/null +++ b/webpack/components/AnsibleRoles/components/AnsibleRolesImportButton.js @@ -0,0 +1,68 @@ +import React from 'react'; +import { Dropdown, DropdownToggle, DropdownItem } from '@patternfly/react-core'; +import { translate as __ } from 'foremanReact/common/I18n'; +import { useAPI } from 'foremanReact/common/hooks/API/APIHooks'; +import { importUrl } from '../AnsibleRolesPageHelpers'; + +export const AnsibleRolesImportButton = () => { + let dropdownItems; + + const { + response: { results }, + status, + } = useAPI('get', '/api/v2/smart_proxies'); + + const [isOpen, setIsOpen] = React.useState(false); + const onToggle = isToggleOpen => { + setIsOpen(isToggleOpen); + }; + const onFocus = () => { + const element = document.getElementById('toggle-primary'); + element.focus(); + }; + const onSelect = () => { + setIsOpen(false); + onFocus(); + }; + + if (status !== 'RESOLVED') { + dropdownItems = [ + {__('Loading...')}, + ]; + } else { + dropdownItems = results + .filter(result => + result.features.some(feature => + feature.capabilities.includes('ansible') + ) + ) + .map(proxy => ( + + {proxy.name} + + )); + if (dropdownItems.length === 0) { + dropdownItems = [ + + {__('No Smart Proxies found')} + , + ]; + } + } + return ( + + {__('Import from')} + + } + isOpen={isOpen} + dropdownItems={dropdownItems} + /> + ); +}; diff --git a/webpack/routes/AnsibleRoles/index.js b/webpack/routes/AnsibleRoles/index.js new file mode 100644 index 000000000..0b090504a --- /dev/null +++ b/webpack/routes/AnsibleRoles/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { Helmet } from 'react-helmet'; +import { translate as __ } from 'foremanReact/common/I18n'; + +import { AnsibleRolesPage } from '../../components/AnsibleRoles/AnsibleRolesPage'; + +const AnsibleRoles = () => ( + + + {__('Ansible Roles')} + + + +); + +export default AnsibleRoles; diff --git a/webpack/routes/routes.js b/webpack/routes/routes.js index 6e996c06a..933734a60 100644 --- a/webpack/routes/routes.js +++ b/webpack/routes/routes.js @@ -1,5 +1,6 @@ import React from 'react'; import HostgroupJobs from './HostgroupJobs'; +import AnsibleRoles from './AnsibleRoles'; export default [ { @@ -7,4 +8,9 @@ export default [ render: props => , exact: true, }, + { + path: '/ansible/ansible_roles', + render: props => , + exact: true, + }, ];