Skip to content

Commit 363f677

Browse files
committed
Add Credential Mapping to Workflows Page
1 parent 08e4114 commit 363f677

File tree

17 files changed

+4715
-1
lines changed

17 files changed

+4715
-1
lines changed

app/controllers/workflow_controller.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,23 @@ def show_searchbar?
2323
end
2424

2525
def button
26-
if params[:pressed] == "embedded_configuration_script_payload_tag"
26+
case params[:pressed]
27+
when 'embedded_configuration_script_payload_map_credentials'
28+
javascript_redirect(:action => 'map_credentials', :id => params[:miq_grid_checks])
29+
when 'embedded_configuration_script_payload_tag'
2730
tag(self.class.model)
2831
end
2932
end
3033

34+
def map_credentials
35+
assert_privileges('embedded_configuration_script_payload_map_credentials')
36+
workflow = find_record_with_rbac(self.class.model, params[:id])
37+
drop_breadcrumb(:name => _("Map Credentials to \"%{name}\"") % {:name => workflow.name},
38+
:url => "/workflow/map_credentials/#{params[:id]}")
39+
@in_a_form = true
40+
@id = workflow.id
41+
end
42+
3143
def toolbar
3244
%w[show_list].include?(@lastaction) ? 'workflows_center' : 'workflow_center'
3345
end

