Skip to content

Commit 34526b1

Browse files
Merge pull request #100 from deepfence/96-google-chronicle
Added Google chronicle integration to the integrations page #96
2 parents 9bbcb39 + fd04c38 commit 34526b1

File tree

9 files changed

+205
-1
lines changed

9 files changed

+205
-1
lines changed
21.5 KB
Loading
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* eslint-disable react/destructuring-assignment */
2+
import React, {useState} from 'react';
3+
import withIntegrationForm from '../../../hoc/notification-integration';
4+
5+
const GoogleChronicleForm = (props) => {
6+
const [apiURL, setApiURL] = useState('');
7+
const [authorizationKey, setAuthorizationKey] = useState('');
8+
9+
const handleChange = (e) => {
10+
const { name, value } = e.target;
11+
switch (name) {
12+
case 'apiURL':
13+
setApiURL(value);
14+
break;
15+
case 'authorizationKey':
16+
setAuthorizationKey(value);
17+
break;
18+
default:
19+
break;
20+
}
21+
22+
props.saveChildFormData({
23+
api_url: apiURL,
24+
authorization_key: authorizationKey,
25+
integration_type: "google_chronicle",
26+
apiURL,
27+
authorizationKey,
28+
});
29+
}
30+
31+
const { submitted } = props;
32+
return (
33+
<div>
34+
<div className="row">
35+
<div className="col-md-4">
36+
<div className={`form-group ${(submitted && !apiURL ? 'has-error' : '')}`}>
37+
<label htmlFor="apiURL">
38+
<i className="fa fa-link" aria-hidden="true" />
39+
<input
40+
type="text"
41+
className="form-control"
42+
name="apiURL"
43+
placeholder="API URL"
44+
value={apiURL}
45+
onChange={handleChange}
46+
autoComplete="off"
47+
/>
48+
</label>
49+
{ submitted && !apiURL && <div className="field-error">API URL is required</div> }
50+
</div>
51+
</div>
52+
<div className="col-md-4">
53+
<div className="form-group">
54+
<label htmlFor="authorizationKey">
55+
<i className="fa fa-key" aria-hidden="true" />
56+
<input
57+
type="text"
58+
className="form-control"
59+
name="authorizationKey"
60+
placeholder="Authorization Key (Optional)"
61+
value={authorizationKey}
62+
onChange={handleChange}
63+
autoComplete="off"
64+
/>
65+
</label>
66+
</div>
67+
</div>
68+
</div>
69+
</div>
70+
)
71+
}
72+
73+
const googleChronicleAdd = withIntegrationForm(GoogleChronicleForm);
74+
75+
export default googleChronicleAdd;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react';
2+
import GoogleChronicleListContainer from './list-container';
3+
import GoogleChronicleForm from './add-form';
4+
5+
const GoogleChronicleView = () => (
6+
<div className="email-integration-view-wrapper">
7+
<GoogleChronicleForm />
8+
<GoogleChronicleListContainer />
9+
</div>
10+
)
11+
12+
export default GoogleChronicleView;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react';
2+
import { useSelector } from 'react-redux';
3+
import GoogleChronicleList from './list';
4+
5+
const GoogleChronicleListContainer = (props) => {
6+
const googleChronicleList = useSelector(state => state.availableGoogleChronicleIntegrations)
7+
return (
8+
<GoogleChronicleList
9+
{...props}
10+
googleChronicleList={googleChronicleList}
11+
/>
12+
);
13+
}
14+
15+
export default GoogleChronicleListContainer;
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/* eslint-disable react/destructuring-assignment */
2+
import React from 'react';
3+
import IntegrationTableView from '../../common/integration-table-view/integration-table-view';
4+
import AppLoader from '../../common/app-loader/app-loader';
5+
import {
6+
requestIntegrationDelete,
7+
showModal,
8+
resetIntegrationStates,
9+
} from '../../../actions/app-actions';
10+
import {
11+
NO_INTEGRATION_FOUND_ALERT_MESSAGE
12+
} from '../../../constants/visualization-config';
13+
14+
function getEmptyStateView() {
15+
return (
16+
<div className="empty-state-wrapper">
17+
{ NO_INTEGRATION_FOUND_ALERT_MESSAGE.message }
18+
</div>
19+
);
20+
}
21+
22+
function getTableEmptyState(data) {
23+
const emptyStateWrapper = {
24+
height: '400px',
25+
width: '100%',
26+
display: 'flex',
27+
alignItems: 'center',
28+
justifyContent: 'center'
29+
};
30+
return (
31+
<div style={emptyStateWrapper}>
32+
{ (data === undefined) ? <AppLoader /> : getEmptyStateView() }
33+
</div>
34+
);
35+
}
36+
37+
function isDataAvailable(data) {
38+
let result;
39+
if (data && data.length > 0) {
40+
result = true;
41+
} else {
42+
result = false;
43+
}
44+
return result;
45+
}
46+
47+
const GoogleChronicleList = (props) => {
48+
const resetStates = () => {
49+
props.dispatch(resetIntegrationStates());
50+
}
51+
52+
const getIntegrationTableView = () => {
53+
const { googleChronicleList } = props;
54+
return (
55+
<IntegrationTableView
56+
recordCollection={googleChronicleList}
57+
onDeleteRequestCallback={record => handleDeleteDialog(record)}
58+
/>
59+
);
60+
}
61+
62+
const deleteIntegration = (record) => {
63+
const params = {
64+
id: record.id,
65+
notification_type: record.notification_type,
66+
};
67+
return props.dispatch(requestIntegrationDelete(params));
68+
}
69+
70+
const handleDeleteDialog = (record) => {
71+
const params = {
72+
dialogTitle: 'Delete Integration?',
73+
dialogBody: 'Are you sure you want to delete this Google Chronicle integration?',
74+
confirmButtonText: 'Yes, Delete',
75+
cancelButtonText: 'No, Keep',
76+
onConfirmButtonClick: () => deleteIntegration(record),
77+
};
78+
props.dispatch(showModal('DIALOG_MODAL', params));
79+
resetStates();
80+
}
81+
82+
const { googleChronicleList } = props;
83+
return (
84+
<div className="integration-list-section">
85+
{ isDataAvailable(googleChronicleList)
86+
? getIntegrationTableView()
87+
: getTableEmptyState(googleChronicleList) }
88+
</div>
89+
)
90+
}
91+
92+
export default GoogleChronicleList;

