Skip to content

Commit

Permalink
Add integrations view
Browse files Browse the repository at this point in the history
  • Loading branch information
yenienserrano committed Jan 15, 2025
1 parent 1d43c48 commit 39cd36b
Show file tree
Hide file tree
Showing 5 changed files with 326 additions and 4 deletions.
8 changes: 4 additions & 4 deletions plugins/wazuh-security-policies/public/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@elastic/eui';
import { Router, Route, Switch, Redirect } from 'react-router-dom';
import { getCore, getHistory } from '../plugin-services';
import { IntegrationOverview } from './integretions/overview';

interface ViewInterface {
name: string;
Expand All @@ -20,7 +21,7 @@ const views: ViewInterface[] = [
{
name: 'Integrations',
id: 'integrations',
render: () => <div>Integrations</div>,
render: () => <IntegrationOverview />,
},
{
name: 'Rules',
Expand Down Expand Up @@ -70,14 +71,13 @@ export const WazuhSecurityPoliciesApp = () => {
<Router history={history}>
<I18nProvider>
<>
{/* <EuiPage restrictWidth='1000px'> */}
<EuiPage>
<EuiPage paddingSize='m'>
<EuiPageSideBar>
<EuiSideNav aria-label='Ruleset' items={sideNav} />
</EuiPageSideBar>
<EuiPageBody component='main'>
<EuiPanel
paddingSize='l'
paddingSize='none'
color='transparent'
hasShadow={false}
hasBorder={false}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useState } from 'react';
import { EuiButtonIcon, EuiPopover } from '@elastic/eui';

interface PopoverIconButtonProps {
children?: React.ReactNode;
styles?: React.CSSProperties;
color?: string;
}

export const PopoverIconButton = (props: PopoverIconButtonProps) => {
const { children, styles, color = 'text' } = props;
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const onButtonClick = () => setIsPopoverOpen(isPopoverOpen => !isPopoverOpen);
const closePopover = () => setIsPopoverOpen(false);

return (
<EuiPopover
style={styles}
ownFocus={false}
button={
<EuiButtonIcon
color={color}
onClick={onButtonClick}
iconType='boxesVertical'
aria-label='Options'
/>
}
isOpen={isPopoverOpen}
closePopover={closePopover}
>
{children}
</EuiPopover>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from 'react';
import {
EuiCard,
EuiIcon,
EuiButtonEmpty,
EuiHorizontalRule,
} from '@elastic/eui';
import { PopoverIconButton } from '../../common/popover';

interface CardIntegrationProps {
image: string;
title: string;
description: string;
isEnable: boolean;
}

export const CardIntegration = (props: CardIntegrationProps) => {
const { image = 'logoOpenSearch', title, description, isEnable } = props;
const buttonIntegrations = [
{
id: 'goToDecoder',
label: 'Go to Decoder',
color: 'text',
},
{
id: 'goToRules',
label: 'Go to Rules',
color: 'text',
},
{
id: 'goToKVDB',
label: 'Go to KVDB',
color: 'text',
},
{
id: 'enable/disable',
label: isEnable ? 'Disable' : 'Enable',
color: isEnable ? 'danger' : 'primary',
},
];

return (
<div style={{ position: 'relative' }}>
<EuiCard
title={title}
description={description}
icon={<EuiIcon type={image} size='xl' />}
paddingSize='m'
/>
<PopoverIconButton
styles={{
position: 'absolute',
top: '5px',
right: '5px',
}}
>
<div>
{buttonIntegrations.map((button, index) => (
<span key={button.id}>
<EuiButtonEmpty size='s' color={button.color}>
{button.label}
</EuiButtonEmpty>
{index < buttonIntegrations.length - 1 && (
<EuiHorizontalRule margin='none' />
)}
</span>
))}
</div>
</PopoverIconButton>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.integration-title-header {
display: flex;
align-items: center;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import React, { useState } from 'react';
import {
EuiPageHeader,
EuiLink,
EuiButton,
EuiHealth,
EuiFlexGroup,
EuiFlexItem,
EuiSearchBar,
EuiCallOut,
EuiText,
} from '@elastic/eui';
import './integrations.scss';
import { CardIntegration } from './components/card-integration';

const integrations = [
{
image: 'advancedSettingsApp',
title: 'Integration 1',
description: 'Description for integration 1',
isEnable: true,
},
{
image: 'grokApp',
title: 'Integration 2',
description: 'Description for integration 2',
isEnable: false,
},
{
image: 'grokApp',
title: 'Integration 3',
description: 'Description for integration 3',
isEnable: true,
},
{
image: 'reportingApp',
title: 'Integration 4',
description: 'Description for integration 4',
isEnable: false,
},
{
image: 'heartbeatApp',
title: 'Integration 5',
description: 'Description for integration 5',
isEnable: true,
},
{
image: 'appSearchApp',
title: 'Integration 6',
description: 'Description for integration 6',
isEnable: false,
},
{
image: 'indexRollupApp',
title: 'Integration 7',
description: 'Description for integration 7',
isEnable: true,
},
{
image: 'canvasApp',
title: 'Integration 8',
description: 'Description for integration 8',
isEnable: false,
},
{
image: 'securityApp',
title: 'Integration 9',
description: 'Description for integration 9',
isEnable: true,
},
{
image: 'lensApp',
title: 'Integration 10',
description: 'Description for integration 10',
isEnable: false,
},
];

export const IntegrationOverview = () => {
const [lastUpdate, setLastUpdate] = useState({
lastUpdateDate: '12/18/2024',
status: 'Success',
});
const titleHeader = (
<span className='integration-title-header'>
<h1>Integrations</h1>
<EuiHealth style={{ marginLeft: '10px' }} color='success'>
Updated
</EuiHealth>
</span>
);

const updateContentManager = () => {
const currentDate = new Date().toLocaleString();

setLastUpdate({
lastUpdateDate: currentDate,
status: 'Success',
});
};

// Search bar

const initialQuery = EuiSearchBar.Query.MATCH_ALL;
const [query, setQuery] = useState(initialQuery);
const [error, setError] = useState(null);

const onChange = ({ query, error }) => {
if (error) {
setError(error);
} else {
setError(null);
setQuery(query);
}
};

const filters = [
{
type: 'field_value_selection',
field: 'integration',
name: 'Integrations',
multiSelect: 'and',
operator: 'exact',
cache: 10000, // will cache the loaded tags for 10 sec
options: integrations.map(integration => ({
value: integration.title,
view: <EuiText>{integration.title}</EuiText>,
})),
},
];
const schema = {
strict: true,
fields: {
integration: {
type: 'string',
},
},
};

const renderError = () => {
if (!error) {
return;
}

return (
<>
<EuiCallOut
iconType='faceSad'
color='danger'
title={`Invalid search: ${error.message}`}
/>
</>
);
};

return (
<>
<EuiPageHeader
pageTitle={titleHeader}
description={
<>
Last update of the content manager was {lastUpdate.lastUpdateDate} (
{lastUpdate.status}).{' '}
<EuiLink href='link-documentation' target='_blank'>
Learn more
</EuiLink>
</>
}
rightSideItems={[
<EuiButton
key={`${lastUpdate.lastUpdateDate}-${lastUpdate.status}`}
fill
onClick={updateContentManager}
>
Update
</EuiButton>,
]}
/>
<div style={{ margin: '20px 0' }}>
<EuiSearchBar
defaultQuery={initialQuery}
box={{
placeholder: 'Search...',
schema,
}}
filters={filters}
onChange={onChange}
/>
</div>
{renderError()}
<EuiFlexGroup gutterSize='m' wrap>
{query.text === ''
? integrations.map((integration, index) => (
<EuiFlexItem key={index}>
<CardIntegration {...integration} />
</EuiFlexItem>
))
: integrations
.filter(integration =>
query.text
.toLocaleLowerCase()
.includes(integration.title.toLocaleLowerCase()),
)
.map((integration, index) => (
<EuiFlexItem key={index}>
<CardIntegration {...integration} />
</EuiFlexItem>
))}
</EuiFlexGroup>
</>
);
};

0 comments on commit 39cd36b

Please sign in to comment.