From 67ad7e5c689cb96d42fd7dc29c5e9e60e0986a0f Mon Sep 17 00:00:00 2001 From: yashashk Date: Fri, 8 Nov 2024 02:59:15 +0530 Subject: [PATCH 01/12] #OBS-I304 : Fixed import data review changes --- .../Dropzone/PlaceholderContent.tsx | 3 +- .../src/pages/IngestionPage/IngestionPage.tsx | 52 ------------- .../src/pages/dashboardV1/datasetsList.tsx | 75 +++++++++++++------ .../src/pages/datasetV1/ImportDataset.tsx | 14 +++- .../src/pages/datasetV1/ImportDialog.tsx | 34 ++++++++- 5 files changed, 94 insertions(+), 84 deletions(-) delete mode 100644 web-console-v2/src/pages/IngestionPage/IngestionPage.tsx diff --git a/web-console-v2/src/components/Dropzone/PlaceholderContent.tsx b/web-console-v2/src/components/Dropzone/PlaceholderContent.tsx index 9013689f..8a6e55a8 100644 --- a/web-console-v2/src/components/Dropzone/PlaceholderContent.tsx +++ b/web-console-v2/src/components/Dropzone/PlaceholderContent.tsx @@ -15,7 +15,6 @@ const PlaceholderContent = ({ imageUrl, mainText, subText, type }: PlaceholderCo {type !== DropzopType.standard && ( { - return ( - - - - - ); -}; - -export default UploadPage; diff --git a/web-console-v2/src/pages/dashboardV1/datasetsList.tsx b/web-console-v2/src/pages/dashboardV1/datasetsList.tsx index dbdaa6e2..676b7fba 100644 --- a/web-console-v2/src/pages/dashboardV1/datasetsList.tsx +++ b/web-console-v2/src/pages/dashboardV1/datasetsList.tsx @@ -86,12 +86,18 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { getDatasets(); }, []) - const AsyncColumnData = (query: Record) => { - const [asyncData, setAsyncData] = useState(null); + const AsyncColumnData = (query: Record, datasetId: any, cellKey: string) => { + const [asyncData, setAsyncData] = useState(() => { + // Initialize state by reading from localStorage based on datasetId and cellKey + const storedData = localStorage.getItem(datasetId); + if (storedData) { + const parsedData = JSON.parse(storedData); + return parsedData[cellKey] || null; + } + return null; + }); const [isLoading, setIsLoading] = useState(false); - const memoizedAsyncData = useMemo(() => asyncData, [asyncData]); - useEffect(() => { const fetchData = async (value: any) => { setIsLoading(true); @@ -99,28 +105,51 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { let data = await fetchChartData(value); const responseData = Array.isArray(data) ? _.first(data) : data; setAsyncData(responseData as any); - } - catch (error) { } - finally { - setIsLoading(false) + + // Always store the successful response in localStorage under datasetId and cellKey + const storedData = localStorage.getItem(datasetId); + const parsedData = storedData ? JSON.parse(storedData) : {}; + parsedData[cellKey] = responseData; + localStorage.setItem(datasetId, JSON.stringify(parsedData)); + } catch (error) { + // Check if localStorage already has a value for cellKey, and only store the error if no value exists + const storedData = localStorage.getItem(datasetId); + const parsedData = storedData ? JSON.parse(storedData) : {}; + if (!parsedData[cellKey]) { + // If localStorage doesn't contain a value for this cellKey, store 0 as value + parsedData[cellKey] = 0; + localStorage.setItem(datasetId, JSON.stringify(parsedData)); + } + } finally { + setIsLoading(false); } }; - if (!memoizedAsyncData) { - fetchData(query); - } - + fetchData(query); }, []); if (isLoading) { return ; } - if ([null, undefined].includes(asyncData)) return "N/A"; - const hoverValue = _.get(asyncData, "hoverValue") || "" - const value: any = _.get(asyncData, "value") || asyncData; + // Always read from localStorage on render, specific to the current cellKey + const storedData = localStorage.getItem(datasetId); + const parsedData = storedData ? JSON.parse(storedData) : null; + const cellData = parsedData ? parsedData[cellKey] : null; - return
{value}
; - } + // Check if the stored data is an error + if (cellData?.error) return cellData.error; + + if ([null, undefined].includes(cellData)) return "N/A"; + + const hoverValue = _.get(cellData, "hoverValue") || ""; + const value: any = _.get(cellData, "value") || cellData; + + return ( +
+ {value} +
+ ); + }; const updateDatasetProps = ({ dataset_id, status, id, name, tags }: any) => { setData((prevState: any) => { @@ -309,7 +338,7 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { const body = druidQueries.total_events_processed({ datasetId, intervals: `${startDate}/${endDate}`, master: isMasterDataset, }) const query = _.get(chartMeta, 'total_events_processed.query'); if (row?.onlyTag) return null; - return AsyncColumnData({ ...query, body }); + return AsyncColumnData({ ...query, body }, datasetId, "total_events"); } }, { @@ -324,7 +353,7 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { const body = druidQueries.total_events_processed({ datasetId, intervals: `${startDate}/${endDate}`, master: isMasterDataset, }) const query = _.get(chartMeta, 'total_events_processed.query'); if (row?.onlyTag) return null; - return AsyncColumnData({ ...query, body }); + return AsyncColumnData({ ...query, body }, datasetId, "total_events_yesterday"); } }, { @@ -339,7 +368,7 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { const body = druidQueries.druid_avg_processing_time({ datasetId, intervals: `${startDate}/${endDate}`, master: isMasterDataset, }) const query = _.get(chartMeta, 'druid_avg_processing_time.query'); if (row?.onlyTag) return null; - return AsyncColumnData({ ...query, body }); + return AsyncColumnData({ ...query, body }, datasetId, "average_processing_time"); } }, { @@ -354,7 +383,7 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { const body = druidQueries.druid_avg_processing_time({ datasetId, intervals: `${startDate}/${endDate}`, master: isMasterDataset, }) const query = _.get(chartMeta, 'druid_avg_processing_time.query'); if (row?.onlyTag) return null; - return AsyncColumnData({ ...query, body }); + return AsyncColumnData({ ...query, body }, datasetId, "average_processing_time_yesterday"); } }, { @@ -369,7 +398,7 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { const body = druidQueries.last_synced_time({ datasetId, intervals: `${startDate}/${endDate}`, master: isMasterDataset, }) const query = _.get(chartMeta, 'last_synced_relative_time.query'); if (row?.onlyTag) return null; - return AsyncColumnData({ ...query, body }); + return AsyncColumnData({ ...query, body }, datasetId, "last_synced_time"); } }, { @@ -384,7 +413,7 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { _.get(chartMeta, 'failed_events_summary_master_datasets.query') : _.get(chartMeta, 'failed_events_summary.query'); if (row?.onlyTag) return null; - return AsyncColumnData({ ...query, time: endDate, dataset: datasetId, master: isMasterDataset, }); + return AsyncColumnData({ ...query, time: endDate, dataset: datasetId, master: isMasterDataset, }, datasetId, "events_failed"); } }, { diff --git a/web-console-v2/src/pages/datasetV1/ImportDataset.tsx b/web-console-v2/src/pages/datasetV1/ImportDataset.tsx index fe7d16e9..9e7d9475 100644 --- a/web-console-v2/src/pages/datasetV1/ImportDataset.tsx +++ b/web-console-v2/src/pages/datasetV1/ImportDataset.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { useDropzone } from 'react-dropzone'; import { Box, Button, Dialog, DialogTitle, DialogContent, Grid, TextField, Typography, DialogActions, IconButton, List, ListItem, ListItemText, ListItemSecondaryAction } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; @@ -57,7 +57,7 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { ); const onDrop = useCallback(async (acceptedFiles: any[]) => { - setAcceptedFiles(prevFiles => [...prevFiles, ...acceptedFiles]); + setAcceptedFiles(acceptedFiles); const contents = await Promise.all(acceptedFiles.map((file: File) => readJsonFileContents(file))); if (contents.length > 0) { setContents(contents as string[]) @@ -148,6 +148,12 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { setOpenImportDialog(false) } + useEffect(() => { + setDatasetId('') + setDatasetName('') + setAcceptedFiles([]) + }, [open]) + return ( <> @@ -200,10 +206,10 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { - + diff --git a/web-console-v2/src/pages/datasetV1/ImportDialog.tsx b/web-console-v2/src/pages/datasetV1/ImportDialog.tsx index 90100256..632fcf25 100644 --- a/web-console-v2/src/pages/datasetV1/ImportDialog.tsx +++ b/web-console-v2/src/pages/datasetV1/ImportDialog.tsx @@ -4,6 +4,8 @@ import MUIForm from "components/form"; import HtmlTooltip from "components/HtmlTooltip"; import _ from "lodash"; import { useEffect, useState } from "react"; +import { datasetRead } from "services/datasetV1"; +import { DatasetStatus } from "types/datasets"; const onSubmission = (value: any) => { }; @@ -13,6 +15,7 @@ const ImportDailog = (props: any) => { const [nameError, setNameError] = useState(''); const [validImport, setValid] = useState(true) const [name, setName] = useState("") + const [datasetExists, setDatasetExists] = useState(true); const options = [ { label: 'Import as new dataset', component: '', value: 'new' }, @@ -66,6 +69,25 @@ const ImportDailog = (props: any) => { } }; + const fetchDataset = async () => { + return datasetRead({ datasetId: `${datasetId}?mode=edit` }).then((response: any) => { + return response?.data?.result + }).catch((err: any) => { console.log(err) }) + } + + useEffect(() => { + const checkDatasetExists = async () => { + const isDatasetExists = await fetchDataset(); + if (isDatasetExists) { + setDatasetExists(true); + } + else { + setDatasetExists(false); + } + }; + checkDatasetExists(); + }, [datasetId]) + useEffect(() => { const { importType } = value const isValid = !_.isEmpty(nameError) || (name.length < 4 || name.length > 100) @@ -104,8 +126,14 @@ const ImportDailog = (props: any) => { value={datasetName} variant="outlined" fullWidth - error={Boolean(nameError)} - helperText={nameError || (datasetName.length > 0 && (datasetName.length < 4 || datasetName.length > 100) ? 'Dataset name should be between 4 and 100 characters' : '')} + error={Boolean(nameError) || datasetExists} + helperText={ + nameError || + (datasetName.length > 0 && (datasetName.length < 4 || datasetName.length > 100) + ? 'Dataset name should be between 4 and 100 characters' + : '') || + (datasetExists ? 'Dataset already exists' : '') + } /> @@ -128,7 +156,7 @@ const ImportDailog = (props: any) => { - From 14c7c3f73d4a845978ffff28b145dd25496787cd Mon Sep 17 00:00:00 2001 From: Rakshitha-D Date: Fri, 8 Nov 2024 14:45:12 +0530 Subject: [PATCH 02/12] #OBS-I304: fixed rerendering of chart in add alert --- .../src/pages/alertManager/components/QueryBuilder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-console-v2/src/pages/alertManager/components/QueryBuilder.tsx b/web-console-v2/src/pages/alertManager/components/QueryBuilder.tsx index 31fa2cb7..1aae5401 100644 --- a/web-console-v2/src/pages/alertManager/components/QueryBuilder.tsx +++ b/web-console-v2/src/pages/alertManager/components/QueryBuilder.tsx @@ -301,4 +301,4 @@ const QueryBuilder = (props: any) => { } -export default QueryBuilder; \ No newline at end of file +export default React.memo(QueryBuilder); \ No newline at end of file From 2ab25e46e39f3ab87e01edec4386dd7eedcd422f Mon Sep 17 00:00:00 2001 From: Rakshitha-D Date: Fri, 8 Nov 2024 14:48:50 +0530 Subject: [PATCH 03/12] #OBS-I304: fixed add label button color --- web-console-v2/src/pages/alertManager/components/RuleLabels.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-console-v2/src/pages/alertManager/components/RuleLabels.tsx b/web-console-v2/src/pages/alertManager/components/RuleLabels.tsx index 48b982bc..d8838f0d 100644 --- a/web-console-v2/src/pages/alertManager/components/RuleLabels.tsx +++ b/web-console-v2/src/pages/alertManager/components/RuleLabels.tsx @@ -165,7 +165,7 @@ const LabelComponent = (props: any) => { + } @@ -103,12 +104,12 @@ const NotificationComponent = (props: any) => { navigate('/home/alertChannels')} + onClick={() => navigate('/home/alertChannels/new')} variant="contained" size="large" sx={{ width: 'auto' }} > - + Create Notification Channel From 62ab956783359419ea72648b6f71818f3a4bd1c2 Mon Sep 17 00:00:00 2001 From: yashashk Date: Fri, 8 Nov 2024 17:16:54 +0530 Subject: [PATCH 06/12] #OBS-I304 : Import dataset review fix and cache fix --- .../src/components/Sidebar/Sidebar.tsx | 7 +- .../src/pages/dashboardV1/datasetsList.tsx | 28 ++++---- .../src/pages/datasetV1/ImportDataset.tsx | 29 ++++++++- .../src/pages/datasetV1/ImportDialog.tsx | 64 +++++++++---------- 4 files changed, 74 insertions(+), 54 deletions(-) diff --git a/web-console-v2/src/components/Sidebar/Sidebar.tsx b/web-console-v2/src/components/Sidebar/Sidebar.tsx index 579b1b28..da081a47 100644 --- a/web-console-v2/src/components/Sidebar/Sidebar.tsx +++ b/web-console-v2/src/components/Sidebar/Sidebar.tsx @@ -104,9 +104,10 @@ const Sidebar: React.FC = ({ onExpandToggle, expand }) => { }; const handleLogout = () => { - http.get(apiEndpoints.logout).then(() => { - navigate(`/login`); - }).catch(() => { + localStorage.clear(); + http.get(apiEndpoints.logout).then(() => { + navigate(`/login`); + }).catch(() => { showAlert('Failed to logout', 'error'); }) }; diff --git a/web-console-v2/src/pages/dashboardV1/datasetsList.tsx b/web-console-v2/src/pages/dashboardV1/datasetsList.tsx index 676b7fba..dbe07072 100644 --- a/web-console-v2/src/pages/dashboardV1/datasetsList.tsx +++ b/web-console-v2/src/pages/dashboardV1/datasetsList.tsx @@ -87,15 +87,6 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { }, []) const AsyncColumnData = (query: Record, datasetId: any, cellKey: string) => { - const [asyncData, setAsyncData] = useState(() => { - // Initialize state by reading from localStorage based on datasetId and cellKey - const storedData = localStorage.getItem(datasetId); - if (storedData) { - const parsedData = JSON.parse(storedData); - return parsedData[cellKey] || null; - } - return null; - }); const [isLoading, setIsLoading] = useState(false); useEffect(() => { @@ -103,18 +94,17 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { setIsLoading(true); try { let data = await fetchChartData(value); - const responseData = Array.isArray(data) ? _.first(data) : data; - setAsyncData(responseData as any); + const responseData = _.isArray(data) ? _.first(data) : data; // Always store the successful response in localStorage under datasetId and cellKey - const storedData = localStorage.getItem(datasetId); - const parsedData = storedData ? JSON.parse(storedData) : {}; + const storedData: any = localStorage.getItem(datasetId); + const parsedData = !_.isEmpty(storedData) ? JSON.parse(storedData) : {}; parsedData[cellKey] = responseData; localStorage.setItem(datasetId, JSON.stringify(parsedData)); } catch (error) { // Check if localStorage already has a value for cellKey, and only store the error if no value exists - const storedData = localStorage.getItem(datasetId); - const parsedData = storedData ? JSON.parse(storedData) : {}; + const storedData: any = localStorage.getItem(datasetId); + const parsedData = !_.isEmpty(storedData) ? JSON.parse(storedData) : {}; if (!parsedData[cellKey]) { // If localStorage doesn't contain a value for this cellKey, store 0 as value parsedData[cellKey] = 0; @@ -133,7 +123,13 @@ const DatasetsList = ({ setDatasetType, sourceConfigs }: any) => { // Always read from localStorage on render, specific to the current cellKey const storedData = localStorage.getItem(datasetId); - const parsedData = storedData ? JSON.parse(storedData) : null; + let parsedData = null; + try { + parsedData = storedData ? JSON.parse(storedData) : null; + } catch (error) { + console.error("Failed to parse stored data:", error); + parsedData = null; + } const cellData = parsedData ? parsedData[cellKey] : null; // Check if the stored data is an error diff --git a/web-console-v2/src/pages/datasetV1/ImportDataset.tsx b/web-console-v2/src/pages/datasetV1/ImportDataset.tsx index 9e7d9475..b50d5321 100644 --- a/web-console-v2/src/pages/datasetV1/ImportDataset.tsx +++ b/web-console-v2/src/pages/datasetV1/ImportDataset.tsx @@ -30,6 +30,7 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { const navigate = useNavigate(); const { showAlert } = useAlert(); const [acceptedFiles, setAcceptedFiles] = useState([]); + const [nameError, setNameError] = useState(''); const flattenContents = (content: Record | any) => { return content.flat().filter((field: any) => field && Object.keys(field).length > 0); @@ -154,6 +155,22 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { setAcceptedFiles([]) }, [open]) + const [name ,setName] = useState(''); + const nameRegex = /^[^!@#$%^&*()+{}[\]:;<>,?~\\|]*$/; + + const handleNameChange = (e: React.ChangeEvent) => { + const newValue = e.target.value; + setDatasetName(newValue); + setName(newValue) + if (nameRegex.test(newValue)) { + const generatedId = newValue.toLowerCase().replace(/\s+/g, '-'); + setDatasetId(generatedId) + setNameError(''); + } else { + setNameError('The field should exclude any special characters, permitting only alphabets, numbers, ".", "-", and "_".'); + } + }; + return ( <> @@ -186,7 +203,14 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { variant="outlined" fullWidth value={datasetName} - onChange={(e) => setDatasetName(e.target.value)} + onChange={handleNameChange} + error={Boolean(nameError)} + helperText={ + nameError || + (datasetName.length > 0 && (datasetName.length < 4 || datasetName.length > 100) + ? 'Dataset name should be between 4 and 100 characters' + : '') + } /> @@ -198,8 +222,9 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { required variant="outlined" fullWidth - value={datasetId} + value={datasetName} onChange={(e) => setDatasetId(e.target.value)} + disabled /> diff --git a/web-console-v2/src/pages/datasetV1/ImportDialog.tsx b/web-console-v2/src/pages/datasetV1/ImportDialog.tsx index 632fcf25..ac172dca 100644 --- a/web-console-v2/src/pages/datasetV1/ImportDialog.tsx +++ b/web-console-v2/src/pages/datasetV1/ImportDialog.tsx @@ -16,6 +16,8 @@ const ImportDailog = (props: any) => { const [validImport, setValid] = useState(true) const [name, setName] = useState("") const [datasetExists, setDatasetExists] = useState(true); + const [localDatasetId, setLocalDatasetId] = useState(datasetId); + const [localDatasetName, setLocalDatasetName] = useState(datasetName); const options = [ { label: 'Import as new dataset', component: '', value: 'new' }, @@ -35,13 +37,13 @@ const ImportDailog = (props: any) => { const selectImportOption = async () => { const { importType } = value - await onSubmit({ datasetName, datasetId, importType }) + await onSubmit({ datasetName: localDatasetName, datasetId: localDatasetId, importType }) setOpenDailog(false) } const onClose = () => { - setDatasetName("") - setDatasetId("") + setLocalDatasetName("") + setLocalDatasetId("") setCheckValidation(true) setOpenDailog(false); } @@ -49,8 +51,6 @@ const ImportDailog = (props: any) => { useEffect(() => { const { importType } = value if (importType === "new") { - setDatasetName("") - setDatasetId("") setCheckValidation(true) } }, [value]) @@ -58,11 +58,11 @@ const ImportDailog = (props: any) => { const nameRegex = /^[^!@#$%^&*()+{}[\]:;<>,?~\\|]*$/; const handleNameChange = (e: React.ChangeEvent) => { const newValue = e.target.value; - setDatasetName(newValue); + setLocalDatasetName(newValue); setName(newValue) if (nameRegex.test(newValue)) { const generatedId = newValue.toLowerCase().replace(/\s+/g, '-'); - setDatasetId(generatedId) + setLocalDatasetId(generatedId) setNameError(''); } else { setNameError('The field should exclude any special characters, permitting only alphabets, numbers, ".", "-", and "_".'); @@ -70,29 +70,27 @@ const ImportDailog = (props: any) => { }; const fetchDataset = async () => { - return datasetRead({ datasetId: `${datasetId}?mode=edit` }).then((response: any) => { + return datasetRead({ datasetId: `${localDatasetId}?mode=edit` }).then((response: any) => { return response?.data?.result }).catch((err: any) => { console.log(err) }) } - useEffect(() => { - const checkDatasetExists = async () => { - const isDatasetExists = await fetchDataset(); - if (isDatasetExists) { - setDatasetExists(true); - } - else { - setDatasetExists(false); - } - }; - checkDatasetExists(); - }, [datasetId]) + const checkDatasetExists = async () => { + const isDatasetExists = await fetchDataset(); + if (isDatasetExists) { + setDatasetExists(true); + } + else { + setDatasetExists(false); + } + }; useEffect(() => { + checkDatasetExists() const { importType } = value - const isValid = !_.isEmpty(nameError) || (name.length < 4 || name.length > 100) + const isValid = datasetExists || !_.isEmpty(nameError) || (localDatasetName.length < 4 || localDatasetName.length > 100) importType === "overwrite" ? setValid(false) : setValid(isValid) - }, [datasetName, value, nameError]) + }, [localDatasetName, value?.importType, nameError,datasetExists]) return @@ -123,17 +121,17 @@ const ImportDailog = (props: any) => { label={'Dataset Name'} onChange={handleNameChange} required - value={datasetName} + value={localDatasetName} variant="outlined" fullWidth error={Boolean(nameError) || datasetExists} - helperText={ - nameError || - (datasetName.length > 0 && (datasetName.length < 4 || datasetName.length > 100) - ? 'Dataset name should be between 4 and 100 characters' - : '') || - (datasetExists ? 'Dataset already exists' : '') - } + helperText={ + nameError || + (localDatasetName.length > 0 && (localDatasetName.length < 4 || localDatasetName.length > 100) + ? 'Dataset name should be between 4 and 100 characters' + : '') || + (datasetExists ? 'Dataset already exists' : '') + } /> @@ -142,9 +140,9 @@ const ImportDailog = (props: any) => { setDatasetId(e.target.value)} + onChange={(e) => setLocalDatasetId(e.target.value)} required - value={datasetId} + value={localDatasetId} variant="outlined" fullWidth disabled @@ -156,7 +154,7 @@ const ImportDailog = (props: any) => { - From a59bbe5722514c842dce3591e6502c8e1a442fc6 Mon Sep 17 00:00:00 2001 From: Rakshitha-D Date: Fri, 8 Nov 2024 17:41:34 +0530 Subject: [PATCH 07/12] #OBS-I304: updated the notification channels field --- .../alertManager/components/NotificationComponent.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/web-console-v2/src/pages/alertManager/components/NotificationComponent.tsx b/web-console-v2/src/pages/alertManager/components/NotificationComponent.tsx index 54268060..8ca28a25 100644 --- a/web-console-v2/src/pages/alertManager/components/NotificationComponent.tsx +++ b/web-console-v2/src/pages/alertManager/components/NotificationComponent.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Button, Grid, Stack, Typography } from "@mui/material"; +import { Box, Button, Grid, Popper, Stack, Typography } from "@mui/material"; import MUIForm from "components/form"; import { StandardWidthButton } from "components/Styled/Buttons"; import { useEffect, useRef, useState } from "react"; @@ -18,7 +18,6 @@ const NotificationComponent = (props: any) => { const [notificationFieldOptions, setNotificationFieldOptions] = useState[]>([]); const formikRef = useRef(null); const navigate = useNavigate(); - const isNoneSelected = value?.notificationChannel === null; const getChannels = () => { return fetchChannels({ data: { "request": { "filters": { "status": "live" } } } }) @@ -46,9 +45,9 @@ const NotificationComponent = (props: any) => { { name: "notificationChannel", label: "Notification Channels", - type: "select", + type: "autocomplete", required: true, - selectOptions: _.concat([{ label: 'none', value: null }], notificationFieldOptions), + selectOptions: notificationFieldOptions, tooltip: "Select the channel for notification delivery" }, ]; @@ -90,7 +89,7 @@ const NotificationComponent = (props: any) => { /> - + } From 0521485c279cb5d3f3ff529441ffc168be2752e2 Mon Sep 17 00:00:00 2001 From: Rakshitha-D Date: Fri, 8 Nov 2024 17:42:05 +0530 Subject: [PATCH 08/12] #OBS-I304: removed width for autocomplete in mui form --- web-console-v2/src/components/form.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/web-console-v2/src/components/form.tsx b/web-console-v2/src/components/form.tsx index 70962f19..441253ab 100644 --- a/web-console-v2/src/components/form.tsx +++ b/web-console-v2/src/components/form.tsx @@ -218,7 +218,6 @@ const MUIForm = forwardRef((props: any, ref: any) => { Date: Fri, 8 Nov 2024 17:45:03 +0530 Subject: [PATCH 09/12] #OBS-I304: updated the notification channels field --- .../pages/alertManager/components/NotificationComponent.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web-console-v2/src/pages/alertManager/components/NotificationComponent.tsx b/web-console-v2/src/pages/alertManager/components/NotificationComponent.tsx index 8ca28a25..97a0001e 100644 --- a/web-console-v2/src/pages/alertManager/components/NotificationComponent.tsx +++ b/web-console-v2/src/pages/alertManager/components/NotificationComponent.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Box, Button, Grid, Popper, Stack, Typography } from "@mui/material"; +import { Box, Button, Grid, Stack, Typography } from "@mui/material"; import MUIForm from "components/form"; import { StandardWidthButton } from "components/Styled/Buttons"; import { useEffect, useRef, useState } from "react"; @@ -89,7 +89,7 @@ const NotificationComponent = (props: any) => { /> - + } From 61c1c738ae49839690593de87862cafc9fc50834 Mon Sep 17 00:00:00 2001 From: Harish Kumar Gangula Date: Fri, 8 Nov 2024 18:25:00 +0530 Subject: [PATCH 10/12] #OBS-I304: backend header fix --- src/main/middlewares/passportAuthenticate.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/middlewares/passportAuthenticate.ts b/src/main/middlewares/passportAuthenticate.ts index 40ebc105..80e1841f 100644 --- a/src/main/middlewares/passportAuthenticate.ts +++ b/src/main/middlewares/passportAuthenticate.ts @@ -29,20 +29,20 @@ export default { if (!user) { return res.redirect(`${baseURL}/login`); } - req.login(user, (loginErr) => { + return req.login(user, (loginErr) => { if (loginErr) { return next(loginErr); } - generateToken(user) + return generateToken(user) .then((token: any) => { req.session.token = token; + req.session.roles = _.get(user, ['roles']); + req.session.userDetails = _.pick(user, ['id', 'user_name', 'email_address', 'roles']); + return res.redirect(baseURL || '/'); }) .catch((tokenError) => { return next(tokenError); }); - req.session.roles = _.get(user, ['roles']); - req.session.userDetails = _.pick(user, ['id', 'user_name', 'email_address', 'roles']); - res.redirect(baseURL || '/'); }); })(req, res, next); }, From 51371816b214ba1c1ec8b0f020ef374694c5a59b Mon Sep 17 00:00:00 2001 From: yashashk Date: Fri, 8 Nov 2024 18:29:28 +0530 Subject: [PATCH 11/12] #OBS-I304 : added partial import error message and clear session after successful logout --- .../src/components/Sidebar/Sidebar.tsx | 2 +- .../src/pages/datasetV1/ImportDataset.tsx | 49 ++++--------------- 2 files changed, 10 insertions(+), 41 deletions(-) diff --git a/web-console-v2/src/components/Sidebar/Sidebar.tsx b/web-console-v2/src/components/Sidebar/Sidebar.tsx index da081a47..264ca441 100644 --- a/web-console-v2/src/components/Sidebar/Sidebar.tsx +++ b/web-console-v2/src/components/Sidebar/Sidebar.tsx @@ -104,8 +104,8 @@ const Sidebar: React.FC = ({ onExpandToggle, expand }) => { }; const handleLogout = () => { - localStorage.clear(); http.get(apiEndpoints.logout).then(() => { + localStorage.clear(); navigate(`/login`); }).catch(() => { showAlert('Failed to logout', 'error'); diff --git a/web-console-v2/src/pages/datasetV1/ImportDataset.tsx b/web-console-v2/src/pages/datasetV1/ImportDataset.tsx index b50d5321..979924cd 100644 --- a/web-console-v2/src/pages/datasetV1/ImportDataset.tsx +++ b/web-console-v2/src/pages/datasetV1/ImportDataset.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useState } from 'react'; import { useDropzone } from 'react-dropzone'; import { Box, Button, Dialog, DialogTitle, DialogContent, Grid, TextField, Typography, DialogActions, IconButton, List, ListItem, ListItemText, ListItemSecondaryAction } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; @@ -30,7 +30,6 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { const navigate = useNavigate(); const { showAlert } = useAlert(); const [acceptedFiles, setAcceptedFiles] = useState([]); - const [nameError, setNameError] = useState(''); const flattenContents = (content: Record | any) => { return content.flat().filter((field: any) => field && Object.keys(field).length > 0); @@ -58,7 +57,7 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { ); const onDrop = useCallback(async (acceptedFiles: any[]) => { - setAcceptedFiles(acceptedFiles); + setAcceptedFiles(prevFiles => [...prevFiles, ...acceptedFiles]); const contents = await Promise.all(acceptedFiles.map((file: File) => readJsonFileContents(file))); if (contents.length > 0) { setContents(contents as string[]) @@ -118,12 +117,12 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { setIsLiveExists(true) return } - await importDataset(contents[0], config, overwrite); + const response = await importDataset(contents[0], config, overwrite); setDatasetName("") setDatasetId("") - showAlert(`Dataset imported successfully`, "success"); + showAlert(_.get(response,"data.result.message","Dataset imported successfully"), "success"); navigate(`/home/datasets?status=${DatasetStatus.Draft}`) - window.location.reload() + // window.location.reload() } catch (err) { setOpen(false) setAcceptedFiles([]) @@ -149,28 +148,6 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { setOpenImportDialog(false) } - useEffect(() => { - setDatasetId('') - setDatasetName('') - setAcceptedFiles([]) - }, [open]) - - const [name ,setName] = useState(''); - const nameRegex = /^[^!@#$%^&*()+{}[\]:;<>,?~\\|]*$/; - - const handleNameChange = (e: React.ChangeEvent) => { - const newValue = e.target.value; - setDatasetName(newValue); - setName(newValue) - if (nameRegex.test(newValue)) { - const generatedId = newValue.toLowerCase().replace(/\s+/g, '-'); - setDatasetId(generatedId) - setNameError(''); - } else { - setNameError('The field should exclude any special characters, permitting only alphabets, numbers, ".", "-", and "_".'); - } - }; - return ( <> @@ -203,14 +180,7 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { variant="outlined" fullWidth value={datasetName} - onChange={handleNameChange} - error={Boolean(nameError)} - helperText={ - nameError || - (datasetName.length > 0 && (datasetName.length < 4 || datasetName.length > 100) - ? 'Dataset name should be between 4 and 100 characters' - : '') - } + onChange={(e) => setDatasetName(e.target.value)} /> @@ -222,19 +192,18 @@ const ImportDataset = ({ open, onClose, setOpen }: any) => { required variant="outlined" fullWidth - value={datasetName} + value={datasetId} onChange={(e) => setDatasetId(e.target.value)} - disabled /> - + From b260464b8871af191003f819abd2b697f37b915e Mon Sep 17 00:00:00 2001 From: JeraldJF Date: Fri, 8 Nov 2024 18:49:59 +0530 Subject: [PATCH 12/12] #OBS-I275: fix: alerts metric fix --- .../alertManager/components/QueryBuilder.tsx | 16 +++++++++------- .../pages/alertManager/components/RunQuery.tsx | 5 +++-- .../src/pages/alertManager/services/utils.tsx | 16 ++++++++++------ .../src/pages/alertManager/views/AddRule.tsx | 2 +- .../src/pages/alertManager/views/EditRule.tsx | 4 ++-- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/web-console-v2/src/pages/alertManager/components/QueryBuilder.tsx b/web-console-v2/src/pages/alertManager/components/QueryBuilder.tsx index 31fa2cb7..92746b52 100644 --- a/web-console-v2/src/pages/alertManager/components/QueryBuilder.tsx +++ b/web-console-v2/src/pages/alertManager/components/QueryBuilder.tsx @@ -18,10 +18,12 @@ const QueryBuilder = (props: any) => { if (!_.isEmpty(existingState)) { const operatorType = _.get(existingState, "operator") const thresholdValue = _.get(existingState, "threshold") + const metricId = _.get(existingState, "id") || "" + if (_.includes(["within_range", "outside_range"], operatorType)) { - return { ..._.omit(existingState, ["threshold"]), threshold_from: _.get(thresholdValue, 0), threshold_to: _.get(thresholdValue, 1) } + return { ..._.omit(existingState, ["threshold"]), threshold_from: _.get(thresholdValue, 0), threshold_to: _.get(thresholdValue, 1), metric: metricId } } - return { ..._.omit(existingState, ["threshold_from", "threshold_to"]), threshold: _.get(thresholdValue, 0) } + return { ..._.omit(existingState, ["threshold_from", "threshold_to"]), threshold: _.get(thresholdValue, 0), metric: metricId } } return {} }); @@ -68,18 +70,18 @@ const QueryBuilder = (props: any) => { if (selectedSubComponent) { const filteredMetrics = _.filter(supportedMetrics, (supportedMetric) => supportedMetric.subComponent == selectedSubComponent); return _.map(filteredMetrics, (supportedMetric) => { - const { alias, metric } = supportedMetric; + const { alias, id } = supportedMetric; return { label: alias, - value: metric + value: id }; }); } return _.map(supportedMetrics, (supportedMetric) => { - const { alias, metric } = supportedMetric; + const { alias, id } = supportedMetric; return { label: alias, - value: metric + value: id }; }); }; @@ -264,7 +266,7 @@ const QueryBuilder = (props: any) => { {runQuery && ( - + )} diff --git a/web-console-v2/src/pages/alertManager/components/RunQuery.tsx b/web-console-v2/src/pages/alertManager/components/RunQuery.tsx index f0009cf4..a89438dd 100644 --- a/web-console-v2/src/pages/alertManager/components/RunQuery.tsx +++ b/web-console-v2/src/pages/alertManager/components/RunQuery.tsx @@ -10,8 +10,9 @@ import { useEffect, useState } from "react"; import Loader from "components/Loader"; const RunQuery = (props: any) => { - const { handleClose, queryBuilderContext } = props; + const { handleClose, queryBuilderContext, component } = props; const { metric, threshold, threshold_from, threshold_to, operator } = queryBuilderContext + const metricValue = _.filter(component, field => _.get(field, "id") == metric) const [metadata, setMetadata] = useState | null>(null); const [loading, setLoading] = useState(false) @@ -139,7 +140,7 @@ const RunQuery = (props: any) => { headers: {}, body: {}, params: { - query: metric, + query: _.get(metricValue, [0, "metric"]) || metric, step: '5m', start: dayjs().unix(), end: dayjs().subtract(1, 'day').unix() diff --git a/web-console-v2/src/pages/alertManager/services/utils.tsx b/web-console-v2/src/pages/alertManager/services/utils.tsx index b04bc8b2..c2cb0bd9 100644 --- a/web-console-v2/src/pages/alertManager/services/utils.tsx +++ b/web-console-v2/src/pages/alertManager/services/utils.tsx @@ -8,6 +8,7 @@ import { LocalizationProvider, DateTimePicker } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { searchAlert } from 'services/alerts'; import { fetchChannels } from 'services/notificationChannels'; +import { getMetricsGroupedByComponents } from './queryBuilder'; export const validateForm = (config: Record) => { if (!config) return false; @@ -196,10 +197,10 @@ const DatePicker = (props: any) => { { + onChange={(newValue: any) => { setDate(newValue, alertId); }} - renderInput={(params:any) => } + renderInput={(params: any) => } /> ); }; @@ -240,7 +241,7 @@ export const asyncValidation = () => { export const getStatusComponent = (props: any) => { return () => { const { statusData, setSilenceStatus, fetchDataHandler, toggleFilter, removeFilter } = props; - return _.map(statusData, (value:any, status:any) => ( + return _.map(statusData, (value: any, status: any) => ( { return _.get(valueToColorMapping, value?.toLowerCase()) || 'success'; }; -export const transformRulePayload = (formData: Record) => { +export const transformRulePayload = async (formData: Record) => { const { name, description, @@ -340,7 +341,10 @@ export const transformRulePayload = (formData: Record) => { context, severity } = formData; - const { threshold, threshold_from, threshold_to, operator } = queryBuilderContext + const { threshold, threshold_from, threshold_to, operator, metric } = queryBuilderContext + const components = await getMetricsGroupedByComponents(); + const selectedComponent = _.get(components, category) + const metricValue = _.filter(selectedComponent, field => _.get(field, "id") == metric) const updatedThreshold = !_.includes(["within_range", "outside_range"], operator) ? [threshold] : [threshold_from, threshold_to] const rulePayload = { name, @@ -356,7 +360,7 @@ export const transformRulePayload = (formData: Record) => { type: category }, metadata: { - queryBuilderContext: { ...queryBuilderContext, threshold: updatedThreshold } + queryBuilderContext: { ...queryBuilderContext, threshold: updatedThreshold, metric: _.get(metricValue, [0, "metric"]), id: metric } }, context: { ...context diff --git a/web-console-v2/src/pages/alertManager/views/AddRule.tsx b/web-console-v2/src/pages/alertManager/views/AddRule.tsx index d1fde029..d611ca79 100644 --- a/web-console-v2/src/pages/alertManager/views/AddRule.tsx +++ b/web-console-v2/src/pages/alertManager/views/AddRule.tsx @@ -63,7 +63,7 @@ const AddAlertrules = () => { }, []); const addAlertRule: any = async () => { - const rulePayload = transformRulePayload({ ...formData, context: { alertType: 'CUSTOM' } }); + const rulePayload = await transformRulePayload({ ...formData, context: { alertType: 'CUSTOM' } }); return addAlert(rulePayload); }; diff --git a/web-console-v2/src/pages/alertManager/views/EditRule.tsx b/web-console-v2/src/pages/alertManager/views/EditRule.tsx index 68b4bcb7..92b1e4bf 100644 --- a/web-console-v2/src/pages/alertManager/views/EditRule.tsx +++ b/web-console-v2/src/pages/alertManager/views/EditRule.tsx @@ -79,8 +79,8 @@ const EditRule = () => { } ], [ruleMetadata]); - const editAlertRule = () => { - const rulePayload = transformRulePayload({ ...formData, context: { alertType: alertType } }); + const editAlertRule = async () => { + const rulePayload = await transformRulePayload({ ...formData, context: { alertType: alertType } }); return editAlert({ id: id, data: rulePayload }); };