This commit is contained in:
Alex Holliday committed 2026-01-14 21:47:37 +00:00
1 parent 2b0c523047
commit 940247b7bf
18 files changed
+109 -151

No files matched your search

@@ -85,7 +85,7 @@ const Search = ({
const enhancedOptions = React.useMemo(() => {
return multiple && isAdorned
? [
{ [filteredBy]: t("selectAll"), isSelectAll: true, _id: "select_all" },
{ [filteredBy]: t("selectAll"), isSelectAll: true, _id: "select_all", id: "select_all" },
...options,
]
: options;
@@ -93,7 +93,7 @@ const Search = ({
const isOptionSelected = (option) => {
if (!multiple && !isAdorned) return false;
if (Array.isArray(value)) {
return value.some((item) => item._id === option._id);
return value.some((item) => (item._id ?? item.id) === (option._id ?? option.id));
}
return false;
};
@@ -145,7 +145,7 @@ const Search = ({
disableClearable
options={enhancedOptions}
getOptionLabel={(option) => option[filteredBy]}
isOptionEqualToValue={(option, value) => option._id === value._id} // Compare by unique identifier
isOptionEqualToValue={(option, value) => (option._id ?? option.id) === (value?._id ?? value?.id)} // Compare by unique identifier
renderInput={(params) => (
<FieldWrapper
label={label}
@@ -206,7 +206,7 @@ const Search = ({
return filtered;
}}
getOptionKey={(option) => {
return option._id;
return option._id ?? option.id;
}}
renderOption={(props, option) => {
const { key, ...optionProps } = props;
@@ -62,6 +62,7 @@ const Select = ({
fieldWrapperSx = {},
}) => {
const theme = useTheme();
const getItemValue = (item) => item?._id ?? item?.id;
const itemStyles = {
fontSize: "var(--env-var-font-size-medium)",
color: theme.palette.primary.contrastTextTertiary,
@@ -123,7 +124,7 @@ const Select = ({
...sx,
}}
renderValue={(selected) => {
const selectedItem = items.find((item) => item._id === selected);
const selectedItem = items.find((item) => getItemValue(item) === selected);
const displayName = selectedItem ? selectedItem.name : placeholder;
return (
<Typography
@@ -152,17 +153,25 @@ const Select = ({
{placeholder}
</MenuItem>
)}
{items.map((item) => (
<MenuItem
value={item._id}
key={`${id}-${item._id}`}
sx={{
...itemStyles,
}}
>
{item.name}
</MenuItem>
))}
{items
.map((item) => {
const itemValue = getItemValue(item);
if (itemValue === undefined || itemValue === null) {
return null;
}
return (
<MenuItem
value={itemValue}
key={`${id}-${itemValue}`}
sx={{
...itemStyles,
}}
>
{item.name}
</MenuItem>
);
})
.filter(Boolean)}
</MuiSelect>
</FieldWrapper>
);
@@ -179,8 +188,8 @@ Select.propTypes = {
.isRequired,
items: PropTypes.arrayOf(
PropTypes.shape({
_id: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool])
.isRequired,
_id: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
name: PropTypes.string.isRequired,
})
+4 -34
View File
@@ -100,22 +100,9 @@ const useFetchMonitorsWithChecks = ({
return [monitors, count, isLoading, networkError];
};
const useFetchMonitorsByTeamId = ({
types,
limit,
page,
rowsPerPage,
filter,
field,
order,
checkOrder,
normalize,
status,
updateTrigger,
}) => {
const useFetchMonitorsByTeamId = ({ types, filter, updateTrigger }) => {
const [isLoading, setIsLoading] = useState(false);
const [monitors, setMonitors] = useState(undefined);
const [summary, setSummary] = useState(undefined);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
@@ -123,20 +110,11 @@ const useFetchMonitorsByTeamId = ({
try {
setIsLoading(true);
const res = await networkService.getMonitorsByTeamId({
limit,
types,
page,
rowsPerPage,
filter,
field,
order,
checkOrder,
status,
normalize,
});
if (res?.data?.data?.filteredMonitors) {
setMonitors(res.data.data.filteredMonitors);
setSummary(res.data.data.summary);
if (res?.data?.data) {
setMonitors(res.data.data);
}
} catch (error) {
setNetworkError(true);
@@ -150,18 +128,10 @@ const useFetchMonitorsByTeamId = ({
fetchMonitors();
}, [
types,
limit,
page,
rowsPerPage,
filter,
field,
order,
updateTrigger,
checkOrder,
normalize,
status,
]);
return [monitors, summary, isLoading, networkError];
return [monitors, isLoading, networkError];
};
const useFetchStatsByMonitorId = ({
+1 -1
View File
@@ -34,7 +34,7 @@ const Incidents2 = () => {
setUpdateTrigger((prev) => !prev);
};
const [monitors, , isLoadingMonitors, monitorsNetworkError] = useFetchMonitorsByTeamId(
const [monitors, isLoadingMonitors, monitorsNetworkError] = useFetchMonitorsByTeamId(
{}
);
@@ -24,7 +24,7 @@ const MonitorListItem = ({ monitor, onDelete }) => {
MonitorListItem.propTypes = {
monitor: PropTypes.shape({
_id: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
}).isRequired,
onDelete: PropTypes.func.isRequired,
@@ -33,7 +33,7 @@ MonitorListItem.propTypes = {
const MonitorList = ({ selectedMonitors, setSelectedMonitors }) => {
const onDelete = (monitorToDelete) => {
const newMonitors = selectedMonitors.filter(
(monitor) => monitor._id !== monitorToDelete._id
(monitor) => monitor.id !== monitorToDelete.id
);
setSelectedMonitors(newMonitors);
};
@@ -47,7 +47,7 @@ const MonitorList = ({ selectedMonitors, setSelectedMonitors }) => {
>
{selectedMonitors?.map((monitor) => (
<MonitorListItem
key={monitor._id}
key={monitor.id}
monitor={monitor}
onDelete={onDelete}
/>
@@ -59,7 +59,7 @@ const MonitorList = ({ selectedMonitors, setSelectedMonitors }) => {
MonitorList.propTypes = {
selectedMonitors: PropTypes.arrayOf(
PropTypes.shape({
_id: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
})
).isRequired,
@@ -22,6 +22,12 @@ const useMaintenanceActions = () => {
weekly: MS_PER_DAY * 7,
};
const handleSubmitForm = async (maintenanceWindowId, form) => {
const toStringId = (monitor) => {
if (!monitor) {
return "";
}
return monitor._id ?? monitor.id ?? "";
};
const start = dayjs(form.startDate)
.set("hour", form.startTime.hour())
.set("minute", form.startTime.minute());
@@ -33,7 +39,7 @@ const useMaintenanceActions = () => {
const repeat = REPEAT_LOOKUP[form.repeat];
const submit = {
monitors: form.monitors.map((monitor) => monitor._id),
monitors: form.monitors.map((monitor) => toStringId(monitor)).filter(Boolean),
name: form.name,
start: start.toISOString(),
end: end.toISOString(),
@@ -41,7 +41,7 @@ const useMaintenanceData = () => {
limit: null,
types: ["http", "ping", "pagespeed", "port"],
});
const fetchedMonitors = response.data.data.monitors;
const fetchedMonitors = response.data.data;
return fetchedMonitors;
};
@@ -55,7 +55,7 @@ const useMaintenanceData = () => {
const endTime = dayjs(end);
const durationInMs = endTime.diff(startTime, "milliseconds").toString();
const { duration, durationUnit } = getDurationAndUnit(durationInMs);
const monitor = monitorList.find((monitor) => monitor._id === monitorId);
const monitor = monitorList.find((monitor) => (monitor._id ?? monitor.id) === monitorId);
const maintenanceWindowInformation = {
name,
repeat: REVERSE_REPEAT_LOOKUP[repeat],
@@ -108,6 +108,7 @@ const CreateMaintenance = () => {
const handleSubmit = async () => {
if (hasValidationErrors(form, maintenanceWindowValidation, setErrors)) return;
const request = handleSubmitForm(maintenanceWindowId, form);
try {
setIsLoading(true);
@@ -43,7 +43,7 @@ const MonitorListItem = ({
const MonitorList = ({ selectedMonitors, setSelectedMonitors }) => {
const onDelete = (monitorToDelete) => {
const newMonitors = selectedMonitors.filter(
(monitor) => monitor._id !== monitorToDelete._id
(monitor) => monitor.id !== monitorToDelete.id
);
setSelectedMonitors(newMonitors);
};
@@ -80,8 +80,8 @@ const MonitorList = ({ selectedMonitors, setSelectedMonitors }) => {
>
{selectedMonitors?.map((monitor, index) => (
<Draggable
key={monitor._id}
draggableId={monitor._id}
key={monitor.id}
draggableId={monitor.id}
index={index}
>
{(provided, snapshot) => (
@@ -24,7 +24,7 @@ const Content = ({
// Handlers
const handleMonitorsChange = (selectedMonitors) => {
handleFormChange({
target: { name: "monitors", value: selectedMonitors.map((monitor) => monitor._id) },
target: { name: "monitors", value: selectedMonitors.map((monitor) => monitor.id) },
});
setSelectedMonitors(selectedMonitors);
};
@@ -16,7 +16,7 @@ const useMonitorsFetch = () => {
limit: null, // donot return any checks for the monitors
types: ["http", "ping", "port", "game"], // include game servers in status page monitor selection
});
setMonitors(response.data.data.monitors);
setMonitors(response.data.data);
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
+3 -2
View File
@@ -62,7 +62,6 @@ const CreateStatusPage = () => {
useStatusPageFetch(isCreate, url);
const [deleteStatusPage, isDeleting] = useStatusPageDelete(fetchStatusPage, url);
console.log(JSON.stringify(form, null, 2));
// Handlers
const handleFormChange = (e) => {
let { type, name, value, checked } = e.target;
@@ -144,6 +143,8 @@ const CreateStatusPage = () => {
...form,
logo: { type: form.logo?.type ?? null, size: form.logo?.size ?? null },
};
console.log(toSubmit);
const { error } = statusPageValidation.validate(toSubmit, {
abortEarly: false,
});
@@ -205,7 +206,7 @@ const CreateStatusPage = () => {
companyName: statusPage?.companyName,
isPublished: statusPage?.isPublished,
timezone: statusPage?.timezone,
monitors: statusPageMonitors.map((monitor) => monitor._id),
monitors: statusPageMonitors.map((monitor) => monitor.id),
color: statusPage?.color,
logo: newLogo,
showCharts: statusPage?.showCharts ?? true,
@@ -28,14 +28,14 @@ const MonitorsList = ({
const status = determineState(monitor);
return (
<Stack
key={monitor._id}
key={monitor.id}
width="100%"
gap={theme.spacing(10)}
margin="0 auto"
maxWidth="95%"
>
<Host
key={monitor._id}
key={monitor.id}
url={monitor.url}
title={monitor.name}
percentageColor={monitor.percentageColor}
+2 -7
View File
@@ -144,20 +144,15 @@ class NetworkService {
*/
async getMonitorsByTeamId(config) {
const { limit, types, page, rowsPerPage, filter, field, order } = config;
const { types, filter } = config ?? {};
const params = new URLSearchParams();
if (limit) params.append("limit", limit);
if (types) {
types.forEach((type) => {
params.append("type", type);
});
}
if (page) params.append("page", page);
if (rowsPerPage) params.append("rowsPerPage", rowsPerPage);
if (filter) params.append("filter", filter);
if (field) params.append("field", field);
if (order) params.append("order", order);
if (filter !== undefined && filter !== null && filter !== "") params.append("filter", filter);
return this.axiosInstance.get(`/monitors/team?${params.toString()}`, {
headers: {
+4 -3
View File
@@ -5,6 +5,7 @@ import {
getMonitorByIdQueryValidation,
getMonitorsByTeamIdParamValidation,
getMonitorsByTeamIdQueryValidation,
getMonitorsWithChecksQueryValidation,
createMonitorBodyValidation,
editMonitorBodyValidation,
pauseMonitorParamValidation,
@@ -317,10 +318,10 @@ class MonitorController {
await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
const { type, filter } = req.query;
const teamId = req?.user?.teamId;
const monitors = await this.monitorService.getMonitorsByTeamId({ teamId, limit, type, page, rowsPerPage, filter, field, order });
const monitors = await this.monitorService.getMonitorsByTeamId({ teamId, type, filter });
return res.status(200).json({
success: true,
@@ -358,7 +359,7 @@ class MonitorController {
getMonitorsWithChecksByTeamId = async (req: Request, res: Response, next: NextFunction) => {
try {
await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
await getMonitorsWithChecksQueryValidation.validateAsync(req.query);
const explain = req?.query?.explain;
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
+26 -40
View File
@@ -289,47 +289,33 @@ class MonitorModule {
}
};
getMonitorsByTeamId = async ({ limit, type, page, rowsPerPage, filter, field, order, teamId }) => {
limit = parseInt(limit);
page = parseInt(page);
rowsPerPage = parseInt(rowsPerPage);
if (field === undefined) {
field = "name";
order = "asc";
}
// Build match stage
const matchStage = { teamId: new this.ObjectId(teamId) };
if (type !== undefined) {
matchStage.type = Array.isArray(type) ? { $in: type } : type;
}
const summaryResult = await this.Monitor.aggregate(buildMonitorSummaryByTeamIdPipeline({ matchStage }));
const summary = summaryResult[0];
const monitors = await this.Monitor.aggregate(buildMonitorsByTeamIdPipeline({ matchStage, field, order }));
const filteredMonitors = await this.Monitor.aggregate(
buildFilteredMonitorsByTeamIdPipeline({
matchStage,
filter,
page,
rowsPerPage,
field,
order,
limit,
type,
})
);
const normalizedFilteredMonitors = filteredMonitors.map((monitor) => {
if (!monitor.checks) {
return monitor;
getMonitorsByTeamId = async ({ teamId, type, filter }) => {
try {
const matchStage = { teamId: new this.ObjectId(teamId) };
if (type !== undefined) {
matchStage.type = Array.isArray(type) ? { $in: type } : type;
}
monitor.checks = this.NormalizeData(monitor.checks, 10, 100);
return monitor;
});
return { summary, monitors, filteredMonitors: normalizedFilteredMonitors };
if (filter !== undefined && filter !== null && filter !== "") {
matchStage.$or = [{ name: { $regex: filter, $options: "i" } }, { url: { $regex: filter, $options: "i" } }];
}
const monitors = await this.Monitor.find(matchStage)
.sort({ name: 1 })
.select({
_id: 1,
name: 1,
type: 1,
url: 1,
status: 1,
isActive: 1,
teamId: 1,
})
.lean();
return monitors;
} catch (error) {
error.service = SERVICE_NAME;
error.method = "getMonitorsByTeamId";
throw error;
}
};
getMonitorsAndSummaryByTeamId = async ({ type, explain, teamId }) => {
+2 -26
View File
@@ -323,34 +323,10 @@ export class MonitorService implements IMonitorService {
return monitor;
};
getMonitorsByTeamId = async ({
teamId,
limit,
type,
page,
rowsPerPage,
filter,
field,
order,
}: {
teamId: string;
limit?: number;
type?: string | string[];
page?: number;
rowsPerPage?: number;
filter?: string;
field?: string;
order?: "asc" | "desc";
}): Promise<any> => {
const monitors = await this.db.monitorModule.getMonitorsByTeamId({
limit,
getMonitorsByTeamId = async ({ teamId, type, filter }: { teamId: string; type?: MonitorType | MonitorType[]; filter?: string }): Promise<any> => {
const monitors = await this.monitorsRepository.findByTeamId(teamId, {
type,
page,
rowsPerPage,
filter,
field,
order,
teamId,
});
return monitors;
};
+19 -6
View File
@@ -120,18 +120,30 @@ const getMonitorByIdQueryValidation = joi.object({
const getMonitorsByTeamIdParamValidation = joi.object({});
const getMonitorsByTeamIdQueryValidation = joi.object({
limit: joi.number(),
type: joi
.alternatives()
.try(
joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port", "game"),
joi.array().items(joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port", "game"))
),
page: joi.number(),
rowsPerPage: joi.number(),
filter: joi.string(),
field: joi.string(),
order: joi.string().valid("asc", "desc"),
filter: joi.string().allow("", null),
});
const getMonitorsWithChecksQueryValidation = joi.object({
limit: joi.number().integer().min(1).max(100).optional(),
page: joi.number().integer().min(0).optional(),
rowsPerPage: joi.number().integer().min(1).max(100).optional(),
filter: joi.string().allow("", null).optional(),
field: joi.string().optional(),
order: joi.string().valid("asc", "desc").optional(),
type: joi
.alternatives()
.try(
joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port", "game"),
joi.array().items(joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port", "game"))
)
.optional(),
explain: joi.boolean().optional(),
});
const getCertificateParamValidation = joi.object({
@@ -713,6 +725,7 @@ export {
getMonitorByIdQueryValidation,
getMonitorsByTeamIdParamValidation,
getMonitorsByTeamIdQueryValidation,
getMonitorsWithChecksQueryValidation,
getHardwareDetailsByIdParamValidation,
getHardwareDetailsByIdQueryValidation,
getCertificateParamValidation,