app/helpers/application_helper/toolbar/workflow_center.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
class ApplicationHelper::Toolbar::WorkflowCenter < ApplicationHelper::Toolbar::Basic
22
button_group('workflows_policy', [
3+
select(
4+
:workflow_configuration,
5+
nil,
6+
t = N_('Configuration'),
7+
t,
8+
:items => [
9+
button(
10+
:embedded_configuration_script_payload_map_credentials,
11+
'pficon pficon-edit fa-lg',
12+
t = N_('Map Credentials to this Workflow'),
13+
t,
14+
:klass => ApplicationHelper::Button::EmbeddedWorkflow,
15+
:url => "/map_credentials"
16+
),
17+
]
18+
),
319
select(
420
:workflows_policy_choice,
521
nil,

app/helpers/application_helper/toolbar/workflows_center.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
class ApplicationHelper::Toolbar::WorkflowsCenter < ApplicationHelper::Toolbar::Basic
22
button_group('workflows_policy', [
3+
select(
4+
:workflows_configuration,
5+
nil,
6+
t = N_('Configuration'),
7+
t,
8+
:items => [
9+
button(
10+
:embedded_configuration_script_payload_map_credentials,
11+
'pficon pficon-edit fa-lg',
12+
t = N_('Map Credentials to this Workflow'),
13+
t,
14+
:klass => ApplicationHelper::Button::EmbeddedWorkflow,
15+
:enabled => false,
16+
:onwhen => "1",
17+
:url_parms => "edit_div",
18+
:send_checked => true
19+
),
20+
]
21+
),
322
select(
423
:workflows_policy_choice,
524
nil,

app/javascript/components/miq-data-table/miq-table-cell.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ const MiqTableCell = ({
121121
disabled={item.disabled}
122122
onKeyPress={(e) => cellButtonEvent(item, e)}
123123
tabIndex={0}
124+
size={item.size ? item.size : ''}
124125
title={item.title ? item.title : truncateText}
125126
kind={item.kind ? item.kind : 'primary'}
126127
className={classNames('miq-data-table-button', item.buttonClassName)}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
import { useFieldApi, useFormApi } from '@@ddf';
3+
import MiqDataTable from '../miq-data-table';
4+
5+
export const CredentialMapperComponent = (props) => {
6+
const { rows, onCellClick } = useFieldApi(props);
7+
const formOptions = useFormApi();
8+
9+
return (
10+
<div className="credential-mapper-data-table">
11+
<MiqDataTable
12+
headers={[
13+
{ key: 'CredentialsIdentifier', header: __('Credentials Identifier') },
14+
{ key: 'CredentialRecord', header: __('Credential Record') },
15+
{ key: 'CredentialField', header: __('Credential Field') },
16+
{ key: 'Delete', header: __('Delete') },
17+
]}
18+
rows={rows}
19+
size="md"
20+
onCellClick={(selectedRow, cellType) => onCellClick(selectedRow, cellType, formOptions)}
21+
/>
22+
</div>
23+
);
24+
};
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import React, { useState, useEffect } from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
import MiqFormRenderer from '@@ddf';
5+
import { CredentialMapperComponent } from './helper';
6+
import componentMapper from '../../forms/mappers/componentMapper';
7+
import createSchema from './workflow-credential-mapping-form.schema';
8+
import miqRedirectBack from '../../helpers/miq-redirect-back';
9+
10+
const WorkflowCredentialMappingForm = ({ recordId }) => {
11+
const [{
12+
credentials,
13+
credentialReferences,
14+
payloadCredentials,
15+
workflowAuthentications,
16+
initialValues,
17+
isLoading,
18+
}, setState] = useState({ isLoading: !!recordId });
19+
const submitLabel = !!recordId ? __('Save') : __('Add');
20+
21+
// custom component mapper
22+
const mapper = {
23+
...componentMapper,
24+
'credential-mapper': CredentialMapperComponent,
25+
};
26+
27+
useEffect(() => {
28+
// eslint-disable-next-line camelcase
29+
API.get(
30+
`/api/authentications?expand=resources&filter[]=type='ManageIQ::Providers::Workflows::AutomationManager::WorkflowCredential'`
31+
).then(({ resources }) => {
32+
API.get(`/api/configuration_script_payloads/${recordId}`).then(({ name, payload, credentials }) => {
33+
const initialCredentials = credentials != null ? credentials : {};
34+
35+
/*
36+
Creates the list of credential references from the workflow payload by parsing each state and saving them to payloadCredentials.
37+
Duplicate references get overridden.
38+
*/
39+
const jsonPayload = JSON.parse(payload).States;
40+
let payloadCredentials = {};
41+
42+
Object.keys(jsonPayload).forEach((key1) => {
43+
if (jsonPayload[key1].Credentials != null) {
44+
Object.keys(jsonPayload[key1].Credentials).forEach((key2) => {
45+
payloadCredentials = {
46+
[key2]: jsonPayload[key1].Credentials[key2],
47+
...payloadCredentials,
48+
};
49+
});
50+
}
51+
});
52+
53+
// Returns the user to the show_list page if the workflow has no credential references in it's payload
54+
if (Object.keys(payloadCredentials).length === 0) {
55+
throw __('Workflow does not have any credentials to map.');
56+
}
57+
58+
/*
59+
payloadCredentials -> list of credential references for this workflow
60+
workflowAuthentications -> list of available workflow credentials
61+
credentials -> List of currently mapped reference-credential parings
62+
*/
63+
setState({
64+
payloadCredentials,
65+
workflowAuthentications: Object.keys(resources).map((key) => ({
66+
value: resources[key].ems_ref,
67+
label: resources[key].name,
68+
})),
69+
credentials: initialCredentials,
70+
initialValues: {
71+
name,
72+
credentials: initialCredentials,
73+
},
74+
isLoading: false,
75+
});
76+
}).catch((error) => {
77+
const message = __('Embedded Workflow service is not available.');
78+
miqRedirectBack(error || message, 'error', '/workflow/show_list');
79+
});
80+
}).catch(() => {
81+
const message = __('Embedded Workflow service is not available.');
82+
miqRedirectBack(message, 'error', '/workflow/show_list');
83+
});
84+
}, []);
85+
86+
const onSubmit = () => {
87+
miqSparkleOn();
88+
89+
const submission = { credentials };
90+
91+
const request = API.patch(`/api/configuration_script_payloads/${recordId}`, submission);
92+
request.then(() => {
93+
const message = sprintf(__('Credential Mapping for "%s" was saved.'), initialValues.name);
94+
miqRedirectBack(message, undefined, '/workflow/show_list');
95+
}).catch(miqSparkleOff);
96+
};
97+
98+
const onReset = () => {
99+
setState((state) => ({
100+
...state,
101+
credentials: state.initialValues.credentials,
102+
}));
103+
};
104+
105+
const onCancel = () => {
106+
const message = sprintf(__('Credential Mapping for "%s" was canceled by the user.'), initialValues && initialValues.name);
107+
miqRedirectBack(message, 'warning', '/workflow/show_list');
108+
};
109+
110+
return !isLoading && (
111+
<MiqFormRenderer
112+
schema={createSchema(credentials, credentialReferences, payloadCredentials, workflowAuthentications, setState)}
113+
initialValues={initialValues}
114+
componentMapper={mapper}
115+
canReset={!!recordId}
116+
onReset={onReset}
117+
onSubmit={onSubmit}
118+
onCancel={onCancel}
119+
buttonsLabels={{ submitLabel }}
120+
/>
121+
);
122+
};
123+
124+
WorkflowCredentialMappingForm.propTypes = {
125+
recordId: PropTypes.string,
126+
};
127+
WorkflowCredentialMappingForm.defaultProps = {
128+
recordId: undefined,
129+
};
130+
131+
export default WorkflowCredentialMappingForm;

0 commit comments

Comments
 (0)