mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 00:09:35 +00:00
rename zinc to OpenObserve --------- Co-authored-by: Taiming Liu <90490946+taimingl@users.noreply.github.com>
821 lines
28 KiB
Vue
821 lines
28 KiB
Vue
<!-- Copyright 2023 OpenObserve Inc.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
-->
|
|
<template>
|
|
<div
|
|
v-if="variablesData.values?.length > 0"
|
|
:key="variablesData.isVariablesLoading"
|
|
class="flex q-mt-xs q-ml-xs"
|
|
>
|
|
<div
|
|
v-for="(item, index) in variablesData.values"
|
|
:key="
|
|
item.name +
|
|
item.value +
|
|
item.type +
|
|
item.options?.length +
|
|
item.isLoading +
|
|
item.isVariableLoadingPending +
|
|
index
|
|
"
|
|
:data-test="`dashboard-variable-${item}-selector`"
|
|
>
|
|
<div v-if="item.type == 'query_values'">
|
|
<VariableQueryValueSelector
|
|
class="q-mr-lg q-mt-xs"
|
|
v-show="!item.hideOnDashboard"
|
|
v-model="item.value"
|
|
:variableItem="item"
|
|
@update:model-value="onVariablesValueUpdated(index)"
|
|
/>
|
|
</div>
|
|
<div v-else-if="item.type == 'constant'">
|
|
<q-input
|
|
v-show="!item.hideOnDashboard"
|
|
class="q-mr-lg q-mt-xs"
|
|
style="max-width: 150px !important"
|
|
v-model="item.value"
|
|
:label="item.label || item.name"
|
|
dense
|
|
outlined
|
|
readonly
|
|
data-test="dashboard-variable-constant-selector"
|
|
@update:model-value="onVariablesValueUpdated(index)"
|
|
></q-input>
|
|
</div>
|
|
<div v-else-if="item.type == 'textbox'">
|
|
<q-input
|
|
v-show="!item.hideOnDashboard"
|
|
class="q-mr-lg q-mt-xs"
|
|
style="max-width: 150px !important"
|
|
debounce="1000"
|
|
v-model="item.value"
|
|
:label="item.label || item.name"
|
|
dense
|
|
outlined
|
|
data-test="dashboard-variable-textbox-selector"
|
|
@update:model-value="onVariablesValueUpdated(index)"
|
|
></q-input>
|
|
</div>
|
|
<div v-else-if="item.type == 'custom'">
|
|
<VariableCustomValueSelector
|
|
v-show="!item.hideOnDashboard"
|
|
class="q-mr-lg q-mt-xs"
|
|
v-model="item.value"
|
|
:variableItem="item"
|
|
@update:model-value="onVariablesValueUpdated(index)"
|
|
/>
|
|
</div>
|
|
<div v-else-if="item.type == 'dynamic_filters'">
|
|
<VariableAdHocValueSelector
|
|
class="q-mr-lg q-mt-xs"
|
|
v-model="item.value"
|
|
:variableItem="item"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { getCurrentInstance, onMounted, watch } from "vue";
|
|
import { defineComponent, reactive } from "vue";
|
|
import streamService from "../../services/stream";
|
|
import { useStore } from "vuex";
|
|
import VariableQueryValueSelector from "./settings/VariableQueryValueSelector.vue";
|
|
import VariableCustomValueSelector from "./settings/VariableCustomValueSelector.vue";
|
|
import VariableAdHocValueSelector from "./settings/VariableAdHocValueSelector.vue";
|
|
import { isInvalidDate } from "@/utils/date";
|
|
import { addLabelsToSQlQuery } from "@/utils/query/sqlUtils";
|
|
import { b64EncodeUnicode, escapeSingleQuotes } from "@/utils/zincutils";
|
|
import { buildVariablesDependencyGraph } from "@/utils/dashboard/variables/variablesDependencyUtils";
|
|
|
|
export default defineComponent({
|
|
name: "VariablesValueSelector",
|
|
props: [
|
|
"selectedTimeDate",
|
|
"variablesConfig",
|
|
"initialVariableValues",
|
|
"showDynamicFilters",
|
|
],
|
|
emits: ["variablesData"],
|
|
components: {
|
|
VariableQueryValueSelector,
|
|
VariableAdHocValueSelector,
|
|
VariableCustomValueSelector,
|
|
},
|
|
setup(props: any, { emit }) {
|
|
const instance = getCurrentInstance();
|
|
const store = useStore();
|
|
// variables data derived from the variables config list
|
|
const variablesData: any = reactive({
|
|
isVariablesLoading: false,
|
|
values: [],
|
|
});
|
|
// variables dependency graph
|
|
let variablesDependencyGraph: any = {};
|
|
|
|
// track old variables data
|
|
const oldVariablesData: any = {};
|
|
|
|
// currently executing promise
|
|
// obj will have variable name as key
|
|
// and reject object of promise as value
|
|
const currentlyExecutingPromises: any = {};
|
|
|
|
// reset variables data
|
|
// it will executed once on mount
|
|
const resetVariablesData = () => {
|
|
variablesData.isVariablesLoading = false;
|
|
variablesData.values = [];
|
|
};
|
|
|
|
const initializeVariablesData = () => {
|
|
// reset the values
|
|
resetVariablesData();
|
|
|
|
// check if variables config list is not empty
|
|
if (!props?.variablesConfig) return;
|
|
|
|
// make list of variables using variables config list
|
|
// set initial variables values from props
|
|
props?.variablesConfig?.list?.forEach((item: any) => {
|
|
let initialValue =
|
|
item.type == "dynamic_filters"
|
|
? JSON.parse(
|
|
decodeURIComponent(
|
|
// if initial value is not exist, use the default value : %5B%5D(which is [] in base64)
|
|
props.initialVariableValues?.value[item.name] ?? "%5B%5D"
|
|
)
|
|
) ?? []
|
|
: props.initialVariableValues?.value[item.name] ?? null;
|
|
|
|
if (item.multiSelect) {
|
|
initialValue = Array.isArray(initialValue)
|
|
? initialValue
|
|
: [initialValue];
|
|
}
|
|
const variableData = {
|
|
...item,
|
|
// isLoading is used to check that currently, if the variable is loading(it is used to show the loading icon)
|
|
isLoading: false,
|
|
// isVariableLoadingPending is used to check that variable loading is pending
|
|
// if parent variable is not loaded or it's value is changed, isVariableLoadingPending will be true
|
|
isVariableLoadingPending: true,
|
|
};
|
|
// need to use initial value
|
|
// also, constant type variable should not be updated
|
|
if (item.type != "constant") {
|
|
// for textbox type variable, if initial value is not exist, use the default value
|
|
if (item.type == "textbox") {
|
|
variableData.value = initialValue ?? variableData.value;
|
|
} else {
|
|
// use the initial value
|
|
variableData.value = initialValue;
|
|
}
|
|
}
|
|
|
|
// push the variable to the list
|
|
variablesData.values.push(variableData);
|
|
|
|
// set old variables data
|
|
oldVariablesData[item.name] = initialValue;
|
|
});
|
|
|
|
// if showDynamicFilters is true, add the Dynamic filters variable
|
|
if (props.showDynamicFilters) {
|
|
// get the initial value
|
|
// need to decode the initial value from base64
|
|
const initialValue =
|
|
JSON.parse(
|
|
decodeURIComponent(
|
|
// if initial value is not exist, use the default value : %5B%5D(which is [] in base64)
|
|
props.initialVariableValues?.value["Dynamic filters"] ?? "%5B%5D"
|
|
)
|
|
) ?? [];
|
|
|
|
// push the variable to the list
|
|
variablesData.values.push({
|
|
name: "Dynamic filters",
|
|
type: "dynamic_filters",
|
|
label: "Dynamic filters",
|
|
value: initialValue,
|
|
isLoading: false,
|
|
isVariableLoadingPending: true,
|
|
options: [],
|
|
});
|
|
|
|
// set old variables data
|
|
oldVariablesData["Dynamic filters"] = initialValue;
|
|
}
|
|
|
|
// need to build variables dependency graph on variables config list change
|
|
variablesDependencyGraph = buildVariablesDependencyGraph(
|
|
variablesData.values
|
|
);
|
|
};
|
|
|
|
const rejectAllPromises = () => {
|
|
Object.keys(currentlyExecutingPromises).forEach((key) => {
|
|
if (currentlyExecutingPromises[key])
|
|
currentlyExecutingPromises[key](false);
|
|
});
|
|
};
|
|
|
|
onMounted(() => {
|
|
// make list of variables using variables config list
|
|
initializeVariablesData();
|
|
|
|
// reject all promises
|
|
rejectAllPromises();
|
|
|
|
// load all variables
|
|
loadAllVariablesData();
|
|
});
|
|
|
|
watch(
|
|
() => props.variablesConfig,
|
|
async () => {
|
|
// make list of variables using variables config list
|
|
initializeVariablesData();
|
|
|
|
// reject all promises
|
|
rejectAllPromises();
|
|
|
|
// load all variables
|
|
loadAllVariablesData();
|
|
}
|
|
);
|
|
|
|
// you may need to query the data if the variable configs or the data/time changes
|
|
watch(
|
|
() => props.selectedTimeDate,
|
|
() => {
|
|
// reject all promises
|
|
rejectAllPromises();
|
|
|
|
loadAllVariablesData();
|
|
}
|
|
);
|
|
watch(
|
|
() => variablesData,
|
|
() => {
|
|
emitVariablesData();
|
|
},
|
|
{ deep: true }
|
|
);
|
|
|
|
const emitVariablesData = () => {
|
|
instance?.proxy?.$forceUpdate();
|
|
emit("variablesData", JSON.parse(JSON.stringify(variablesData)));
|
|
};
|
|
|
|
// it is used to change/update initial variables values from outside the component
|
|
// NOTE: right now, it is not used after variables in variables feature
|
|
const changeInitialVariableValues = async (
|
|
newInitialVariableValues: any
|
|
) => {
|
|
// reject all promises
|
|
rejectAllPromises();
|
|
|
|
// NOTE: need to re-initialize variables data
|
|
resetVariablesData();
|
|
|
|
// set initial variables values
|
|
props.initialVariableValues.value = newInitialVariableValues;
|
|
|
|
// make list of variables using variables config list
|
|
initializeVariablesData();
|
|
|
|
// load all variables
|
|
loadAllVariablesData();
|
|
};
|
|
const handleQueryValuesLogic = (
|
|
currentVariable: any,
|
|
oldVariableSelectedValues: any[]
|
|
) => {
|
|
// Pre-calculate the options values array
|
|
const optionsValues =
|
|
currentVariable.options.map((option: any) => option.value) ?? [];
|
|
|
|
// if multi select
|
|
if (currentVariable.multiSelect) {
|
|
// old selected values
|
|
const selectedValues = currentVariable.options
|
|
.filter((option: any) =>
|
|
oldVariableSelectedValues.includes(option.value)
|
|
)
|
|
.map((option: any) => option.value);
|
|
|
|
// if selected values exist, select the values
|
|
if (selectedValues.length > 0) {
|
|
currentVariable.value = selectedValues;
|
|
} else {
|
|
//here, multiselect and old values will be not exist
|
|
|
|
switch (currentVariable?.selectAllValueForMultiSelect) {
|
|
case "custom":
|
|
currentVariable.value = optionsValues.filter((value: any) =>
|
|
currentVariable?.customMultiSelectValue.includes(value)
|
|
);
|
|
break;
|
|
case "all":
|
|
currentVariable.value = optionsValues;
|
|
break;
|
|
default:
|
|
currentVariable.value = [currentVariable.options[0].value];
|
|
}
|
|
}
|
|
} else {
|
|
// here, multi select is false
|
|
|
|
// old selected value
|
|
const oldValue = currentVariable.options.find(
|
|
(option: any) => option.value === oldVariableSelectedValues[0]
|
|
)?.value;
|
|
|
|
// if old value exist, select the old value
|
|
if (oldValue) {
|
|
currentVariable.value = oldValue;
|
|
} else if (currentVariable.options.length > 0) {
|
|
// here, multi select is false and old value not exist
|
|
|
|
if (currentVariable.selectAllValueForMultiSelect === "custom") {
|
|
const customValue = currentVariable.options.find(
|
|
(variableOption: any) =>
|
|
variableOption.value ===
|
|
currentVariable.customMultiSelectValue[0]
|
|
);
|
|
|
|
// customValue can be undefined or default value
|
|
currentVariable.value =
|
|
customValue?.value ?? currentVariable.options[0].value;
|
|
} else {
|
|
currentVariable.value = currentVariable.options[0].value;
|
|
}
|
|
} else {
|
|
currentVariable.value = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleCustomVariablesLogic = (
|
|
currentVariable: any,
|
|
oldVariableSelectedValues: any[]
|
|
) => {
|
|
// Pre-calculate the selected options values array
|
|
const selectedOptionsValues =
|
|
currentVariable.options
|
|
.filter((option: any) => option.selected)
|
|
.map((option: any) => option.value) ?? [];
|
|
|
|
// if multi select
|
|
if (currentVariable.multiSelect) {
|
|
// old selected values
|
|
const selectedValues = currentVariable.options
|
|
.filter((option: any) =>
|
|
oldVariableSelectedValues.includes(option.value)
|
|
)
|
|
.map((option: any) => option.value);
|
|
|
|
// if old selected values exist, select the values
|
|
if (selectedValues.length > 0) {
|
|
currentVariable.value = selectedValues;
|
|
} else {
|
|
// here, multiselect is true and old values will be not exist
|
|
|
|
// if custom value is not defined, select the first option
|
|
currentVariable.value =
|
|
selectedOptionsValues.length > 0
|
|
? selectedOptionsValues
|
|
: [currentVariable?.options?.[0]?.value];
|
|
}
|
|
} else {
|
|
// here, multi select is false
|
|
|
|
// old selected value
|
|
const oldValue = currentVariable.options.find(
|
|
(option: any) => option.value === oldVariableSelectedValues[0]
|
|
)?.value;
|
|
|
|
// if old value exist, select the old value
|
|
if (oldValue) {
|
|
currentVariable.value = oldValue;
|
|
} else if (currentVariable.options.length > 0) {
|
|
// here, multi select is false and old value not exist
|
|
|
|
// if custom value is not defined, select the first option
|
|
currentVariable.value =
|
|
selectedOptionsValues.length > 0
|
|
? selectedOptionsValues[0]
|
|
: currentVariable.options[0].value;
|
|
} else {
|
|
currentVariable.value = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
// get single variable data based on index
|
|
const loadSingleVariableDataByIndex = async (variableIndex: number) => {
|
|
return new Promise(async (resolve, reject) => {
|
|
// if variableIndex is not valid, return
|
|
if (variableIndex < 0) resolve(false);
|
|
|
|
// variables data
|
|
const currentVariable = variablesData.values[variableIndex];
|
|
|
|
// if currentVariable is undefined, return
|
|
if (!currentVariable) {
|
|
return resolve(false);
|
|
}
|
|
|
|
// assign current promise reject object to currentlyExecutingPromises object
|
|
if (currentlyExecutingPromises[currentVariable.name]) {
|
|
// if the variable is already loading, reject that promise
|
|
currentlyExecutingPromises[currentVariable.name](false);
|
|
}
|
|
// assign current promise reject object to currentlyExecutingPromises object
|
|
currentlyExecutingPromises[currentVariable.name] = reject;
|
|
|
|
// need to load the current variable
|
|
if (currentVariable.isVariableLoadingPending == false) {
|
|
return resolve(false);
|
|
}
|
|
|
|
if (
|
|
isInvalidDate(props.selectedTimeDate?.start_time) ||
|
|
isInvalidDate(props.selectedTimeDate?.end_time)
|
|
) {
|
|
return resolve(false);
|
|
}
|
|
|
|
// check if all dependencies are loaded
|
|
const isAnyDepndentVariableLoadingPending = variablesDependencyGraph[
|
|
currentVariable.name
|
|
].parentVariables.find((parentVariable: any) => {
|
|
// get whole parent variable object from parent variable name
|
|
const variableData = variablesData?.values?.find(
|
|
(variable: any) => variable?.name == parentVariable
|
|
);
|
|
|
|
// if parentVariable is not loaded, return
|
|
return (
|
|
variableData?.isLoading || variableData?.isVariableLoadingPending
|
|
);
|
|
});
|
|
|
|
// if any dependent variable is loading, return
|
|
if (isAnyDepndentVariableLoadingPending) {
|
|
return resolve(false);
|
|
}
|
|
|
|
switch (currentVariable.type) {
|
|
case "query_values": {
|
|
try {
|
|
// set loading as true
|
|
currentVariable.isLoading = true;
|
|
|
|
const filterConditions =
|
|
currentVariable?.query_data?.filter ?? [];
|
|
let dummyQuery = `SELECT ${
|
|
store.state.zoConfig.timestamp_column || "_timestamp"
|
|
} FROM '${currentVariable?.query_data?.stream}'`;
|
|
const constructedFilter = filterConditions.map(
|
|
(condition: any) => ({
|
|
name: condition.name,
|
|
operator: condition.operator,
|
|
value: condition.value,
|
|
})
|
|
);
|
|
let queryContext = await addLabelsToSQlQuery(
|
|
dummyQuery,
|
|
constructedFilter
|
|
);
|
|
// replace variables placeholders
|
|
// NOTE: must use for of loop because we have return statement in the loop
|
|
for (let variable of variablesData?.values) {
|
|
// if variable is loaded
|
|
if (
|
|
variable.isLoading === false &&
|
|
variable.isVariableLoadingPending === false
|
|
) {
|
|
// replace it's value in the query if it is dependent on query context
|
|
|
|
if (Array.isArray(variable.value)) {
|
|
const arrayValues = variable.value
|
|
.map((value: any) => {
|
|
return `'${escapeSingleQuotes(value)}'`;
|
|
})
|
|
.join(", ");
|
|
|
|
queryContext = queryContext.replace(
|
|
`'$${variable.name}'`,
|
|
`${arrayValues}`
|
|
);
|
|
} else {
|
|
queryContext = queryContext.replace(
|
|
`$${variable.name}`,
|
|
variable.value
|
|
);
|
|
}
|
|
}
|
|
// above condition not matched, means variable is not loaded
|
|
// so, check if it is dependent on query context
|
|
else if (queryContext.includes(`$${variable.name}`)) {
|
|
// mark isLoading as false
|
|
currentVariable.isLoading = false;
|
|
currentVariable.isVariableLoadingPending = true;
|
|
resolve(false);
|
|
}
|
|
}
|
|
|
|
// base64 encode the query
|
|
queryContext = b64EncodeUnicode(queryContext) || "";
|
|
const res = await streamService.fieldValues({
|
|
org_identifier: store.state.selectedOrganization.identifier,
|
|
stream_name: currentVariable.query_data.stream,
|
|
start_time: new Date(
|
|
props.selectedTimeDate?.start_time?.toISOString()
|
|
).getTime(),
|
|
end_time: new Date(
|
|
props.selectedTimeDate?.end_time?.toISOString()
|
|
).getTime(),
|
|
fields: [currentVariable.query_data.field],
|
|
size: currentVariable?.query_data?.max_record_size
|
|
? currentVariable?.query_data?.max_record_size
|
|
: 10,
|
|
type: currentVariable.query_data.stream_type,
|
|
query_context: queryContext,
|
|
no_count: true,
|
|
});
|
|
|
|
if (res.data.hits.length) {
|
|
//set options value from the api response
|
|
currentVariable.options = res.data.hits
|
|
.find(
|
|
(field: any) =>
|
|
field.field === currentVariable.query_data.field
|
|
)
|
|
.values.filter(
|
|
(value: any) => value.zo_sql_key || value.zo_sql_key === ""
|
|
)
|
|
.map((value: any) => ({
|
|
label:
|
|
value.zo_sql_key !== ""
|
|
? value.zo_sql_key.toString()
|
|
: "<blank>",
|
|
value: value.zo_sql_key.toString(),
|
|
}));
|
|
|
|
// Define oldVariableSelectedValues array
|
|
let oldVariableSelectedValues: any = [];
|
|
if (oldVariablesData[currentVariable.name]) {
|
|
oldVariableSelectedValues = Array.isArray(
|
|
oldVariablesData[currentVariable.name]
|
|
)
|
|
? oldVariablesData[currentVariable.name]
|
|
: [oldVariablesData[currentVariable.name]];
|
|
}
|
|
|
|
// if the old value exists in the dropdown, set the old value; otherwise, set the first value of the dropdown; otherwise, set a blank string value
|
|
if (
|
|
oldVariablesData[currentVariable.name] !== undefined ||
|
|
oldVariablesData[currentVariable.name] !== null
|
|
) {
|
|
if (currentVariable.type === "custom") {
|
|
handleCustomVariablesLogic(
|
|
currentVariable,
|
|
oldVariableSelectedValues
|
|
);
|
|
} else {
|
|
handleQueryValuesLogic(
|
|
currentVariable,
|
|
oldVariableSelectedValues
|
|
);
|
|
}
|
|
} else {
|
|
currentVariable.value = currentVariable.options.length
|
|
? currentVariable.options[0].value
|
|
: null;
|
|
}
|
|
|
|
resolve(true);
|
|
break;
|
|
} else {
|
|
// no response hits found
|
|
// set value as empty string
|
|
currentVariable.value = currentVariable.multiSelect ? [] : null;
|
|
// set options as empty array
|
|
currentVariable.options = [];
|
|
|
|
resolve(true);
|
|
break;
|
|
}
|
|
} catch (err: any) {
|
|
// some error occurred
|
|
// set value as empty string
|
|
currentVariable.value = null;
|
|
// set options as empty array
|
|
currentVariable.options = [];
|
|
|
|
resolve(true);
|
|
break;
|
|
}
|
|
}
|
|
case "constant": {
|
|
resolve(true);
|
|
break;
|
|
}
|
|
case "textbox": {
|
|
resolve(true);
|
|
break;
|
|
}
|
|
case "custom": {
|
|
currentVariable.options = currentVariable?.options;
|
|
|
|
// Check if the old value exists and set it
|
|
let oldVariableSelectedValues: any = [];
|
|
if (oldVariablesData[currentVariable.name]) {
|
|
oldVariableSelectedValues = Array.isArray(
|
|
oldVariablesData[currentVariable.name]
|
|
)
|
|
? oldVariablesData[currentVariable.name]
|
|
: [oldVariablesData[currentVariable.name]];
|
|
}
|
|
|
|
// If multiSelect is true, set the value as an array containing old value and selected value
|
|
if (currentVariable.type === "custom") {
|
|
handleCustomVariablesLogic(
|
|
currentVariable,
|
|
oldVariableSelectedValues
|
|
);
|
|
} else {
|
|
handleQueryValuesLogic(
|
|
currentVariable,
|
|
oldVariableSelectedValues
|
|
);
|
|
}
|
|
resolve(true);
|
|
break;
|
|
}
|
|
case "dynamic_filters": {
|
|
resolve(true);
|
|
break;
|
|
}
|
|
default:
|
|
resolve(true);
|
|
break;
|
|
}
|
|
|
|
resolve(true);
|
|
})
|
|
.then((res) => {
|
|
if (res) {
|
|
// if (!res) return;
|
|
// if variableIndex is not valid, return
|
|
if (variableIndex < 0) return;
|
|
// variables data
|
|
const currentVariable = variablesData.values[variableIndex];
|
|
// if currentVariable is undefined, return
|
|
if (!currentVariable) {
|
|
return;
|
|
}
|
|
|
|
// remove the current promise from currentlyExecutingPromises
|
|
currentlyExecutingPromises[currentVariable.name] = null;
|
|
|
|
// set old variables data
|
|
oldVariablesData[currentVariable.name] = currentVariable.value;
|
|
|
|
// mark current variable as loaded
|
|
currentVariable.isLoading = false;
|
|
currentVariable.isVariableLoadingPending = false;
|
|
|
|
// check all variables are loaded?
|
|
// if all variables are loaded, set isVariablesLoading to false
|
|
variablesData.isVariablesLoading = variablesData.values.some(
|
|
(val: { isLoading: any; isVariableLoadingPending: any }) =>
|
|
val.isLoading || val.isVariableLoadingPending
|
|
);
|
|
|
|
// now, load all it's child variables
|
|
const childVariableIndices = variablesData.values.reduce(
|
|
(indices: number[], variable: any, index: number) => {
|
|
if (
|
|
variablesDependencyGraph[
|
|
currentVariable.name
|
|
].childVariables.includes(variable.name)
|
|
) {
|
|
indices.push(index);
|
|
}
|
|
return indices;
|
|
},
|
|
[]
|
|
);
|
|
|
|
// will force update the variables data
|
|
emitVariablesData();
|
|
|
|
Promise.all(
|
|
childVariableIndices.map((childIndex: number) =>
|
|
loadSingleVariableDataByIndex(childIndex)
|
|
)
|
|
);
|
|
}
|
|
})
|
|
.catch((res) => {
|
|
// if (!res) return;
|
|
// if variableIndex is not valid, return
|
|
if (variableIndex < 0) return;
|
|
// variables data
|
|
const currentVariable = variablesData.values[variableIndex];
|
|
// if currentVariable is undefined, return
|
|
if (!currentVariable) {
|
|
return;
|
|
}
|
|
|
|
// remove the current promise from currentlyExecutingPromises
|
|
currentlyExecutingPromises[currentVariable.name] = null;
|
|
|
|
// set isLoading as false
|
|
currentVariable.isLoading = false;
|
|
});
|
|
};
|
|
|
|
const loadAllVariablesData = async () => {
|
|
if (
|
|
isInvalidDate(props.selectedTimeDate?.start_time) ||
|
|
isInvalidDate(props.selectedTimeDate?.end_time)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
// set isVariableLoadingPending as true for all variables
|
|
variablesData.values.forEach((variable: any) => {
|
|
variable.isVariableLoadingPending = true;
|
|
});
|
|
|
|
Promise.all(
|
|
variablesData.values.map((it: any, index: number) =>
|
|
loadSingleVariableDataByIndex(index)
|
|
)
|
|
);
|
|
};
|
|
|
|
const setLoadingStateToAllChildNode = (currentVariable: string) => {
|
|
for (const variableName of variablesDependencyGraph[currentVariable]
|
|
.childVariables) {
|
|
const variableObj = variablesData.values.find(
|
|
(it: any) => it.name === variableName
|
|
);
|
|
variableObj.isVariableLoadingPending = true;
|
|
setLoadingStateToAllChildNode(variableObj.name);
|
|
}
|
|
};
|
|
|
|
const onVariablesValueUpdated = (variableIndex: number) => {
|
|
// if variableIndex is not valid, return
|
|
if (variableIndex < 0) return;
|
|
// variables data
|
|
const currentVariable = variablesData.values[variableIndex];
|
|
// if currentVariable is undefined, return
|
|
if (!currentVariable) {
|
|
return;
|
|
}
|
|
|
|
// currentVariable value changed.
|
|
// so, set it to oldVariablesData
|
|
oldVariablesData[currentVariable.name] = currentVariable.value;
|
|
|
|
// set all child variables to loading state
|
|
setLoadingStateToAllChildNode(currentVariable.name);
|
|
|
|
Promise.all(
|
|
variablesData.values.map((it: any, index: number) =>
|
|
loadSingleVariableDataByIndex(index)
|
|
)
|
|
);
|
|
};
|
|
|
|
return {
|
|
props,
|
|
variablesData,
|
|
changeInitialVariableValues,
|
|
onVariablesValueUpdated,
|
|
};
|
|
},
|
|
});
|
|
</script>
|