From 9878992af156c0fbaebe39529b93e5f129c469c5 Mon Sep 17 00:00:00 2001 From: Julia Robles <48439828+juliarobles@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:40:38 +0200 Subject: [PATCH] Now in the extra calculation you can set the moment to obtain the value to be considered (before or after applying all the preprocess) --- src/components/editors/extraCalcForm.tsx | 21 +++++- src/utils/datasources/extraCalc.tsx | 86 ++++++++++++++++-------- src/utils/datasources/predictions.tsx | 18 +++-- src/utils/default.tsx | 5 +- src/utils/types.tsx | 13 +++- 5 files changed, 108 insertions(+), 35 deletions(-) diff --git a/src/components/editors/extraCalcForm.tsx b/src/components/editors/extraCalcForm.tsx index b519e59..ee6ba19 100644 --- a/src/components/editors/extraCalcForm.tsx +++ b/src/components/editors/extraCalcForm.tsx @@ -1,6 +1,6 @@ import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react' import { SelectableValue, StandardEditorContext } from "@grafana/data"; -import { Calc, ExtraCalcFormat, IExtraCalc, ISelect } from 'utils/types'; +import { Calc, ExtraCalcFormat, IExtraCalc, ISelect, WhenApplyEnum } from 'utils/types'; import { Alert, Button, Collapse, ConfirmButton, DeleteButton, Form, FormAPI, HorizontalGroup, InlineField, Input, InputControl, Select, useTheme2 } from '@grafana/ui'; import { ExtraCalcDefault } from 'utils/default'; import { Mode } from 'utils/constants'; @@ -23,10 +23,12 @@ export const ExtraCalcForm: React.FC = ({ extraCalc, updateFunction, dele const calcOptions: ISelect[] = enumToSelect(Calc) const formatOptions: ISelect[] = enumToSelect(ExtraCalcFormat) + const whenApplyOptions: ISelect[] = enumToSelect(WhenApplyEnum) const [currentCalc, setCurrentCalc] = useState(ExtraCalcDefault) const [selectedCalc, setSelectedCalc] = useState>(calcOptions[0]) const [selectedFormat, setSelectedFormat] = useState>(formatOptions[0]) + const [selectedWhen, setSelectedWhen] = useState>(whenApplyOptions[0]) const [currentDynamicFields, setCurrentDynamicFields] = useState([]) const [currentDynFieldName, setCurrentDynFieldName] = useState("") const [disabled, setDisabled] = useState(false) @@ -35,6 +37,7 @@ export const ExtraCalcForm: React.FC = ({ extraCalc, updateFunction, dele setCurrentCalc(extraCalc) setSelectedCalc({ value: extraCalc.calc, label: extraCalc.calc as string }) setSelectedFormat({ value: extraCalc.resFormat, label: extraCalc.resFormat as string }) + setSelectedWhen({ value: extraCalc.whenApply, label: extraCalc.whenApply as string }) if (extraCalc.dynamicFields) setCurrentDynamicFields(extraCalc.dynamicFields) } @@ -56,6 +59,7 @@ export const ExtraCalcForm: React.FC = ({ extraCalc, updateFunction, dele ...currentCalc, calc: selectedCalc.value, resFormat: selectedFormat.value, + whenApply: selectedWhen.value, dynamicFields: currentDynamicFields }) if (mode === Mode.EDIT) { @@ -167,6 +171,21 @@ export const ExtraCalcForm: React.FC = ({ extraCalc, updateFunction, dele + + + diff --git a/src/utils/datasources/extraCalc.tsx b/src/utils/datasources/extraCalc.tsx index 7579c1c..c44a125 100644 --- a/src/utils/datasources/extraCalc.tsx +++ b/src/utils/datasources/extraCalc.tsx @@ -1,7 +1,7 @@ -import { Calc, DateRes, ExtraCalcFormat, IDataCollection, IDataPred, IModel, IResult, ITag } from "utils/types" -import { getListValuesFromNew, newDataToObject, predictResults } from "./predictions" +import { Calc, DateRes, ExtraCalcFormat, IDataCollection, IDataPred, IModel, IResult, ITag, PostChangeIDataPred, WhenApplyEnum } from "utils/types" +import { getListValuesFromNew, newDataToObject, predictResults, prepareAndPredictResults, prepareToPredict } from "./predictions" import vm from 'vm' -import { getMean } from "utils/utils" +import { deepCopy, getMean } from "utils/utils" import { dateTime, DateTime } from "@grafana/data" const replaceVariables = (text: string, data: IDataPred, dyn?: number[], lastResult?: number) => { @@ -63,32 +63,56 @@ const applyFormatToRes = (res: number, format: ExtraCalcFormat, selectedDate?: D return res.toString() } -const createRequests = (num: number, calcValue: number, data: IDataPred, tag: string, calc: Calc, idNumber: number) => { +const createRequests = (iniRes: IResult, num: number, calcValue: number, data: IDataPred, tag: string, calc: Calc, idNumber: number, isProcessed = false): PostChangeIDataPred => { let res: IResult[] = [] + let allData: IDataPred[] = [] for (let i = 0; i < num; i++) { + let newResult = deepCopy(iniRes) let mean = getMean(data[tag]) let newValue = applyCalcValue(mean, calcValue, calc) data = { ...data, [tag]: getListValuesFromNew(newValue, mean, data[tag]) } - res.push({ - id: ("extraCalc_" + (idNumber + i)), - data: { ...data }, - correspondsWith: { tag: tag, intervalValue: newValue } - }) + const copyData = {...data} + allData.push(copyData) + + newResult.id = newResult.id + "_" + (idNumber + i) + newResult.correspondsWith.intervalValue = newValue + if(isProcessed) { + newResult.processedData = {...copyData} + } else { + newResult.data = {...copyData} + } + + res.push(newResult) } - return res + return {newData: allData, newResults: res} +} + +const check = (r: IResult, model: IModel, isAfter: boolean, dyn?: number[]) => { + if(r.result && model.extraCalc && typeof r.result === 'number') { + let condition = "" + if(isAfter && r.processedData) { + condition = replaceVariables(model.extraCalc.until, r.processedData, dyn, r.result) + } else { + condition = replaceVariables(model.extraCalc.until, r.data, dyn, r.result) + } + return executeString(condition) + } + return false } export const extraCalcCollection = async (model: IModel, col: IDataCollection, dyn?: number[]): Promise => { if (model.extraCalc && model.tags.some((tag: ITag) => tag.id === model.extraCalc?.tag)) { let res: IResult[] = [] + let calcValue = 0 + let results: IResult[] = [] const tag = model.extraCalc.tag + const isAfter = model.extraCalc.whenApply === WhenApplyEnum.afterPreprocess // Preparamos los datos iniciales y obtenemos el valor para los calculos let data: IDataPred = prepareInitialData(col, model.numberOfValues) - const calcValue = executeString(replaceVariables(model.extraCalc.calcValue, data, dyn)) // Creamos el resultado inicial const iniResult: IResult = { @@ -96,27 +120,35 @@ export const extraCalcCollection = async (model: IModel, col: IDataCollection, d data: { ...data }, correspondsWith: { tag: tag, intervalValue: getMean(data[tag]) } } - - // Generamos el resto de resultados sumando calc de forma recursiva al tag correspondiente y predecimos - let results = [iniResult, ...createRequests((model.extraCalc.numRequests-1), calcValue, data, tag, model.extraCalc.calc, 1)] - results = await predictResults(model, results) - // Comprobamos si se cumple la condicion en alguno - const check = (r: IResult) => { - if(r.result && model.extraCalc && typeof r.result === 'number') { - const condition = replaceVariables(model.extraCalc.until, r.data, dyn, r.result) - return executeString(condition) - } - return false + if(isAfter){ + const prep = await prepareToPredict(model, [iniResult]) + calcValue = executeString(replaceVariables(model.extraCalc.calcValue, prep.newData[0], dyn)) + const requests = createRequests(iniResult, (model.extraCalc.numRequests-1), calcValue, prep.newData[0], tag, model.extraCalc.calc, 1, true) + results = await predictResults(model, [...prep.newData, ...requests.newData], [...prep.newResults, ...requests.newResults]) + } else { + calcValue = executeString(replaceVariables(model.extraCalc.calcValue, data, dyn)) + results = [iniResult, ...createRequests(iniResult, (model.extraCalc.numRequests-1), calcValue, data, tag, model.extraCalc.calc, 1).newResults] + results = await prepareAndPredictResults(model, results) } - let idxFin = results.findIndex(check) + + // Comprobamos si se cumple la condicion en alguno + let idxFin = results.findIndex((r) => check(r, model, isAfter, dyn)) while (idxFin < 0) { // Probamos hasta que se cumpla alguna condicion - data = results[results.length-1].data + const lastRes = results[results.length-1] res = [...res, ...results] - results = [...createRequests(model.extraCalc.numRequests, calcValue, data, tag, model.extraCalc.calc, res.length)] - results = await predictResults(model, results) - idxFin = results.findIndex(check) + if(isAfter && lastRes.processedData){ + data = lastRes.processedData + results = [...createRequests(iniResult, model.extraCalc.numRequests, calcValue, data, tag, model.extraCalc.calc, res.length).newResults] + const requests = createRequests(iniResult, model.extraCalc.numRequests, calcValue, data, tag, model.extraCalc.calc, res.length, true) + results = await predictResults(model, [...requests.newData], [...requests.newResults]) + } else { + data = lastRes.data + results = [...createRequests(iniResult, model.extraCalc.numRequests, calcValue, data, tag, model.extraCalc.calc, res.length).newResults] + results = await prepareAndPredictResults(model, results) + } + idxFin = results.findIndex((r) => check(r, model, isAfter, dyn)) } res = (idxFin + 1 < results.length) ? [...res, ...results.slice(0, (idxFin+1))] : [...res, ...results] diff --git a/src/utils/datasources/predictions.tsx b/src/utils/datasources/predictions.tsx index e831d18..aad323c 100644 --- a/src/utils/datasources/predictions.tsx +++ b/src/utils/datasources/predictions.tsx @@ -1,5 +1,5 @@ import { PreprocessCodeDefault } from "../default"; -import { IData, IDataCollection, IDataPred, IFormat, IInterval, IModel, IResult, IScaler, IntervalTypeEnum } from "../types" +import { IData, IDataCollection, IDataPred, IFormat, IInterval, IModel, IResult, IScaler, IntervalTypeEnum, PostChangeIDataPred } from "../types" //import * as dfd from "danfojs" import { idDefault, idNew, varEachInput, varEachInputEnd, varInput, variableOutput } from "../constants" import vm from 'vm' @@ -15,7 +15,7 @@ export const predictAllCollections = async (model: IModel, allData: IDataCollect return allData } -export const predictResults = async (model: IModel, results: IResult[]) => { +export const prepareToPredict = async (model: IModel, results: IResult[]): Promise => { let dataToPredict: IDataPred[] = [] for (const [i, r] of results.entries()) { let finalData = deepCopy(r.data) @@ -33,15 +33,25 @@ export const predictResults = async (model: IModel, results: IResult[]) => { dataToPredict.push(finalData) results[i] = { ...r, processedData: finalData } } - const predictions: any = await sendRequest(model, dataToPredict) + return {newData: dataToPredict, newResults: results} +} + +export const predictResults = async (model: IModel, data: IDataPred[], results: IResult[]) => { + const predictions: any = await sendRequest(model, data) return results.map((r: IResult, indx: number) => { return { ...r, result: predictions[indx] } }) } +export const prepareAndPredictResults = async (model: IModel, results: IResult[]) => { + const res = await prepareToPredict(model, results) + console.log("prepareResults", res) + return await predictResults(model, res.newData, res.newResults) +} + const predictData = async (model: IModel, dataCollection: IDataCollection) => { //console.log("numValues", model.numberOfValues) //console.log("dataCollection", dataCollection) let results: IResult[] = prepareData(dataCollection, model.numberOfValues) - return await predictResults(model, results) + return await prepareAndPredictResults(model, results) } const getValuesFromInterval = (interval: IInterval): number[] => { diff --git a/src/utils/default.tsx b/src/utils/default.tsx index aab37c2..5ad1852 100644 --- a/src/utils/default.tsx +++ b/src/utils/default.tsx @@ -1,5 +1,5 @@ import { messages_en } from "./localization/en"; -import { FormatTags, IContext, IDataCollection, IFormat, IModel, IInterval, ITag, Language, Method, IntervalTypeEnum, IExtraCalc, Calc, ExtraCalcFormat } from "./types"; +import { FormatTags, IContext, IDataCollection, IFormat, IModel, IInterval, ITag, Language, Method, IntervalTypeEnum, IExtraCalc, Calc, ExtraCalcFormat, WhenApplyEnum } from "./types"; export const PreprocessCodeDefault = "console.log('Preprocess')" @@ -19,7 +19,8 @@ export const ExtraCalcDefault: IExtraCalc = { resProcess: "$res", maxIterations: 1000, resFormat: ExtraCalcFormat.raw, - numRequests: 10 + numRequests: 10, + whenApply: WhenApplyEnum.afterPreprocess } export const ModelDefault: IModel = { diff --git a/src/utils/types.tsx b/src/utils/types.tsx index 053a3bd..e79aa2f 100644 --- a/src/utils/types.tsx +++ b/src/utils/types.tsx @@ -20,6 +20,11 @@ export enum ExtraCalcFormat { addDays = "Add as days to selected date" } +export enum WhenApplyEnum { + afterPreprocess = "After preprocessing", + beforePreprocess = "Before preprocessing" +} + export enum FormatTags { None = 'None', dq = 'Double quotes', @@ -152,7 +157,13 @@ export interface IExtraCalc { resProcess: string, maxIterations: number, resFormat: ExtraCalcFormat, - numRequests: number + numRequests: number, + whenApply: WhenApplyEnum +} + +export interface PostChangeIDataPred { + newData: IDataPred[], + newResults: IResult[] } export class DateRes {