diff --git a/Dashboard/src/Components/Dashboard/Canvas/ArgumentsForm.tsx b/Dashboard/src/Components/Dashboard/Canvas/ArgumentsForm.tsx index 361e8b7496..8ab084145e 100644 --- a/Dashboard/src/Components/Dashboard/Canvas/ArgumentsForm.tsx +++ b/Dashboard/src/Components/Dashboard/Canvas/ArgumentsForm.tsx @@ -86,6 +86,7 @@ const ArgumentsForm: FunctionComponent = ( data={value[arg.id] as MetricQueryConfigData} metricNameAndUnits={props.metrics.metricNameAndUnits} telemetryAttributes={props.metrics.telemetryAttributes} + hideCard={true} /> ); }; diff --git a/Dashboard/src/Components/Dashboard/Components/DashboardBaseComponent.tsx b/Dashboard/src/Components/Dashboard/Components/DashboardBaseComponent.tsx index ead69a9a6c..d2f9ef3948 100644 --- a/Dashboard/src/Components/Dashboard/Components/DashboardBaseComponent.tsx +++ b/Dashboard/src/Components/Dashboard/Components/DashboardBaseComponent.tsx @@ -18,6 +18,8 @@ import { GetReactElementFunction } from "Common/UI/Types/FunctionTypes"; import DashboardViewConfig from "Common/Types/Dashboard/DashboardViewConfig"; import ObjectID from "Common/Types/ObjectID"; import DashboardComponentType from "Common/Types/Dashboard/DashboardComponentType"; +import DashboardStartAndEndDate from "../Types/DashboardStartAndEndDate"; +import MetricNameAndUnit from "../../Metrics/Types/MetricNameAndUnit"; export interface DashboardBaseComponentProps { componentId: ObjectID; @@ -31,6 +33,8 @@ export interface DashboardBaseComponentProps { dashboardCanvasWidthInPx: number; dashboardCanvasHeightInPx: number; dashboardViewConfig: DashboardViewConfig; + dashboardStartAndEndDate: DashboardStartAndEndDate; + metricNameAndUnits: Array; } export interface ComponentProps extends DashboardBaseComponentProps { diff --git a/Dashboard/src/Components/Dashboard/Components/DashboardChartComponent.tsx b/Dashboard/src/Components/Dashboard/Components/DashboardChartComponent.tsx index cd64b4ac81..ff370145dc 100644 --- a/Dashboard/src/Components/Dashboard/Components/DashboardChartComponent.tsx +++ b/Dashboard/src/Components/Dashboard/Components/DashboardChartComponent.tsx @@ -1,6 +1,15 @@ -import React, { FunctionComponent, ReactElement } from "react"; +import React, { FunctionComponent, ReactElement, useEffect } from "react"; import DashboardChartComponent from "Common/Types/Dashboard/DashboardComponents/DashboardChartComponent"; import { DashboardBaseComponentProps } from "./DashboardBaseComponent"; +import MetricCharts from "../../Metrics/MetricCharts"; +import AggregatedResult from "Common/Types/BaseDatabase/AggregatedResult"; +import { DashboardStartAndEndDateUtil } from "../Types/DashboardStartAndEndDate"; +import PageLoader from "Common/UI/Components/Loader/PageLoader"; +import ErrorMessage from "Common/UI/Components/ErrorMessage/ErrorMessage"; +import { PromiseVoidFunction } from "Common/Types/FunctionTypes"; +import MetricViewData from "../../Metrics/Types/MetricViewData"; +import MetricUtil from "../../Metrics/Utils/Metrics"; +import API from "Common/UI/Utils/API/API"; export interface ComponentProps extends DashboardBaseComponentProps { component: DashboardChartComponent; @@ -9,7 +18,65 @@ export interface ComponentProps extends DashboardBaseComponentProps { const DashboardChartComponentElement: FunctionComponent = ( props: ComponentProps, ): ReactElement => { - return
Chart Component {props.component.componentId.toString()}
; + + const [metricResults, setMetricResults] = React.useState>([]); + const [error, setError] = React.useState(null); + const [isLoading, setIsLoading] = React.useState(true); + + const metricViewData: MetricViewData = { + queryConfigs: props.component.arguments.metricQueryConfig ? [props.component.arguments.metricQueryConfig] : [], + startAndEndDate: DashboardStartAndEndDateUtil.getStartAndEndDate(props.dashboardStartAndEndDate), + formulaConfigs: [] + } + + const fetchAggregatedResults: PromiseVoidFunction = + async (): Promise => { + + + setIsLoading(true); + + if ( + !metricViewData.startAndEndDate?.startValue || + !metricViewData.startAndEndDate?.endValue + ) { + setIsLoading(false); + return; + } + try { + const results: Array = await MetricUtil.fetchResults({ + metricViewData: metricViewData, + }); + + setMetricResults(results); + setError(""); + } catch (err: unknown) { + setError(API.getFriendlyErrorMessage(err as Error)); + } + + setIsLoading(false); + }; + + if (isLoading) { + return ; + } + + if (error) { + return ; + } + + useEffect(() => { + fetchAggregatedResults(); + }, [props.dashboardStartAndEndDate, props.component.arguments.metricQueryConfig, props.metricNameAndUnits]); + + + + return
+ +
; }; export default DashboardChartComponentElement; diff --git a/Dashboard/src/Components/Dashboard/Types/DashboardStartAndEndDate.ts b/Dashboard/src/Components/Dashboard/Types/DashboardStartAndEndDate.ts index 9568505471..e46f4a827e 100644 --- a/Dashboard/src/Components/Dashboard/Types/DashboardStartAndEndDate.ts +++ b/Dashboard/src/Components/Dashboard/Types/DashboardStartAndEndDate.ts @@ -1,7 +1,64 @@ import InBetween from "Common/Types/BaseDatabase/InBetween"; import DashboardStartAndEndDateRange from "./DashboardStartAndEndDateRange"; +import OneUptimeDate from "Common/Types/Date"; export default interface DashboardStartAndEndDate { startAndEndDate?: InBetween | undefined; range: DashboardStartAndEndDateRange; } + +export class DashboardStartAndEndDateUtil { + public static getStartAndEndDate(dashboardStartAndEndDate: DashboardStartAndEndDate): InBetween { + const currentDate: Date = OneUptimeDate.getCurrentDate(); + + // 30 mins. + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_THIRTY_MINS) { + return new InBetween(OneUptimeDate.addRemoveMinutes(currentDate, -30), currentDate); + } + + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_ONE_HOUR) { + return new InBetween(OneUptimeDate.addRemoveHours(currentDate, -1), currentDate); + } + + // two hours. + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_TWO_HOURS) { + return new InBetween(OneUptimeDate.addRemoveHours(currentDate, -2), currentDate); + } + + // three hours + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_THREE_HOURS) { + return new InBetween(OneUptimeDate.addRemoveHours(currentDate, -3), currentDate); + } + + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_ONE_DAY) { + return new InBetween(OneUptimeDate.addRemoveDays(currentDate, -1), currentDate); + } + + // two days . + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_TWO_DAYS) { + return new InBetween(OneUptimeDate.addRemoveDays(currentDate, -2), currentDate); + } + + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_ONE_WEEK) { + return new InBetween(OneUptimeDate.addRemoveDays(currentDate, -7), currentDate); + } + + // two weeks. + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_TWO_WEEKS) { + return new InBetween(OneUptimeDate.addRemoveDays(currentDate, -14), currentDate); + } + + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_ONE_MONTH) { + return new InBetween(OneUptimeDate.addRemoveMonths(currentDate, -1), currentDate); + } + + // three months. + if(dashboardStartAndEndDate.range === DashboardStartAndEndDateRange.PAST_THREE_MONTHS) { + return new InBetween(OneUptimeDate.addRemoveMonths(currentDate, -3), currentDate); + } + + // custom + return dashboardStartAndEndDate.startAndEndDate || new InBetween(currentDate, currentDate); + + } +} \ No newline at end of file diff --git a/Dashboard/src/Components/Metrics/MetricQueryConfig.tsx b/Dashboard/src/Components/Metrics/MetricQueryConfig.tsx index 0d57f705fd..94db90bcac 100644 --- a/Dashboard/src/Components/Metrics/MetricQueryConfig.tsx +++ b/Dashboard/src/Components/Metrics/MetricQueryConfig.tsx @@ -22,6 +22,7 @@ export interface ComponentProps { onFocus?: (() => void) | undefined; onBlur?: (() => void) | undefined; tabIndex?: number | undefined; + hideCard?: boolean | undefined; } const MetricGraphConfig: FunctionComponent = ( @@ -35,53 +36,64 @@ const MetricGraphConfig: FunctionComponent = ( throw new BadDataException("MetricQueryData is required"); } + + const getContent = (): ReactElement => { + return ( +
{props.data.metricAliasData && ( + { + props.onBlur?.(); + props.onFocus?.(); + props.onChange && + props.onChange({ ...props.data, metricAliasData: data }); + }} + isFormula={false} + /> + )} + {props.data.metricQueryData && ( + { + props.onBlur?.(); + props.onFocus?.(); + props.onChange && + props.onChange({ ...props.data, metricQueryData: data }); + }} + metricNameAndUnits={props.metricNameAndUnits} + telemetryAttributes={props.telemetryAttributes} + /> + )} + {props.onRemove && ( +
+
+ )} + {props.error && ( +

+ {props.error} +

+ )} +
); + } + + if(props.hideCard) { + return getContent(); + } + return (
- {props.data.metricAliasData && ( - { - props.onBlur?.(); - props.onFocus?.(); - props.onChange && - props.onChange({ ...props.data, metricAliasData: data }); - }} - isFormula={false} - /> - )} - {props.data.metricQueryData && ( - { - props.onBlur?.(); - props.onFocus?.(); - props.onChange && - props.onChange({ ...props.data, metricQueryData: data }); - }} - metricNameAndUnits={props.metricNameAndUnits} - telemetryAttributes={props.telemetryAttributes} - /> - )} - {props.onRemove && ( -
-
- )} - {props.error && ( -

- {props.error} -

- )} + {getContent()}
); diff --git a/Dashboard/src/Components/Metrics/MetricView.tsx b/Dashboard/src/Components/Metrics/MetricView.tsx index 80c8a663fa..4e3f4b6782 100644 --- a/Dashboard/src/Components/Metrics/MetricView.tsx +++ b/Dashboard/src/Components/Metrics/MetricView.tsx @@ -23,18 +23,11 @@ import Card from "Common/UI/Components/Card/Card"; import AggregatedResult from "Common/Types/BaseDatabase/AggregatedResult"; import API from "Common/UI/Utils/API/API"; import { PromiseVoidFunction } from "Common/Types/FunctionTypes"; -import ModelAPI from "Common/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI"; -import Metric from "Common/Models/AnalyticsModels/Metric"; -import OneUptimeDate from "Common/Types/Date"; -import { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax"; import ComponentLoader from "Common/UI/Components/ComponentLoader/ComponentLoader"; import ErrorMessage from "Common/UI/Components/ErrorMessage/ErrorMessage"; -import AggregatedModel from "Common/Types/BaseDatabase/AggregatedModel"; import IconProp from "Common/Types/Icon/IconProp"; import PageLoader from "Common/UI/Components/Loader/PageLoader"; -import Dictionary from "Common/Types/Dictionary"; import MetricNameAndUnit from "./Types/MetricNameAndUnit"; - import MetricQueryConfigData from "Common/Types/Metrics/MetricQueryConfigData"; import MetricFormulaConfigData from "Common/Types/Metrics/MetricFormulaConfigData"; import MetricUtil from "./Utils/Metrics"; @@ -155,49 +148,10 @@ const MetricView: FunctionComponent = ( setIsMetricResultsLoading(false); return; } - - const results: Array = []; try { - for (const queryConfig of metricViewData.queryConfigs) { - const result: AggregatedResult = await ModelAPI.aggregate({ - modelType: Metric, - aggregateBy: { - query: { - time: metricViewData.startAndEndDate!, - name: queryConfig.metricQueryData.filterData.metricName!, - attributes: queryConfig.metricQueryData.filterData - .attributes as Dictionary, - }, - aggregationType: - (queryConfig.metricQueryData.filterData - .aggegationType as MetricsAggregationType) || - MetricsAggregationType.Avg, - aggregateColumnName: "value", - aggregationTimestampColumnName: "time", - startTimestamp: - (metricViewData.startAndEndDate?.startValue as Date) || - OneUptimeDate.getCurrentDate(), - endTimestamp: - (metricViewData.startAndEndDate?.endValue as Date) || - OneUptimeDate.getCurrentDate(), - limit: LIMIT_PER_PROJECT, - skip: 0, - groupBy: queryConfig.metricQueryData.groupBy, - }, - }); - - result.data.map((data: AggregatedModel) => { - // convert to int from float - - if (data.value) { - data.value = Math.round(data.value); - } - - return data; - }); - - results.push(result); - } + const results: Array = await MetricUtil.fetchResults({ + metricViewData: metricViewData, + }); setMetricResults(results); setMetricResultsError(""); @@ -208,18 +162,6 @@ const MetricView: FunctionComponent = ( setIsMetricResultsLoading(false); }; - // type GetEmptyFormulaConfigFunction = () => MetricFormulaConfigData; - - // const getEmptyFormulaConfigData: GetEmptyFormulaConfigFunction = - // (): MetricFormulaConfigData => { - // return { - // metricAliasData: { metricVariable: "", title: "", description: "" }, - // metricFormulaData: { - // metricFormula: "", - // }, - // }; - // }; - if (isPageLoading) { return ; } diff --git a/Dashboard/src/Components/Metrics/Utils/Metrics.ts b/Dashboard/src/Components/Metrics/Utils/Metrics.ts index c352b21198..c300905cd2 100644 --- a/Dashboard/src/Components/Metrics/Utils/Metrics.ts +++ b/Dashboard/src/Components/Metrics/Utils/Metrics.ts @@ -11,8 +11,67 @@ import { JSONObject } from "Common/Types/JSON"; import API from "Common/UI/Utils/API/API"; import URL from "Common/Types/API/URL"; import { APP_API_URL } from "Common/UI/Config"; +import AggregatedModel from "Common/Types/BaseDatabase/AggregatedModel"; +import MetricsAggregationType from "Common/Types/Metrics/MetricsAggregationType"; +import Dictionary from "Common/Types/Dictionary"; +import AggregatedResult from "Common/Types/BaseDatabase/AggregatedResult"; +import MetricViewData from "../Types/MetricViewData"; +import OneUptimeDate from "Common/Types/Date"; export default class MetricUtil { + + + public static async fetchResults(data: { + metricViewData: MetricViewData; + }): Promise> { + const results: Array = []; + + const metricViewData: MetricViewData = data.metricViewData; + + for (const queryConfig of metricViewData.queryConfigs) { + const result: AggregatedResult = await ModelAPI.aggregate({ + modelType: Metric, + aggregateBy: { + query: { + time: metricViewData.startAndEndDate!, + name: queryConfig.metricQueryData.filterData.metricName!, + attributes: queryConfig.metricQueryData.filterData + .attributes as Dictionary, + }, + aggregationType: + (queryConfig.metricQueryData.filterData + .aggegationType as MetricsAggregationType) || + MetricsAggregationType.Avg, + aggregateColumnName: "value", + aggregationTimestampColumnName: "time", + startTimestamp: + (metricViewData.startAndEndDate?.startValue as Date) || + OneUptimeDate.getCurrentDate(), + endTimestamp: + (metricViewData.startAndEndDate?.endValue as Date) || + OneUptimeDate.getCurrentDate(), + limit: LIMIT_PER_PROJECT, + skip: 0, + groupBy: queryConfig.metricQueryData.groupBy, + }, + }); + + result.data.map((data: AggregatedModel) => { + // convert to int from float + + if (data.value) { + data.value = Math.round(data.value); + } + + return data; + }); + + results.push(result); + } + + return results; + } + public static async loadAllMetricsTypes(): Promise<{ metricNamesAndUnits: Array; telemetryAttributes: Array; @@ -63,14 +122,14 @@ export default class MetricUtil { const metricAttributesResponse: | HTTPResponse | 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(), + }, + ); let attributes: Array = [];