Refactor code for consistency by standardizing property names and improving formatting across various components

This commit is contained in:
Simon Larsen 2024-11-11 17:24:05 +00:00
parent 86e6bca5e1
commit d9d2b615d2
No known key found for this signature in database
GPG Key ID: 96C5DCA24769DBCA
11 changed files with 211 additions and 70 deletions

View File

@ -291,15 +291,14 @@ export default class BaseAnalyticsAPI<
) as any;
}
let groupBy: GroupBy<AnalyticsDataModel> | null = req.body["groupBy"] || null;
let groupBy: GroupBy<AnalyticsDataModel> | null =
req.body["groupBy"] || null;
if(groupBy && Object.keys(groupBy).length > 0) {
groupBy = JSONFunctions.deserialize(
groupBy as JSONObject,
) as any;
if (groupBy && Object.keys(groupBy).length > 0) {
groupBy = JSONFunctions.deserialize(groupBy as JSONObject) as any;
}
if(groupBy && Object.keys(groupBy).length === 0) {
if (groupBy && Object.keys(groupBy).length === 0) {
groupBy = null;
}

View File

@ -57,14 +57,14 @@ import ModelEventType from "../../Types/Realtime/ModelEventType";
export default class AnalyticsDatabaseService<
TBaseModel extends AnalyticsBaseModel,
> extends BaseService {
public modelType!: { new(): TBaseModel };
public modelType!: { new (): TBaseModel };
public database!: ClickhouseDatabase;
public model!: TBaseModel;
public databaseClient!: ClickhouseClient;
public statementGenerator!: StatementGenerator<TBaseModel>;
public constructor(data: {
modelType: { new(): TBaseModel };
modelType: { new (): TBaseModel };
database?: ClickhouseDatabase | undefined;
}) {
super();
@ -240,8 +240,6 @@ export default class AnalyticsDatabaseService<
columns: Array<string>;
} = this.toAggregateStatement(aggregateBy);
debugger;
const dbResult: ExecResult<Stream> = await this.execute(
findStatement.statement,
);
@ -261,22 +259,24 @@ export default class AnalyticsDatabaseService<
// convert date column from string to date.
const groupByColumnName: keyof TBaseModel | undefined = aggregateBy.groupBy && Object.keys(aggregateBy.groupBy).length > 0 ? Object.keys(aggregateBy.groupBy)[0] as keyof TBaseModel : undefined;
const groupByColumnName: keyof TBaseModel | undefined =
aggregateBy.groupBy && Object.keys(aggregateBy.groupBy).length > 0
? (Object.keys(aggregateBy.groupBy)[0] as keyof TBaseModel)
: undefined;
for (const item of items) {
if (
!(item as JSONObject)[
aggregateBy.aggregationTimestampColumnName as string
aggregateBy.aggregationTimestampColumnName as string
]
) {
continue;
}
const aggregatedModel: AggregatedModel = {
timestamp: OneUptimeDate.fromString(
(item as JSONObject)[
aggregateBy.aggregationTimestampColumnName as string
aggregateBy.aggregationTimestampColumnName as string
] as string,
),
value: (item as JSONObject)[

View File

@ -548,17 +548,18 @@ export default class StatementGenerator<TBaseModel extends AnalyticsBaseModel> {
`${aggregationMethod}(${aggregateBy.aggregateColumnName.toString()}) as ${aggregateBy.aggregateColumnName.toString()}, date_trunc('${aggregationInterval.toLowerCase()}', toStartOfInterval(${aggregateBy.aggregationTimestampColumnName.toString()}, INTERVAL 1 ${aggregationInterval.toLowerCase()})) as ${aggregateBy.aggregationTimestampColumnName.toString()}`,
);
const columns: Array<string> = [
aggregateBy.aggregateColumnName.toString(),
aggregateBy.aggregationTimestampColumnName.toString(),
];
if(aggregateBy.groupBy && Object.keys(aggregateBy.groupBy).length > 0) {
const groupByStatement: Statement = this.toGroupByStatement(aggregateBy.groupBy);
if (aggregateBy.groupBy && Object.keys(aggregateBy.groupBy).length > 0) {
const groupByStatement: Statement = this.toGroupByStatement(
aggregateBy.groupBy,
);
selectStatement.append(SQL`, `).append(groupByStatement);
// add to columns.
// add to columns.
for (const key in aggregateBy.groupBy) {
columns.push(key);
}

View File

@ -7,12 +7,11 @@ export default interface MetricsQuery {
aggegationType: MetricsAggregationType;
aggregateBy: Dictionary<boolean>;
// This is used for example for probes.
// To display US probe and EU probe in chart for example.
// This is used for example for probes.
// To display US probe and EU probe in chart for example.
// In this case groupByAttribute is "probeId"
// and attributeValueToLegendMap is { "xx-xx-xx-xx": "US Probe", "yy-yyy-yyy-yy-yy": "EU Probe" }
groupByAttribute?: string | undefined;
attributeValueToLegendMap?: Dictionary<string>;
}

View File

@ -47,7 +47,7 @@ const ChartGroup: FunctionComponent<ComponentProps> = (
{chart.description}
</p>
)}
<LineChart key={index} {...chart.props} syncId={syncId} />
<LineChart key={index} {...chart.props} syncid={syncId} />
</div>
);
default:

View File

@ -571,7 +571,7 @@ interface LineChartProps extends React.HTMLAttributes<HTMLDivElement> {
legendPosition?: "left" | "center" | "right";
tooltipCallback?: (tooltipCallbackContent: TooltipProps) => void;
customTooltip?: React.ComponentType<TooltipProps>;
syncId?: string | undefined;
syncid?: string | undefined;
}
const LineChart: React.ForwardRefExoticComponent<
@ -692,7 +692,7 @@ const LineChart: React.ForwardRefExoticComponent<
<ResponsiveContainer>
<RechartsLineChart
data={data}
syncId={props.syncId?.toString() || ""}
syncId={props.syncid?.toString() || ""}
onClick={
hasOnValueChange && (activeLegend || activeDot)
? () => {

View File

@ -16,7 +16,7 @@ export interface ComponentProps {
}
export interface LineInternalProps extends ComponentProps {
syncId: string;
syncid: string;
}
const LineChartElement: FunctionComponent<LineInternalProps> = (
@ -64,7 +64,7 @@ const LineChartElement: FunctionComponent<LineInternalProps> = (
showTooltip={true}
connectNulls={true}
curve={props.curve}
syncId={props.sync ? props.syncId : undefined}
syncid={props.sync ? props.syncid : undefined}
yAxisWidth={60}
/>
);

View File

@ -12,7 +12,7 @@ import Metric from "Common/Models/AnalyticsModels/Metric";
export interface MetricQueryData {
filterData: FilterData<MetricsQuery>;
groupBy?: GroupBy<Metric> | undefined;
groupBy?: GroupBy<Metric> | undefined;
}
export interface ComponentProps {

View File

@ -10,7 +10,7 @@ import Button, {
import MetricNameAndUnit from "./Types/MetricNameAndUnit";
import AggregatedModel from "Common/Types/BaseDatabase/AggregatedModel";
export interface ChartSeries {
export interface ChartSeries {
title: string;
}

View File

@ -5,7 +5,10 @@ import React, {
useEffect,
useState,
} from "react";
import MetricQueryConfig, { ChartSeries, MetricQueryConfigData } from "./MetricQueryConfig";
import MetricQueryConfig, {
ChartSeries,
MetricQueryConfigData,
} from "./MetricQueryConfig";
import MetricGraphConfig, {
MetricFormulaConfigData,
} from "./MetricFormulaConfig";
@ -199,12 +202,9 @@ const MetricView: FunctionComponent<ComponentProps> = (
xAxisAggregationType = XAxisAggregateType.Average;
}
let chartSeries: Array<SeriesPoint> = [
];
const chartSeries: Array<SeriesPoint> = [];
if (queryConfig.getSeries) {
for (const item of metricResults[index]!.data) {
const series: ChartSeries = queryConfig.getSeries(item);
const seriesName: string = series.title;
@ -213,27 +213,30 @@ const MetricView: FunctionComponent<ComponentProps> = (
// if it does not exist then create a new series and add the data to it
const existingSeries: SeriesPoint | undefined = chartSeries.find((s: SeriesPoint) => {
return s.seriesName === seriesName;
});
const existingSeries: SeriesPoint | undefined = chartSeries.find(
(s: SeriesPoint) => {
return s.seriesName === seriesName;
},
);
if (existingSeries) {
existingSeries.data.push({
x: OneUptimeDate.fromString(item.timestamp),
y: item.value
y: item.value,
});
} else {
const newSeries: SeriesPoint = {
seriesName: seriesName,
data: [{
x: OneUptimeDate.fromString(item.timestamp),
y: item.value
}]
data: [
{
x: OneUptimeDate.fromString(item.timestamp),
y: item.value,
},
],
};
chartSeries.push(newSeries);
}
}
} else {
chartSeries.push({
@ -241,14 +244,12 @@ const MetricView: FunctionComponent<ComponentProps> = (
queryConfig.metricAliasData.title ||
queryConfig.metricQueryData.filterData.metricName?.toString() ||
"",
data: metricResults[index]!.data.map(
(result: AggregatedModel) => {
return {
x: OneUptimeDate.fromString(result.timestamp),
y: result.value,
};
},
),
data: metricResults[index]!.data.map((result: AggregatedModel) => {
return {
x: OneUptimeDate.fromString(result.timestamp),
y: result.value,
};
}),
});
}
@ -365,14 +366,14 @@ const MetricView: FunctionComponent<ComponentProps> = (
const metricAttributesResponse:
| HTTPResponse<JSONObject>
| HTTPErrorResponse = await API.post(
URL.fromString(APP_API_URL.toString()).addRoute(
"/telemetry/metrics/get-attributes",
),
{},
{
...ModelAPI.getCommonHeaders(),
},
);
URL.fromString(APP_API_URL.toString()).addRoute(
"/telemetry/metrics/get-attributes",
),
{},
{
...ModelAPI.getCommonHeaders(),
},
);
if (metricAttributesResponse instanceof HTTPErrorResponse) {
throw metricAttributesResponse;
@ -421,7 +422,7 @@ const MetricView: FunctionComponent<ComponentProps> = (
OneUptimeDate.getCurrentDate(),
limit: LIMIT_PER_PROJECT,
skip: 0,
groupBy: queryConfig.metricQueryData.groupBy
groupBy: queryConfig.metricQueryData.groupBy,
},
});

View File

@ -9,16 +9,26 @@ import MonitorMetricTypeUtil from "Common/Utils/Monitor/MonitorMetricType";
import OneUptimeDate from "Common/Types/Date";
import InBetween from "Common/Types/BaseDatabase/InBetween";
import MetricView from "../Metrics/MetricView";
import { MetricQueryConfigData } from "../Metrics/MetricQueryConfig";
import {
ChartSeries,
MetricQueryConfigData,
} from "../Metrics/MetricQueryConfig";
import DashboardNavigation from "../../Utils/Navigation";
import MonitorMetricType from "Common/Types/Monitor/MonitorMetricType";
import MonitorType from "Common/Types/Monitor/MonitorType";
import MonitorType, {
MonitorTypeHelper,
} from "Common/Types/Monitor/MonitorType";
import API from "Common/UI/Utils/API/API";
import Monitor from "Common/Models/DatabaseModels/Monitor";
import ModelAPI from "Common/UI/Utils/ModelAPI/ModelAPI";
import PageLoader from "Common/UI/Components/Loader/PageLoader";
import ErrorMessage from "Common/UI/Components/ErrorMessage/ErrorMessage";
import { PromiseVoidFunction } from "Common/Types/FunctionTypes";
import ProbeUtil from "../../Utils/Probe";
import Probe from "Common/Models/DatabaseModels/Probe";
import AggregateModel from "Common/Types/BaseDatabase/AggregatedModel";
import { JSONObject } from "Common/Types/JSON";
import JSONFunctions from "Common/Types/JSONFunctions";
export interface ComponentProps {
monitorId: ObjectID;
@ -35,6 +45,8 @@ const MonitorMetricsElement: FunctionComponent<ComponentProps> = (
const [error, setError] = useState<string>("");
const [probes, setProbes] = useState<Array<Probe>>([]);
const fetchMonitor: PromiseVoidFunction = async (): Promise<void> => {
setIsLoading(true);
@ -47,7 +59,16 @@ const MonitorMetricsElement: FunctionComponent<ComponentProps> = (
},
});
setMonitorType(item?.monitorType || MonitorType.Manual);
const monitorType: MonitorType = item?.monitorType || MonitorType.Manual;
setMonitorType(monitorType);
const isProbeableMonitor: boolean =
MonitorTypeHelper.isProbableMonitor(monitorType);
if (isProbeableMonitor) {
setProbes(await ProbeUtil.getAllProbes());
}
} catch (err) {
setError(API.getFriendlyMessage(err));
}
@ -89,6 +110,10 @@ const MonitorMetricsElement: FunctionComponent<ComponentProps> = (
(): Array<MetricQueryConfigData> => {
const queries: Array<MetricQueryConfigData> = [];
if (!monitorType) {
return [];
}
for (const monitorMetricType of monitorMetricTypesByMonitor) {
queries.push({
metricAliasData: {
@ -113,18 +138,134 @@ const MonitorMetricsElement: FunctionComponent<ComponentProps> = (
MonitorMetricTypeUtil.getAggregationTypeByMonitorMetricType(
monitorMetricType,
),
},
groupBy: {
attributes: true
}
attributes: true,
},
},
getSeries: (data) => {
getSeries: (data: AggregateModel): ChartSeries => {
const isProbeableMonitor: boolean =
MonitorTypeHelper.isProbableMonitor(monitorType);
if (!data) {
return {
title:
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
if (isProbeableMonitor) {
let attributes: JSONObject = data["attributes"] as JSONObject;
if (!attributes) {
return {
title:
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
// if attributes is typeof string then parse it to JSON
if (typeof attributes === "string") {
try {
attributes = JSONFunctions.parseJSONObject(attributes);
} catch (err) {
return {
title:
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
}
const probeId: ObjectID = new ObjectID(
((attributes as JSONObject)["probeId"] as string)?.toString(),
);
if (!probeId) {
return {
title:
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
const probe: Probe | undefined = probes.find((probe: Probe) => {
return probe.id?.toString() === probeId.toString();
});
if (probe) {
return {
title:
probe.name?.toString() ||
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
return {
title:
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
if (monitorType === MonitorType.Server) {
let attributes: JSONObject = data["attributes"] as JSONObject;
if (!attributes) {
return {
title:
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
// if attributes is typeof string then parse it to JSON
if (typeof attributes === "string") {
try {
attributes = JSONFunctions.parseJSONObject(attributes);
} catch (err) {
return {
title:
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
}
if (attributes["diskPath"]) {
return {
title: attributes["diskPath"].toString(),
};
}
return {
title:
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
return {
title: data.attributes.monitorId,
title:
MonitorMetricTypeUtil.getTitleByMonitorMetricType(
monitorMetricType,
),
};
}
},
});
}