Skip to content

Commit

Permalink
log types table; details page with basic editing
Browse files Browse the repository at this point in the history
Signed-off-by: Amardeepsingh Siglani <amardeep7194@gmail.com>
  • Loading branch information
amsiglan committed Jul 27, 2023
1 parent 15f2e2f commit 9139f29
Show file tree
Hide file tree
Showing 27 changed files with 949 additions and 43 deletions.
7 changes: 4 additions & 3 deletions public/components/ContentPanel/ContentPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
EuiPanel,
EuiTitle,
EuiText,
EuiSpacer,
} from '@elastic/eui';

interface ContentPanelProps {
Expand All @@ -19,9 +20,9 @@ interface ContentPanelProps {
subTitleText?: string | JSX.Element;
bodyStyles?: object;
panelStyles?: object;
horizontalRuleClassName?: string;
actions?: React.ReactNode | React.ReactNode[];
children: React.ReactNode | React.ReactNode[];
hideHeaderBorder?: boolean;
className?: string;
}

Expand All @@ -43,9 +44,9 @@ const ContentPanel: React.SFC<ContentPanelProps> = ({
subTitleText = '',
bodyStyles = {},
panelStyles = {},
horizontalRuleClassName = '',
actions,
children,
hideHeaderBorder = false,
className = '',
}) => (
<EuiPanel
Expand Down Expand Up @@ -80,7 +81,7 @@ const ContentPanel: React.SFC<ContentPanelProps> = ({
) : null}
</EuiFlexGroup>

<EuiHorizontalRule margin="xs" className={horizontalRuleClassName} />
{hideHeaderBorder ? <EuiSpacer /> : <EuiHorizontalRule margin="xs" />}

<div style={{ padding: '0px 10px', ...bodyStyles }}>{children}</div>
</EuiPanel>
Expand Down
2 changes: 2 additions & 0 deletions public/models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
RuleService,
NotificationsService,
IndexPatternsService,
LogTypeService,
} from '../services';
import CorrelationService from '../services/CorrelationService';

Expand All @@ -29,6 +30,7 @@ export interface BrowserServices {
notificationsService: NotificationsService;
savedObjectsService: ISavedObjectsService;
indexPatternsService: IndexPatternsService;
logTypeService: LogTypeService;
}

export interface RuleOptions {
Expand Down
115 changes: 115 additions & 0 deletions public/pages/LogTypes/components/LogTypeDetailsTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import {
EuiButton,
EuiDescriptionList,
EuiFormRow,
EuiFieldText,
EuiSpacer,
EuiTextArea,
EuiBottomBar,
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
} from '@elastic/eui';
import { ContentPanel } from '../../../components/ContentPanel';
import React from 'react';
import { LogTypeItem } from '../../../../types';
import { DataStore } from '../../../store/DataStore';

export interface LogTypeDetailsTabProps {
initialLogTypeDetails: LogTypeItem;
logTypeDetails: LogTypeItem;
isEditMode: boolean;
setIsEditMode: (isEdit: boolean) => void;
setLogTypeDetails: (logType: LogTypeItem) => void;
}

export const LogTypeDetailsTab: React.FC<LogTypeDetailsTabProps> = ({
initialLogTypeDetails,
logTypeDetails,
isEditMode,
setIsEditMode,
setLogTypeDetails,
}) => {
const onUpdateLogType = async () => {
const success = await DataStore.logTypes.updateLogType(logTypeDetails);
if (success) {
setIsEditMode(false);
}
};

return (
<ContentPanel
title="Details"
actions={!isEditMode && [<EuiButton onClick={() => setIsEditMode(true)}>Edit</EuiButton>]}
>
<EuiDescriptionList
type="column"
listItems={[
{
title: 'Log type',
description: (
<>
<EuiFormRow label="Name">
<EuiFieldText
value={logTypeDetails?.name}
onChange={(e) =>
setLogTypeDetails({
...logTypeDetails!,
name: e.target.value,
})
}
placeholder="Enter name for log type"
disabled={!isEditMode || !!logTypeDetails.detectionRules}
/>
</EuiFormRow>
<EuiSpacer />
<EuiFormRow label="Description">
<EuiTextArea
value={logTypeDetails?.description}
onChange={(e) =>
setLogTypeDetails({
...logTypeDetails!,
description: e.target.value,
})
}
placeholder="Description of the log type"
disabled={!isEditMode}
/>
</EuiFormRow>
{isEditMode ? (
<EuiBottomBar>
<EuiFlexGroup gutterSize="s" justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty
color="ghost"
size="s"
iconType="cross"
onClick={() => {
setLogTypeDetails(initialLogTypeDetails);
setIsEditMode(false);
}}
>
Cancel
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton color="primary" fill size="s" onClick={onUpdateLogType}>
Update
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiBottomBar>
) : null}
</>
),
},
]}
/>
</ContentPanel>
);
};
10 changes: 10 additions & 0 deletions public/pages/LogTypes/components/LogTypeDetectionRules.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export interface LogTypeDetectionRulesProps {
logTypeId: string;
}

export const LogTypeDetectionRules = () => {};
137 changes: 137 additions & 0 deletions public/pages/LogTypes/containers/LogTypeDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useContext } from 'react';
import { useState } from 'react';
import { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { LogTypeItem } from '../../../../types';
import {
EuiDescriptionList,
EuiFlexGroup,
EuiFlexItem,
EuiLoadingSpinner,
EuiPanel,
EuiSpacer,
EuiTab,
EuiTabs,
EuiTitle,
} from '@elastic/eui';
import { DataStore } from '../../../store/DataStore';
import { CoreServicesContext } from '../../../components/core_services';
import { BREADCRUMBS } from '../../../utils/constants';
import { logTypeDetailsTabs } from '../utils/constants';
import { LogTypeDetailsTab } from '../components/LogTypeDetailsTab';

export interface LogTypeDetailsProps {}

export const LogTypeDetails: React.FC<LogTypeDetailsProps> = () => {
const context = useContext(CoreServicesContext);
const { logTypeId } = useParams<{ logTypeId: string }>();
const [selectedTabId, setSelectedTabId] = useState('details');
const [infoText, setInfoText] = useState<React.ReactNode | string>(
<>
Loading details &nbsp;
<EuiLoadingSpinner size="l" />
</>
);
const [logTypeDetails, setLogTypeDetails] = useState<LogTypeItem | undefined>(undefined);
const [initialLogTypeDetails, setInitialLogTypeDetails] = useState<LogTypeItem | undefined>(
undefined
);

const [isEditMode, setIsEditMode] = useState(false);

useEffect(() => {
const getLogTypeDetails = async () => {
const details = await DataStore.logTypes.getLogType(logTypeId);

if (!details) {
setInfoText('Log type not found!');
return;
}

setInitialLogTypeDetails(details);
setLogTypeDetails(details);
};

context?.chrome.setBreadcrumbs([
BREADCRUMBS.SECURITY_ANALYTICS,
BREADCRUMBS.DETECTORS,
BREADCRUMBS.LOG_TYPES,
{ text: logTypeId },
]);
getLogTypeDetails();
}, []);

const renderTabContent = () => {
switch (selectedTabId) {
case 'detection_rules':
return null;
case 'details':
default:
return (
<LogTypeDetailsTab
initialLogTypeDetails={initialLogTypeDetails!}
logTypeDetails={logTypeDetails!}
isEditMode={isEditMode}
setIsEditMode={setIsEditMode}
setLogTypeDetails={setLogTypeDetails}
/>
);
}
};

return !logTypeDetails ? (
<EuiTitle>
<h2>{infoText}</h2>
</EuiTitle>
) : (
<>
<EuiTitle>
<h1>{logTypeDetails.name}</h1>
</EuiTitle>
<EuiSpacer />
<EuiPanel grow={false}>
<EuiDescriptionList
listItems={[{ title: 'Description', description: logTypeDetails.description }]}
/>
<EuiSpacer />
<EuiFlexGroup>
<EuiFlexItem>
<EuiDescriptionList listItems={[{ title: 'ID', description: logTypeDetails.id }]} />
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionList
listItems={[{ title: 'Detection rules', description: logTypeDetails.detectionRules }]}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionList
listItems={[{ title: 'Source', description: logTypeDetails.source }]}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
<EuiSpacer />
<EuiTabs>
{logTypeDetailsTabs.map((tab, index) => {
return (
<EuiTab
onClick={() => {
setSelectedTabId(tab.id);
}}
key={index}
isSelected={selectedTabId === tab.id}
>
{tab.name}
</EuiTab>
);
})}
</EuiTabs>
{renderTabContent()}
</>
);
};
61 changes: 61 additions & 0 deletions public/pages/LogTypes/containers/LogTypes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useContext, useEffect, useState } from 'react';
import { EuiInMemoryTable } from '@elastic/eui';
import { ContentPanel } from '../../../components/ContentPanel';
import { CoreServicesContext } from '../../../components/core_services';
import { BREADCRUMBS, ROUTES } from '../../../utils/constants';
import { LogType } from '../../../../types';
import { DataStore } from '../../../store/DataStore';
import { getLogTypesTableColumns } from '../utils/helpers';
import { RouteComponentProps } from 'react-router-dom';
import { useCallback } from 'react';

export interface LogTypesProps extends RouteComponentProps {}

export const LogTypes: React.FC<LogTypesProps> = ({ history }) => {
const context = useContext(CoreServicesContext);
const [logTypes, setLogTypes] = useState<LogType[]>([]);

useEffect(() => {
context?.chrome.setBreadcrumbs([
BREADCRUMBS.SECURITY_ANALYTICS,
BREADCRUMBS.DETECTORS,
BREADCRUMBS.LOG_TYPES,
]);
const getLogTypes = async () => {
const logTypes = await DataStore.logTypes.getLogTypes();
setLogTypes(logTypes);
};

getLogTypes();
}, []);

const showLogTypeDetails = useCallback((id: string) => {
history.push(`${ROUTES.LOG_TYPES}/${id}`);
}, []);

return (
<ContentPanel
title={'Log types'}
subTitleText={
'Log types describe the data sources the detection rules are meant to be applied to.'
}
hideHeaderBorder
>
<EuiInMemoryTable
items={logTypes}
columns={getLogTypesTableColumns(showLogTypeDetails, (id: string) =>
alert(`Deleted ${id}`)
)}
pagination={{
initialPageSize: 25,
}}
sorting={true}
/>
</ContentPanel>
);
};
15 changes: 15 additions & 0 deletions public/pages/LogTypes/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export const logTypeDetailsTabs = [
{
id: 'details',
name: 'Details',
},
{
id: 'detection_rules',
name: 'Detection rules',
},
];
Loading

0 comments on commit 9139f29

Please sign in to comment.