diff --git a/public/pages/LogTypes/components/DeleteLogTypeModal.tsx b/public/pages/LogTypes/components/DeleteLogTypeModal.tsx
new file mode 100644
index 000000000..be9749a03
--- /dev/null
+++ b/public/pages/LogTypes/components/DeleteLogTypeModal.tsx
@@ -0,0 +1,115 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiButton,
+ EuiCallOut,
+ EuiConfirmModal,
+ EuiFieldText,
+ EuiForm,
+ EuiFormRow,
+ EuiLoadingSpinner,
+ EuiModal,
+ EuiModalBody,
+ EuiModalFooter,
+ EuiModalHeader,
+ EuiModalHeaderTitle,
+ EuiOverlayMask,
+ EuiSpacer,
+} from '@elastic/eui';
+import React from 'react';
+import { useState } from 'react';
+
+export interface DeleteLogTypeModalProps {
+ logTypeName: string;
+ detectionRulesCount: number;
+ loading?: boolean;
+ closeModal: () => void;
+ onConfirm: () => void;
+}
+
+export const DeleteLogTypeModal: React.FC = ({
+ detectionRulesCount,
+ logTypeName,
+ loading,
+ closeModal,
+ onConfirm,
+}) => {
+ const [confirmDeleteText, setConfirmDeleteText] = useState('');
+
+ if (loading) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ const onConfirmClick = () => {
+ onConfirm();
+ closeModal();
+ };
+
+ return (
+
+ {detectionRulesCount > 0 ? (
+
+
+
+ This log type can't be deleted
+
+
+
+ 1 ? 'rules' : 'rule'
+ }.`}
+ iconType={'iInCircle'}
+ color="warning"
+ />
+
+
+ Only log types that don’t have any associated rules can be deleted. Consider editing
+ log type or deleting associated detection rules.
+
+
+
+
+ Close
+
+
+
+ ) : (
+
+
+ The log type will be permanently deleted. This action is irreversible.
+
+
+ Type {logTypeName} to confirm
+
+
+ setConfirmDeleteText(e.target.value)}
+ />
+
+
+
+ )}
+
+ );
+};
diff --git a/public/pages/LogTypes/components/LogTypeDetails.tsx b/public/pages/LogTypes/components/LogTypeDetails.tsx
new file mode 100644
index 000000000..5b4090a20
--- /dev/null
+++ b/public/pages/LogTypes/components/LogTypeDetails.tsx
@@ -0,0 +1,72 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiButton, EuiDescriptionList } from '@elastic/eui';
+import { ContentPanel } from '../../../components/ContentPanel';
+import React from 'react';
+import { LogTypeItem } from '../../../../types';
+import { DataStore } from '../../../store/DataStore';
+import { LogTypeForm } from './LogTypeForm';
+import { NotificationsStart } from 'opensearch-dashboards/public';
+
+export interface LogTypeDetailsProps {
+ initialLogTypeDetails: LogTypeItem;
+ logTypeDetails: LogTypeItem;
+ isEditMode: boolean;
+ notifications: NotificationsStart;
+ setIsEditMode: (isEdit: boolean) => void;
+ setLogTypeDetails: (logType: LogTypeItem) => void;
+}
+
+export const LogTypeDetails: React.FC = ({
+ initialLogTypeDetails,
+ logTypeDetails,
+ isEditMode,
+ notifications,
+ setIsEditMode,
+ setLogTypeDetails,
+}) => {
+ const onUpdateLogType = async () => {
+ const success = await DataStore.logTypes.updateLogType(logTypeDetails);
+ if (success) {
+ setIsEditMode(false);
+ }
+ };
+
+ return (
+ setIsEditMode(true)}>Edit,
+ ]
+ }
+ >
+ {
+ setLogTypeDetails(initialLogTypeDetails);
+ setIsEditMode(false);
+ }}
+ onConfirm={onUpdateLogType}
+ />
+ ),
+ },
+ ]}
+ />
+
+ );
+};
diff --git a/public/pages/LogTypes/components/LogTypeDetectionRules.tsx b/public/pages/LogTypes/components/LogTypeDetectionRules.tsx
index 765f03c37..8d2b4fd90 100644
--- a/public/pages/LogTypes/components/LogTypeDetectionRules.tsx
+++ b/public/pages/LogTypes/components/LogTypeDetectionRules.tsx
@@ -3,8 +3,30 @@
* SPDX-License-Identifier: Apache-2.0
*/
+import React from 'react';
+import { RulesTable } from '../../Rules/components/RulesTable/RulesTable';
+import { RuleTableItem } from '../../Rules/utils/helpers';
+import { ContentPanel } from '../../../components/ContentPanel';
+import { EuiButton } from '@elastic/eui';
+
export interface LogTypeDetectionRulesProps {
- logTypeId: string;
+ rules: RuleTableItem[];
+ loadingRules: boolean;
+ refreshRules: () => void;
}
-export const LogTypeDetectionRules = () => {};
+export const LogTypeDetectionRules: React.FC = ({
+ rules,
+ loadingRules,
+ refreshRules,
+}) => {
+ return (
+ Refresh]}
+ >
+ {}} />
+
+ );
+};
diff --git a/public/pages/LogTypes/components/LogTypeForm.tsx b/public/pages/LogTypes/components/LogTypeForm.tsx
new file mode 100644
index 000000000..ce0b6ebb4
--- /dev/null
+++ b/public/pages/LogTypes/components/LogTypeForm.tsx
@@ -0,0 +1,124 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ EuiBottomBar,
+ EuiButton,
+ EuiButtonEmpty,
+ EuiFieldText,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiFormRow,
+ EuiSpacer,
+ EuiTextArea,
+} from '@elastic/eui';
+import { LogTypeItem } from '../../../../types';
+import React from 'react';
+import { validateName } from '../../../utils/validation';
+import { NotificationsStart } from 'opensearch-dashboards/public';
+import { useState } from 'react';
+
+export interface LogTypeFormProps {
+ logTypeDetails: LogTypeItem;
+ isEditMode: boolean;
+ confirmButtonText: string;
+ notifications: NotificationsStart;
+ setLogTypeDetails: (logType: LogTypeItem) => void;
+ onCancel: () => void;
+ onConfirm: () => void;
+}
+
+export const LogTypeForm: React.FC = ({
+ logTypeDetails,
+ isEditMode,
+ confirmButtonText,
+ notifications,
+ setLogTypeDetails,
+ onCancel,
+ onConfirm,
+}) => {
+ const [nameError, setNameError] = useState('');
+
+ const updateErrors = (details = logTypeDetails) => {
+ const nameInvalid = !validateName(details.name);
+ setNameError(nameInvalid ? 'Invalid name' : '');
+
+ return { nameInvalid };
+ };
+ const onConfirmClicked = () => {
+ const { nameInvalid } = updateErrors();
+
+ if (nameInvalid) {
+ notifications?.toasts.addDanger({
+ title: `Failed to ${confirmButtonText.toLowerCase()}`,
+ text: `Fix the marked errors.`,
+ toastLifeTimeMs: 3000,
+ });
+
+ return;
+ }
+ onConfirm();
+ };
+
+ return (
+ <>
+
+ {
+ const newLogType = {
+ ...logTypeDetails!,
+ name: e.target.value,
+ };
+ setLogTypeDetails(newLogType);
+ updateErrors(newLogType);
+ }}
+ placeholder="Enter name for the log type"
+ disabled={!isEditMode || !!logTypeDetails.detectionRules}
+ />
+
+
+
+ {
+ const newLogType = {
+ ...logTypeDetails!,
+ description: e.target.value,
+ };
+ setLogTypeDetails(newLogType);
+ updateErrors(newLogType);
+ }}
+ placeholder="Description of the log type"
+ disabled={!isEditMode}
+ />
+
+ {isEditMode ? (
+
+
+
+
+ Cancel
+
+
+
+
+ {confirmButtonText}
+
+
+
+
+ ) : null}
+ >
+ );
+};
diff --git a/public/pages/LogTypes/containers/CreateLogType.tsx b/public/pages/LogTypes/containers/CreateLogType.tsx
new file mode 100644
index 000000000..1d11974ba
--- /dev/null
+++ b/public/pages/LogTypes/containers/CreateLogType.tsx
@@ -0,0 +1,67 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { EuiLink } from '@elastic/eui';
+import { ContentPanel } from '../../../components/ContentPanel';
+import React, { useContext, useState } from 'react';
+import { LogTypeForm } from '../components/LogTypeForm';
+import { LogTypeBase } from '../../../../types';
+import { defaultLogType } from '../utils/constants';
+import { RouteComponentProps } from 'react-router-dom';
+import { BREADCRUMBS, ROUTES } from '../../../utils/constants';
+import { CoreServicesContext } from '../../../components/core_services';
+import { useEffect } from 'react';
+import { DataStore } from '../../../store/DataStore';
+import { successNotificationToast } from '../../../utils/helpers';
+import { NotificationsStart } from 'opensearch-dashboards/public';
+
+export interface CreateLogTypeProps extends RouteComponentProps {
+ notifications: NotificationsStart;
+}
+
+export const CreateLogType: React.FC = ({ history, notifications }) => {
+ const [logTypeDetails, setLogTypeDetails] = useState({ ...defaultLogType });
+ const context = useContext(CoreServicesContext);
+
+ useEffect(() => {
+ context?.chrome.setBreadcrumbs([
+ BREADCRUMBS.SECURITY_ANALYTICS,
+ BREADCRUMBS.DETECTORS,
+ BREADCRUMBS.LOG_TYPES,
+ BREADCRUMBS.LOG_TYPE_CREATE,
+ ]);
+ }, []);
+
+ return (
+
+ Create log type to categorize and identify detection rules for your data sources. {' '}
+
+ Learn more
+
+
+ }
+ hideHeaderBorder={true}
+ >
+ history.push(ROUTES.LOG_TYPES)}
+ onConfirm={async () => {
+ const success = await DataStore.logTypes.createLogType(logTypeDetails);
+ if (success) {
+ successNotificationToast(notifications, 'created', `log type ${logTypeDetails.name}`);
+ history.push(ROUTES.LOG_TYPES);
+ }
+ }}
+ />
+
+ );
+};
diff --git a/public/pages/LogTypes/containers/LogType.tsx b/public/pages/LogTypes/containers/LogType.tsx
new file mode 100644
index 000000000..75163d2b1
--- /dev/null
+++ b/public/pages/LogTypes/containers/LogType.tsx
@@ -0,0 +1,218 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useContext } from 'react';
+import { useState } from 'react';
+import { useEffect } from 'react';
+import { RouteComponentProps, useParams } from 'react-router-dom';
+import { LogTypeItem } from '../../../../types';
+import {
+ EuiButtonIcon,
+ EuiDescriptionList,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiLoadingSpinner,
+ EuiPanel,
+ EuiSpacer,
+ EuiTab,
+ EuiTabs,
+ EuiTitle,
+ EuiToolTip,
+} from '@elastic/eui';
+import { DataStore } from '../../../store/DataStore';
+import { CoreServicesContext } from '../../../components/core_services';
+import { BREADCRUMBS, ROUTES } from '../../../utils/constants';
+import { logTypeDetailsTabs } from '../utils/constants';
+import { LogTypeDetails } from '../components/LogTypeDetails';
+import { NotificationsStart } from 'opensearch-dashboards/public';
+import { LogTypeDetectionRules } from '../components/LogTypeDetectionRules';
+import { RuleTableItem } from '../../Rules/utils/helpers';
+import { useCallback } from 'react';
+import { DeleteLogTypeModal } from '../components/DeleteLogTypeModal';
+import { errorNotificationToast, successNotificationToast } from '../../../utils/helpers';
+
+export interface LogTypeProps extends RouteComponentProps {
+ notifications: NotificationsStart;
+}
+
+export const LogType: React.FC = ({ notifications, history }) => {
+ const context = useContext(CoreServicesContext);
+ const { logTypeId } = useParams<{ logTypeId: string }>();
+ const [selectedTabId, setSelectedTabId] = useState('details');
+ const [showDeleteModal, setShowDeleteModal] = useState(false);
+ const [infoText, setInfoText] = useState(
+ <>
+ Loading details
+
+ >
+ );
+ const [logTypeDetails, setLogTypeDetails] = useState(undefined);
+ const [initialLogTypeDetails, setInitialLogTypeDetails] = useState(
+ undefined
+ );
+
+ const [isEditMode, setIsEditMode] = useState(false);
+ const [rules, setRules] = useState([]);
+ const [loadingRules, setLoadingRules] = useState(true);
+
+ const updateRules = useCallback(async (details: LogTypeItem, intialDetails: LogTypeItem) => {
+ const rulesRes = await DataStore.rules.getAllRules({
+ 'rule.category': [logTypeId],
+ });
+ const ruleItems = rulesRes.map((rule) => ({
+ title: rule._source.title,
+ level: rule._source.level,
+ category: rule._source.category,
+ description: rule._source.description,
+ source: rule.prePackaged ? 'Sigma' : 'Custom',
+ ruleInfo: rule,
+ ruleId: rule._id,
+ }));
+ setRules(ruleItems);
+ setLoadingRules(false);
+ setLogTypeDetails({
+ ...details,
+ detectionRules: ruleItems.length,
+ });
+ setInitialLogTypeDetails({
+ ...intialDetails,
+ detectionRules: ruleItems.length,
+ });
+ }, []);
+
+ useEffect(() => {
+ context?.chrome.setBreadcrumbs([
+ BREADCRUMBS.SECURITY_ANALYTICS,
+ BREADCRUMBS.DETECTORS,
+ BREADCRUMBS.LOG_TYPES,
+ { text: logTypeId },
+ ]);
+
+ const getLogTypeDetails = async () => {
+ const details = await DataStore.logTypes.getLogType(logTypeId);
+
+ if (!details) {
+ setInfoText('Log type not found!');
+ return;
+ }
+
+ updateRules(details, details);
+ };
+
+ getLogTypeDetails();
+ }, []);
+
+ const refreshRules = useCallback(() => {
+ updateRules(logTypeDetails!, initialLogTypeDetails!);
+ }, [logTypeDetails]);
+
+ const renderTabContent = () => {
+ switch (selectedTabId) {
+ case 'detection_rules':
+ return (
+
+ );
+ case 'details':
+ default:
+ return (
+
+ );
+ }
+ };
+
+ const deleteLogType = async () => {
+ const deleteSucceeded = await DataStore.logTypes.deleteLogType(logTypeDetails!.id);
+ if (deleteSucceeded) {
+ successNotificationToast(notifications, 'deleted', 'log type');
+ history.push(ROUTES.LOG_TYPES);
+ } else {
+ errorNotificationToast(notifications, 'delete', 'log type');
+ }
+ };
+
+ return !logTypeDetails ? (
+
+ {infoText}
+
+ ) : (
+ <>
+ {showDeleteModal && (
+ setShowDeleteModal(false)}
+ onConfirm={deleteLogType}
+ />
+ )}
+
+
+
+ {logTypeDetails.name}
+
+
+
+
+ setShowDeleteModal(true)}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {logTypeDetailsTabs.map((tab, index) => {
+ return (
+ {
+ setSelectedTabId(tab.id);
+ }}
+ key={index}
+ isSelected={selectedTabId === tab.id}
+ >
+ {tab.name}
+
+ );
+ })}
+
+ {renderTabContent()}
+ >
+ );
+};
diff --git a/public/pages/LogTypes/containers/LogTypes.tsx b/public/pages/LogTypes/containers/LogTypes.tsx
index 59a2a5f47..e57e8799f 100644
--- a/public/pages/LogTypes/containers/LogTypes.tsx
+++ b/public/pages/LogTypes/containers/LogTypes.tsx
@@ -4,7 +4,7 @@
*/
import React, { useContext, useEffect, useState } from 'react';
-import { EuiInMemoryTable } from '@elastic/eui';
+import { EuiButton, EuiInMemoryTable } from '@elastic/eui';
import { ContentPanel } from '../../../components/ContentPanel';
import { CoreServicesContext } from '../../../components/core_services';
import { BREADCRUMBS, ROUTES } from '../../../utils/constants';
@@ -13,12 +13,33 @@ import { DataStore } from '../../../store/DataStore';
import { getLogTypesTableColumns } from '../utils/helpers';
import { RouteComponentProps } from 'react-router-dom';
import { useCallback } from 'react';
+import { NotificationsStart } from 'opensearch-dashboards/public';
+import { successNotificationToast } from '../../../utils/helpers';
+import { DeleteLogTypeModal } from '../components/DeleteLogTypeModal';
-export interface LogTypesProps extends RouteComponentProps {}
+export interface LogTypesProps extends RouteComponentProps {
+ notifications: NotificationsStart;
+}
-export const LogTypes: React.FC = ({ history }) => {
+export const LogTypes: React.FC = ({ history, notifications }) => {
const context = useContext(CoreServicesContext);
const [logTypes, setLogTypes] = useState([]);
+ const [logTypeToDelete, setLogTypeItemToDelete] = useState(undefined);
+ const [deletionDetails, setDeletionDetails] = useState<
+ { detectionRulesCount: number } | undefined
+ >(undefined);
+ const getLogTypes = async () => {
+ const logTypes = await DataStore.logTypes.getLogTypes();
+ setLogTypes(logTypes);
+ };
+
+ const deleteLogType = async (id: string) => {
+ const deleteSucceeded = await DataStore.logTypes.deleteLogType(id);
+ if (deleteSucceeded) {
+ successNotificationToast(notifications, 'deleted', 'log type');
+ getLogTypes();
+ }
+ };
useEffect(() => {
context?.chrome.setBreadcrumbs([
@@ -26,10 +47,6 @@ export const LogTypes: React.FC = ({ history }) => {
BREADCRUMBS.DETECTORS,
BREADCRUMBS.LOG_TYPES,
]);
- const getLogTypes = async () => {
- const logTypes = await DataStore.logTypes.getLogTypes();
- setLogTypes(logTypes);
- };
getLogTypes();
}, []);
@@ -38,24 +55,46 @@ export const LogTypes: React.FC = ({ history }) => {
history.push(`${ROUTES.LOG_TYPES}/${id}`);
}, []);
+ const onDeleteClick = async (item: LogType) => {
+ setLogTypeItemToDelete(item);
+ const rules = await DataStore.rules.getAllRules({
+ 'rule.category': [item.id],
+ });
+ setDeletionDetails({ detectionRulesCount: rules.length });
+ };
+
return (
-
-
- alert(`Deleted ${id}`)
- )}
- pagination={{
- initialPageSize: 25,
- }}
- sorting={true}
- />
-
+ <>
+ {logTypeToDelete && (
+ setLogTypeItemToDelete(undefined)}
+ onConfirm={() => deleteLogType(logTypeToDelete.id)}
+ />
+ )}
+ history.push(ROUTES.LOG_TYPES_CREATE)}>
+ Create log type
+ ,
+ ]}
+ >
+
+
+ >
);
};
diff --git a/public/pages/LogTypes/utils/constants.ts b/public/pages/LogTypes/utils/constants.ts
index f7a7837f3..865e35e64 100644
--- a/public/pages/LogTypes/utils/constants.ts
+++ b/public/pages/LogTypes/utils/constants.ts
@@ -3,6 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
+import { LogTypeBase } from '../../../../types';
+
export const logTypeDetailsTabs = [
{
id: 'details',
@@ -13,3 +15,10 @@ export const logTypeDetailsTabs = [
name: 'Detection rules',
},
];
+
+export const defaultLogType: LogTypeBase = {
+ name: '',
+ description: '',
+ source: 'Custom',
+ tags: null,
+};
diff --git a/public/pages/LogTypes/utils/helpers.tsx b/public/pages/LogTypes/utils/helpers.tsx
index 2ad78d793..a651d2a12 100644
--- a/public/pages/LogTypes/utils/helpers.tsx
+++ b/public/pages/LogTypes/utils/helpers.tsx
@@ -10,7 +10,7 @@ import { capitalize } from 'lodash';
export const getLogTypesTableColumns = (
showDetails: (id: string) => void,
- deleteLogType: (logTypeId: string) => void
+ deleteLogType: (logType: LogType) => void
) => [
{
field: 'name',
@@ -41,7 +41,7 @@ export const getLogTypesTableColumns = (
aria-label={'Delete log type'}
iconType={'trash'}
color="danger"
- onClick={() => deleteLogType(item.id)}
+ onClick={() => deleteLogType(item)}
/>
);
diff --git a/public/pages/Main/Main.tsx b/public/pages/Main/Main.tsx
index aab5ec1ca..df6adfc5e 100644
--- a/public/pages/Main/Main.tsx
+++ b/public/pages/Main/Main.tsx
@@ -48,7 +48,8 @@ import FindingDetailsFlyout, {
FindingDetailsFlyoutBaseProps,
} from '../Findings/components/FindingDetailsFlyout';
import { LogTypes } from '../LogTypes/containers/LogTypes';
-import { LogTypeDetails } from '../LogTypes/containers/LogTypeDetails';
+import { LogType } from '../LogTypes/containers/LogType';
+import { CreateLogType } from '../LogTypes/containers/CreateLogType';
enum Navigation {
SecurityAnalytics = 'Security Analytics',
@@ -76,6 +77,7 @@ const HIDDEN_NAV_ROUTES: string[] = [
ROUTES.EDIT_FIELD_MAPPINGS,
ROUTES.EDIT_DETECTOR_ALERT_TRIGGERS,
`${ROUTES.LOG_TYPES}/.+`,
+ ROUTES.LOG_TYPES_CREATE,
];
interface MainProps extends RouteComponentProps {
@@ -559,12 +561,20 @@ export default class Main extends Component {
/>
}
+ render={(props: RouteComponentProps) => (
+
+ )}
/>
) => {
- return ;
+ return ;
+ }}
+ />
+ ) => {
+ return ;
}}
/>
diff --git a/public/pages/Rules/containers/Rules/Rules.tsx b/public/pages/Rules/containers/Rules/Rules.tsx
index e5ee1ca67..60c2cb412 100644
--- a/public/pages/Rules/containers/Rules/Rules.tsx
+++ b/public/pages/Rules/containers/Rules/Rules.tsx
@@ -13,7 +13,6 @@ import { BREADCRUMBS, ROUTES } from '../../../../utils/constants';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { CoreServicesContext } from '../../../../components/core_services';
import { DataStore } from '../../../../store/DataStore';
-import { RuleItemInfoBase } from '../../../../../types';
export interface RulesProps extends RouteComponentProps {
notifications?: NotificationsStart;
@@ -22,7 +21,7 @@ export interface RulesProps extends RouteComponentProps {
export const Rules: React.FC = (props) => {
const context = useContext(CoreServicesContext);
- const [allRules, setAllRules] = useState([]);
+ const [allRules, setAllRules] = useState([]);
const [flyoutData, setFlyoutData] = useState(undefined);
const [loading, setLoading] = useState(false);
diff --git a/public/store/LogTypeStore.ts b/public/store/LogTypeStore.ts
index 1eebdc8ae..8f9d6cfa1 100644
--- a/public/store/LogTypeStore.ts
+++ b/public/store/LogTypeStore.ts
@@ -72,4 +72,13 @@ export class LogTypeStore {
return updateRes.ok;
}
+
+ public async deleteLogType(id: string) {
+ const deleteRes = await this.service.deleteLogType(id);
+ if (!deleteRes.ok) {
+ errorNotificationToast(this.notifications, 'delete', 'log type', deleteRes.error);
+ }
+
+ return deleteRes.ok;
+ }
}
diff --git a/public/store/RulesStore.ts b/public/store/RulesStore.ts
index ba735767d..edb392877 100644
--- a/public/store/RulesStore.ts
+++ b/public/store/RulesStore.ts
@@ -65,6 +65,7 @@ export class RulesStore implements IRulesStore {
* @returns {Promise}
*/
public async getAllRules(terms?: { [key: string]: string[] }): Promise {
+ this.invalidateCache();
let customRules = await this.getCustomRules(terms);
let prePackagedRules = await this.getPrePackagedRules(terms);
diff --git a/types/Rule.ts b/types/Rule.ts
index 82f617267..4b57f9d75 100644
--- a/types/Rule.ts
+++ b/types/Rule.ts
@@ -25,7 +25,7 @@ export type RuleSource = Rule & {
rule: string;
last_update_time: string;
queries: { value: string }[];
- query_field_names: string[];
+ query_field_names: { value: string }[];
};
export interface RuleInfo {