deepfence_ui/app/scripts/components/integration-view/integration-view.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import SplunkIntegrationView from './splunk-integration-view/index';
1717
import ElasticSearchIntegrationView from './elasticsearch-integration-view/index';
1818
import AWSS3IntegrationView from './aws-s3-integration-view/index';
1919
import HTTPEndpointView from './http-endpoint-view/index';
20+
import GoogleChronicleEndpointView from './google-chronicle-view/index';
2021
import JiraIntegrationView from './jira-integration-view';
2122
import SumoLogicView from './sumo-logic-view';
2223
import ReportDownload from './report-download/index';
@@ -129,6 +130,7 @@ class IntegrationView extends React.Component {
129130
'pagerduty':'notification',
130131
'email':'notification',
131132
'http_endpoint':'notification',
133+
'google_chronicle':'notification',
132134
'splunk':'siem',
133135
'elasticsearch':'siem',
134136
'sumo_logic':'siem',
@@ -207,6 +209,9 @@ class IntegrationView extends React.Component {
207209
case 'http_endpoint': {
208210
return <HTTPEndpointView />
209211
}
212+
case 'google_chronicle': {
213+
return <GoogleChronicleEndpointView />
214+
}
210215
case 'jira': {
211216
return <JiraIntegrationView />
212217
}

deepfence_ui/app/scripts/constants/menu-collection.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import JIRA_LOGO from '../../images/jira.png';
88
import SUMO_LOGIC_LOGO from '../../images/sumo-logic.png';
99
import XLSX_LOGO from '../../images/xls.png';
1010
import HTTP_LOGO from '../../images/http.png';
11+
import GOOGLE_CHRONICLE_LOGO from '../../images/google-chronicle.png';
1112
import PDF_LOGO from '../../images/pdf-logo.png';
1213
import MICROSOFT_LOGO from '../../images/microsoft-teams.png';
1314

@@ -33,6 +34,9 @@ export const INTEGRATION_MENU_COLLECTION = [
3334
{
3435
name: 'http_endpoint', isActive: true, icon: HTTP_LOGO, displayName: 'HTTP endpoint', category: 'notification', bgcolor: 'white', parent: 'Notification'
3536
},
37+
{
38+
name: 'google_chronicle', isActive: true, icon: GOOGLE_CHRONICLE_LOGO, displayName: 'Google Chronicle', category: 'notification', bgcolor: 'white', parent: 'Notification'
39+
},
3640
{
3741
name: 'jira', isActive: false, icon: JIRA_LOGO, displayName: 'Jira', category: 'ticketing', bgcolor: '#A6CDFF', parent: 'Ticketing'
3842
},

deepfence_ui/app/scripts/hoc/notification-integration.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ const withIntegrationForm = WrappedComponent => {
151151
childValues.length - 2 === filledValues.length;
152152
}
153153
}
154-
if (childPayload.integration_type === 'http_endpoint') {
154+
if (childPayload.integration_type === 'http_endpoint' || childPayload.integration_type === 'google_chronicle') {
155155
if (!childPayload.authorizationKey) {
156156
childFormComplete =
157157
childValues.length !== 0 &&

deepfence_ui/app/scripts/reducers/root.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ export function rootReducer(state = initialState, action) {
569569
'availableHTTPEndpoints',
570570
action.response.http_endpoint
571571
);
572+
state = state.set('availableGoogleChronicleIntegrations', action.response.google_chronicle);
572573
state = state.set('availableJiraIntegrations', action.response.jira);
573574
state = state.set(
574575
'availableSumoLogicIntegrations',

0 commit comments

Comments
 (0)