2022-09-09 17:43:25 +05:30
|
|
|
import { orange } from '@ant-design/colors';
|
|
|
|
|
import { WarningOutlined } from '@ant-design/icons';
|
|
|
|
|
import { Input, Popover, Select, Typography } from 'antd';
|
|
|
|
|
import query from 'api/dashboard/variables/query';
|
|
|
|
|
import { commaValuesParser } from 'lib/dashbaordVariables/customCommaValuesParser';
|
|
|
|
|
import sortValues from 'lib/dashbaordVariables/sortVariableValues';
|
|
|
|
|
import { map } from 'lodash-es';
|
|
|
|
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
|
|
|
import { IDashboardVariable } from 'types/api/dashboard/getAll';
|
|
|
|
|
|
2023-01-25 13:22:57 +05:30
|
|
|
import { variablePropsToPayloadVariables } from '../utils';
|
|
|
|
|
import { SelectItemStyle, VariableContainer, VariableName } from './styles';
|
|
|
|
|
import { areArraysEqual } from './util';
|
2022-09-09 17:43:25 +05:30
|
|
|
|
|
|
|
|
const { Option } = Select;
|
|
|
|
|
|
|
|
|
|
const ALL_SELECT_VALUE = '__ALL__';
|
|
|
|
|
|
|
|
|
|
interface VariableItemProps {
|
|
|
|
|
variableData: IDashboardVariable;
|
2023-01-25 13:22:57 +05:30
|
|
|
existingVariables: Record<string, IDashboardVariable>;
|
|
|
|
|
onValueUpdate: (
|
|
|
|
|
name: string | undefined,
|
|
|
|
|
arg1:
|
|
|
|
|
| string
|
|
|
|
|
| number
|
|
|
|
|
| boolean
|
|
|
|
|
| (string | number | boolean)[]
|
|
|
|
|
| null
|
|
|
|
|
| undefined,
|
|
|
|
|
) => void;
|
2022-09-09 17:43:25 +05:30
|
|
|
onAllSelectedUpdate: (name: string | undefined, arg1: boolean) => void;
|
2023-01-25 13:22:57 +05:30
|
|
|
lastUpdatedVar: string;
|
2022-09-09 17:43:25 +05:30
|
|
|
}
|
|
|
|
|
function VariableItem({
|
|
|
|
|
variableData,
|
2023-01-25 13:22:57 +05:30
|
|
|
existingVariables,
|
2022-09-09 17:43:25 +05:30
|
|
|
onValueUpdate,
|
|
|
|
|
onAllSelectedUpdate,
|
2023-01-25 13:22:57 +05:30
|
|
|
lastUpdatedVar,
|
2022-09-09 17:43:25 +05:30
|
|
|
}: VariableItemProps): JSX.Element {
|
2023-01-25 13:22:57 +05:30
|
|
|
const [optionsData, setOptionsData] = useState<(string | number | boolean)[]>(
|
|
|
|
|
[],
|
|
|
|
|
);
|
2022-09-09 17:43:25 +05:30
|
|
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
|
|
|
|
|
|
|
|
const [errorMessage, setErrorMessage] = useState<null | string>(null);
|
2023-01-25 13:22:57 +05:30
|
|
|
|
|
|
|
|
/* eslint-disable sonarjs/cognitive-complexity */
|
2022-09-09 17:43:25 +05:30
|
|
|
const getOptions = useCallback(async (): Promise<void> => {
|
|
|
|
|
if (variableData.type === 'QUERY') {
|
|
|
|
|
try {
|
|
|
|
|
setErrorMessage(null);
|
|
|
|
|
setIsLoading(true);
|
|
|
|
|
|
|
|
|
|
const response = await query({
|
|
|
|
|
query: variableData.queryValue || '',
|
2023-01-25 13:22:57 +05:30
|
|
|
variables: variablePropsToPayloadVariables(existingVariables),
|
2022-09-09 17:43:25 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setIsLoading(false);
|
|
|
|
|
if (response.error) {
|
2023-01-25 13:22:57 +05:30
|
|
|
let message = response.error;
|
|
|
|
|
if (response.error.includes('Syntax error:')) {
|
|
|
|
|
message =
|
|
|
|
|
'Please make sure query is valid and dependent variables are selected';
|
|
|
|
|
}
|
|
|
|
|
setErrorMessage(message);
|
2022-09-09 17:43:25 +05:30
|
|
|
return;
|
|
|
|
|
}
|
2023-01-25 13:22:57 +05:30
|
|
|
if (response.payload?.variableValues) {
|
|
|
|
|
const newOptionsData = sortValues(
|
|
|
|
|
response.payload?.variableValues,
|
|
|
|
|
variableData.sort,
|
2022-09-09 17:43:25 +05:30
|
|
|
);
|
2023-01-25 13:22:57 +05:30
|
|
|
// Since there is a chance of a variable being dependent on other
|
|
|
|
|
// variables, we need to check if the optionsData has changed
|
|
|
|
|
// If it has changed, we need to update the dependent variable
|
|
|
|
|
// So we compare the new optionsData with the old optionsData
|
|
|
|
|
const oldOptionsData = sortValues(optionsData, variableData.sort) as never;
|
|
|
|
|
if (!areArraysEqual(newOptionsData, oldOptionsData)) {
|
|
|
|
|
/* eslint-disable no-useless-escape */
|
|
|
|
|
const re = new RegExp(`\\{\\{\\s*?\\.${lastUpdatedVar}\\s*?\\}\\}`); // regex for `{{.var}}`
|
|
|
|
|
// If the variable is dependent on the last updated variable
|
|
|
|
|
// and contains the last updated variable in its query (of the form `{{.var}}`)
|
|
|
|
|
// then we need to update the value of the variable
|
|
|
|
|
const queryValue = variableData.queryValue || '';
|
|
|
|
|
const dependVarReMatch = queryValue.match(re);
|
|
|
|
|
if (
|
|
|
|
|
variableData.type === 'QUERY' &&
|
|
|
|
|
dependVarReMatch !== null &&
|
|
|
|
|
dependVarReMatch.length > 0
|
|
|
|
|
) {
|
|
|
|
|
let value = variableData.selectedValue;
|
|
|
|
|
let allSelected = false;
|
|
|
|
|
// The default value for multi-select is ALL and first value for
|
|
|
|
|
// single select
|
|
|
|
|
if (variableData.multiSelect) {
|
|
|
|
|
value = newOptionsData;
|
|
|
|
|
allSelected = true;
|
|
|
|
|
} else {
|
|
|
|
|
[value] = newOptionsData;
|
|
|
|
|
}
|
|
|
|
|
onValueUpdate(variableData.name, value);
|
|
|
|
|
onAllSelectedUpdate(variableData.name, allSelected);
|
|
|
|
|
}
|
|
|
|
|
setOptionsData(newOptionsData);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-09 17:43:25 +05:30
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
}
|
|
|
|
|
} else if (variableData.type === 'CUSTOM') {
|
|
|
|
|
setOptionsData(
|
|
|
|
|
sortValues(
|
|
|
|
|
commaValuesParser(variableData.customValue || ''),
|
|
|
|
|
variableData.sort,
|
|
|
|
|
) as never,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}, [
|
2023-01-25 13:22:57 +05:30
|
|
|
variableData,
|
|
|
|
|
existingVariables,
|
|
|
|
|
onValueUpdate,
|
|
|
|
|
onAllSelectedUpdate,
|
|
|
|
|
optionsData,
|
|
|
|
|
lastUpdatedVar,
|
2022-09-09 17:43:25 +05:30
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
getOptions();
|
|
|
|
|
}, [getOptions]);
|
|
|
|
|
|
|
|
|
|
const handleChange = (value: string | string[]): void => {
|
|
|
|
|
if (
|
|
|
|
|
value === ALL_SELECT_VALUE ||
|
2023-01-25 13:22:57 +05:30
|
|
|
(Array.isArray(value) && value.includes(ALL_SELECT_VALUE)) ||
|
|
|
|
|
(Array.isArray(value) && value.length === 0)
|
2022-09-09 17:43:25 +05:30
|
|
|
) {
|
|
|
|
|
onValueUpdate(variableData.name, optionsData);
|
|
|
|
|
onAllSelectedUpdate(variableData.name, true);
|
|
|
|
|
} else {
|
|
|
|
|
onValueUpdate(variableData.name, value);
|
|
|
|
|
onAllSelectedUpdate(variableData.name, false);
|
|
|
|
|
}
|
|
|
|
|
};
|
2023-01-25 13:22:57 +05:30
|
|
|
|
|
|
|
|
const selectValue = variableData.allSelected
|
|
|
|
|
? 'ALL'
|
|
|
|
|
: variableData.selectedValue?.toString() || '';
|
|
|
|
|
const mode =
|
|
|
|
|
variableData.multiSelect && !variableData.allSelected
|
|
|
|
|
? 'multiple'
|
|
|
|
|
: undefined;
|
|
|
|
|
const enableSelectAll = variableData.multiSelect && variableData.showALLOption;
|
2022-09-09 17:43:25 +05:30
|
|
|
return (
|
|
|
|
|
<VariableContainer>
|
|
|
|
|
<VariableName>${variableData.name}</VariableName>
|
|
|
|
|
{variableData.type === 'TEXTBOX' ? (
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="Enter value"
|
|
|
|
|
bordered={false}
|
|
|
|
|
value={variableData.selectedValue?.toString()}
|
|
|
|
|
onChange={(e): void => {
|
|
|
|
|
handleChange(e.target.value || '');
|
|
|
|
|
}}
|
|
|
|
|
style={{
|
2023-01-25 13:22:57 +05:30
|
|
|
width:
|
|
|
|
|
50 + ((variableData.selectedValue?.toString()?.length || 0) * 7 || 50),
|
2022-09-09 17:43:25 +05:30
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
2023-01-25 13:22:57 +05:30
|
|
|
!errorMessage && (
|
|
|
|
|
<Select
|
|
|
|
|
value={selectValue}
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
bordered={false}
|
|
|
|
|
placeholder="Select value"
|
|
|
|
|
mode={mode}
|
|
|
|
|
dropdownMatchSelectWidth={false}
|
|
|
|
|
style={SelectItemStyle}
|
|
|
|
|
loading={isLoading}
|
|
|
|
|
showArrow
|
|
|
|
|
>
|
|
|
|
|
{enableSelectAll && <Option value={ALL_SELECT_VALUE}>ALL</Option>}
|
|
|
|
|
{map(optionsData, (option) => (
|
|
|
|
|
<Option value={option}>{option.toString()}</Option>
|
|
|
|
|
))}
|
|
|
|
|
</Select>
|
|
|
|
|
)
|
2022-09-09 17:43:25 +05:30
|
|
|
)}
|
|
|
|
|
{errorMessage && (
|
|
|
|
|
<span style={{ margin: '0 0.5rem' }}>
|
|
|
|
|
<Popover placement="top" content={<Typography>{errorMessage}</Typography>}>
|
|
|
|
|
<WarningOutlined style={{ color: orange[5] }} />
|
|
|
|
|
</Popover>
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</VariableContainer>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default VariableItem;
|