251 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Парус 8 - Панели мониторинга - Редакторы панелей
Компонент: Редактор действия
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useState, useEffect } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { TextField, Select, Menu, MenuItem, FormControl, InputLabel, Stack, Box } from "@mui/material"; //Интерфейсные элементы
import { TITLES } from "../../../../app.text"; //Общие текстовые ресурсы
import { P8PConfigDialog } from "../p8p_config_dialog"; //Диалог настройки
import { deepCopyObject } from "../../../core/utils"; //Вспомогательные функции
import { P8P_CA_DEF_VALUE_TYPES, P8P_CA_TYPE, P8P_CA_SHAPE, P8P_CA_INPUT_PARAM_INITIAL, P8P_CA_OPEN_UNIT_INITIAL, P8P_CA_INITIAL } from "./common"; //Общие ресурсы действий
import { P8PCAUnitOpenOptions } from "./config_unit_open"; //Компонент редактора действия "Открыть раздел"
import { P8PCAPanelOpenOptions } from "./config_panel_open"; //Компонент редактора действия "Открыть панель"
import { P8PCAVarSetOptions } from "./config_var_set"; //Компонент редактора действия "Установить переменную"
import { isActionOkDisabled, getActionTypeParams } from "./util"; //Вспомогательные ресурсы действий
//---------
//Константы
//---------
//Стили
const STYLES = {
CONTAINER: { display: "flex", flexDirection: "column", gap: "10px", minWidth: "300px" }
};
//-----------
//Тело модуля
//-----------
//Редактор действия
const P8PCAEditor = ({ areas = [], valueTypes = [], action = null, onOk = null, onCancel = null, valueProviders = {} }) => {
//Собственное состояние - признак инициализиации
const [init, setInit] = useState(true);
//Собственное состояние - параметры действия
const [state, setState] = useState({});
//Собственное состояние - доступные типы значений компонента
const [availableValueTypes, setAvailableValueTypes] = useState([]);
//Собственное состояние - доступные области компонента
const [availableAreas, setAvailableAreas] = useState([]);
//Собственное состояние - доступность поля "Элемент"
const [hasElement, setHasElement] = useState(false);
//Собственное состояние - элемент привязки меню выбора источника
const [valueProvidersMenuAnchorEl, setValueProvidersMenuAnchorEl] = useState({
target: null,
onChange: null
});
//Открытие/сокрытие меню выбора источника
const toggleValueProvidersMenu = (target, onChange) =>
setValueProvidersMenuAnchorEl(target instanceof Element ? { target, onChange } : { target: null, onChange: null });
//При отображении меню связывания значения с поставщиком данных
const handleValueSourceLinkMenuClick = (e, onChange) => setValueProvidersMenuAnchorEl({ target: e.currentTarget, onChange });
//При закрытии редактора с сохранением
const handleOk = () => onOk && onOk({ ...state });
//При закрытии редактора с отменой
const handleCancel = () => onCancel && onCancel();
//При изменении типа действия
const handleTypeChange = e => {
//Иницилизируем параметры типа
let newParams = getActionTypeParams(e.target.value);
//Изменяем тип действия с изменение структуры параметров
setState(pv => ({
...pv,
type: e.target.value,
params: Array.isArray(newParams) ? [...newParams] : { ...newParams }
}));
};
//При ручном изменении общего параметра действия
const handleChange = e => setState(pv => ({ ...pv, [e.target.name]: e.target.value }));
//При изменении области действия
const handleAreaChange = e => {
//Устанавливаем значение
setState(pv => ({ ...pv, [e.target.name]: e.target.value, name: "" }));
//Устанавливаем доступность "Элемент"
setHasElement(availableAreas.find(item => item.area === e.target.value).hasElement);
};
//При изменении полей параметров действия
const handleParamsChange = params => {
setState(pv => ({ ...pv, params: { ...pv.params, ...params } }));
};
//При изменении переменных параметров действия "Установить переменную"
const handleVariablesParamsChange = variables => {
setState(pv => ({ ...pv, params: [...variables] }));
};
//Список значений
const values = Object.keys(valueProviders);
//Наличие значений
const isValues = values && values.length > 0 ? true : false;
//Меню привязки к поставщикам значений
const valueProvidersMenu = isValues && (
<Menu anchorEl={valueProvidersMenuAnchorEl.target} open={Boolean(valueProvidersMenuAnchorEl.target)} onClose={toggleValueProvidersMenu}>
{values.map((value, i) => (
<MenuItem
key={i}
onClick={() => {
//Выполняем выбор параметра
valueProvidersMenuAnchorEl.onChange(value);
//Закрываем меню выбора переменной
toggleValueProvidersMenu();
}}
>
{value}
</MenuItem>
))}
</Menu>
);
//При инициализации действия
useEffect(() => {
//Если это иницализация
if (init) {
//Если это открытие действия - берем его параметры, иначе - инициализируем изначальными
const initAction = action
? action
: {
...P8P_CA_INITIAL,
area: areas[0].area,
params: { ...P8P_CA_OPEN_UNIT_INITIAL, inputParams: [{ ...P8P_CA_INPUT_PARAM_INITIAL }] }
};
//Устанавливаем параметры действия
setState(deepCopyObject(initAction));
//Заполняем доступные области
setAvailableAreas([...areas]);
//Определяем доступность "Элемент"
setHasElement(areas.find(item => item.area === initAction.area)?.hasElement || false);
//Заполняем доступные типы значений
setAvailableValueTypes([...P8P_CA_DEF_VALUE_TYPES, ...valueTypes]);
//Сбрасываем признак инициализации
setInit(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [init]);
//Формирование представления
return (
<>
{!init ? (
<P8PConfigDialog
title={`${action ? TITLES.UPDATE : TITLES.INSERT} действия`}
onOk={handleOk}
onCancel={handleCancel}
width={"xl"}
okDisabled={isActionOkDisabled(state)}
>
<Stack direction={"column"} spacing={1}>
{valueProvidersMenu}
<Box sx={STYLES.CONTAINER}>
{availableAreas.length !== 0 ? (
<FormControl variant={"standard"} fullWidth>
<InputLabel id={"areaLabel-label"}>Область</InputLabel>
<Select name={"area"} value={state.area} labelId={"area-label"} label={"Область"} onChange={handleAreaChange}>
{availableAreas.map((item, index) => (
<MenuItem value={item.area} key={index}>
{item.name}
</MenuItem>
))}
</Select>
</FormControl>
) : null}
{hasElement && (
<TextField
type={"text"}
variant={"standard"}
value={state.element}
label={"Элемент"}
name={"element"}
onChange={handleChange}
/>
)}
<FormControl variant={"standard"} fullWidth>
<InputLabel id={"type-label"}>Тип</InputLabel>
<Select name={"type"} value={state.type} labelId={"type-label"} label={"Тип"} onChange={handleTypeChange}>
{Object.keys(P8P_CA_TYPE).map((item, index) => (
<MenuItem value={P8P_CA_TYPE[item].code} key={index}>
{P8P_CA_TYPE[item].name}
</MenuItem>
))}
</Select>
</FormControl>
</Box>
{state.type === P8P_CA_TYPE.openUnit.code && (
<P8PCAUnitOpenOptions
unit={state.params}
valueTypes={availableValueTypes}
isValues={isValues}
onStateChange={handleParamsChange}
onValueSourceMenuClick={handleValueSourceLinkMenuClick}
/>
)}
{state.type === P8P_CA_TYPE.openPanel.code && (
<P8PCAPanelOpenOptions
panel={state.params}
valueTypes={availableValueTypes}
isValues={isValues}
onStateChange={handleParamsChange}
onValueSourceMenuClick={handleValueSourceLinkMenuClick}
/>
)}
{state.type === P8P_CA_TYPE.setVariable.code && (
<P8PCAVarSetOptions
variables={state.params}
valueTypes={availableValueTypes}
isValues={isValues}
onStateChange={handleVariablesParamsChange}
onValueSourceMenuClick={handleValueSourceLinkMenuClick}
/>
)}
</Stack>
</P8PConfigDialog>
) : null}
</>
);
};
//Контроль свойств - Редактор условия
P8PCAEditor.propTypes = {
areas: PropTypes.array,
valueTypes: PropTypes.array,
action: P8P_CA_SHAPE,
onOk: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
valueProviders: PropTypes.object
};
//----------------
//Интерфейс модуля
//----------------
export { P8PCAEditor };