231 lines
11 KiB
JavaScript
231 lines
11 KiB
JavaScript
/*
|
||
Парус 8 - Панели мониторинга - Редактор панелей
|
||
Редактор глобальных свойств панели
|
||
*/
|
||
|
||
//---------------------
|
||
//Подключение библиотек
|
||
//---------------------
|
||
|
||
import React, { useState, useContext } from "react"; //Классы React
|
||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||
import { Chip, Stack, TextField, Button, Icon } from "@mui/material"; //Интерфейсные элементы
|
||
import { P8PConfigDialog } from "../../components/editors/p8p_config_dialog"; //Диалог настройки
|
||
import { isElementNameCorrect } from "../../components/editors/p8p_editors_common"; //Общие ресурсы редакторов
|
||
import { P8PEditorSubHeader } from "../../components/editors/p8p_editor_sub_header"; //Заголовок раздела редактора
|
||
import { P8PEditorBox } from "../../components/editors/p8p_editor_box"; //Контейнер редактора
|
||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||
import { STYLES as COMMON_STYLES } from "../../components/editors/p8p_editors_common"; //Общие ресурсы редакторов
|
||
import { P8PChipList } from "../../components/editors/p8p_chip_list"; //Дополнительные настройки редактора
|
||
|
||
//---------
|
||
//Константы
|
||
//---------
|
||
|
||
//Стили
|
||
const STYLES = {
|
||
STACK_DEPENENCIES: { gap: "5px", ...APP_STYLES.SCROLL, overflow: "auto", maxHeight: "160px", width: "260px" },
|
||
CHIP_DEPENDENCY: { ...COMMON_STYLES.CHIP(true, false), minHeight: "32px" }
|
||
};
|
||
|
||
//Начальное состояние переменной
|
||
const VARIABLE_INITIAL = {
|
||
dependencies: [],
|
||
description: "",
|
||
value: ""
|
||
};
|
||
|
||
//Структура переменной
|
||
export const VARIABLE_SHAPE = PropTypes.shape({
|
||
dependencies: PropTypes.arrayOf(PropTypes.string),
|
||
description: PropTypes.string.isRequired,
|
||
value: PropTypes.string
|
||
});
|
||
|
||
//------------------------------------
|
||
//Вспомогательные функции и компоненты
|
||
//------------------------------------
|
||
|
||
//Редактор переменной
|
||
const VariableEditor = ({ variableName = "", variable = null, dependencies = [], onDependencyClick, onOk, onCancel } = {}) => {
|
||
//Собственное состояние - имя переменной
|
||
const [name, setName] = useState(variableName || "");
|
||
|
||
//Собственное состояние - параметры переменной
|
||
const [state, setState] = useState({ ...VARIABLE_INITIAL, ...variable });
|
||
|
||
//При закрытии редактора с сохранением
|
||
const handleOk = () => onOk(name, { ...state });
|
||
|
||
//При закрытии редактора с отменой
|
||
const handleCancel = () => onCancel();
|
||
|
||
//При изменении параметра переменной
|
||
const handleChange = e => {
|
||
//Если это поле наименования, то проверяем корректность
|
||
if (e.target.id === "name" && isElementNameCorrect(e.target.value)) setName(e.target.value);
|
||
//Устанавливаем значение
|
||
else setState(pv => ({ ...pv, [e.target.id]: e.target.value }));
|
||
};
|
||
|
||
//Доступность сохранения настроек элемента
|
||
const okDisabled = !name || !state.description ? true : false;
|
||
|
||
//Формирование представления
|
||
return (
|
||
<P8PConfigDialog title={`${variable ? "Изменение" : "Добавление"} элемента`} onOk={handleOk} onCancel={handleCancel} okDisabled={okDisabled}>
|
||
<Stack direction={"column"} spacing={1}>
|
||
<TextField type={"text"} variant={"standard"} value={name} label={"Имя"} id={"name"} onChange={handleChange} required={true} />
|
||
<TextField
|
||
type={"text"}
|
||
variant={"standard"}
|
||
value={state.description}
|
||
label={"Описание"}
|
||
id={"description"}
|
||
onChange={handleChange}
|
||
required={true}
|
||
/>
|
||
</Stack>
|
||
{dependencies.length !== 0 ? (
|
||
<>
|
||
<P8PEditorSubHeader title={"Зависимости"} />
|
||
<Stack sx={STYLES.STACK_DEPENENCIES} direction={"column"} p={1} useFlexGap={true}>
|
||
{dependencies.map((item, i) => (
|
||
<Chip
|
||
key={i}
|
||
label={item}
|
||
variant={"outlined"}
|
||
onClick={() => onDependencyClick && onDependencyClick(item)}
|
||
sx={STYLES.CHIP_DEPENDENCY}
|
||
/>
|
||
))}
|
||
</Stack>
|
||
</>
|
||
) : null}
|
||
</P8PConfigDialog>
|
||
);
|
||
};
|
||
|
||
//Контроль свойств - редактор переменной
|
||
VariableEditor.propTypes = {
|
||
variableName: PropTypes.string,
|
||
variable: VARIABLE_SHAPE,
|
||
dependencies: PropTypes.array,
|
||
onDependencyClick: PropTypes.func.isRequired,
|
||
onOk: PropTypes.func.isRequired,
|
||
onCancel: PropTypes.func.isRequired
|
||
};
|
||
|
||
//-----------
|
||
//Тело модуля
|
||
//-----------
|
||
|
||
//Редактор глобальных свойств панели
|
||
const PanelPropsEditor = ({ valueProviders = {}, onSettingsChange, onDependencyClick } = {}) => {
|
||
//Собственное состояние - редактор переменных панели
|
||
const [variableEditor, setVariableEditor] = useState({ display: false, item: null });
|
||
|
||
//Подключение к контексту сообщений
|
||
const { showMsgErr } = useContext(MessagingСtx);
|
||
|
||
//При добавлении новой переменной
|
||
const handleVariableAdd = () => setVariableEditor({ display: true, item: null });
|
||
|
||
//При нажатии на переменную
|
||
const handleVariableClick = index => setVariableEditor({ display: true, item: variables[index] });
|
||
|
||
//При отмене сохранения изменений переменной
|
||
const handleVariableCancel = () => setVariableEditor({ display: false, index: null });
|
||
|
||
//При сохранении изменений переменной
|
||
const handleVariableSave = (variableName, variable) => {
|
||
//Текст ошибки
|
||
let msgError = "";
|
||
//Если это добавление или изменилось наименование - проверяем на дублирование
|
||
if ((!variableEditor.item || variableEditor.item !== variableName) && Object.prototype.hasOwnProperty.call(valueProviders, variableName)) {
|
||
msgError = `Дублирование наименования параметра "${variableName}".`;
|
||
}
|
||
//Если это исправление наименования параметра, но он используется
|
||
if (variableEditor.item && variableEditor.item !== variableName && valueProviders[variableEditor.item].dependencies.length !== 0) {
|
||
msgError = `Переменная имеет связи с компонентами. Изменение наименования запрещено.`;
|
||
}
|
||
//Если есть ошибка - выводим
|
||
if (msgError) {
|
||
showMsgErr(msgError);
|
||
} else {
|
||
//Копируем параметры
|
||
let newValueProviders = { ...valueProviders };
|
||
//Удаляем старое значение, если требуется
|
||
variableEditor.item && variableEditor.item !== variableName ? delete newValueProviders[variableEditor.item] : null;
|
||
//Добавляем новый параметр
|
||
newValueProviders = { ...newValueProviders, [variableName]: { ...variable } };
|
||
//Обновляем проводники панели
|
||
onSettingsChange({ valueProviders: { ...newValueProviders } });
|
||
//Закрываем редактирование
|
||
setVariableEditor({ display: false, index: null });
|
||
}
|
||
};
|
||
|
||
//При удалении переменной
|
||
const handleVariableDelete = index => {
|
||
const variable = variables[index];
|
||
//Если переменная не используется в компонентах - удаляем
|
||
if (valueProviders[variable].dependencies.length === 0) {
|
||
const newValueProviders = { ...valueProviders };
|
||
delete newValueProviders[variable];
|
||
onSettingsChange({ valueProviders: { ...newValueProviders } });
|
||
} else {
|
||
showMsgErr(`Переменная имеет связи с компонентами. Удаление запрещено.`);
|
||
}
|
||
};
|
||
|
||
//При нажатии на зависимый компонент
|
||
const handleDependencyClick = id => {
|
||
//Закрываем редактирование
|
||
setVariableEditor({ display: false, index: null });
|
||
//Открываем настройку компонента
|
||
onDependencyClick(id);
|
||
};
|
||
|
||
//Текущие переменные панели
|
||
const variables = Object.keys(valueProviders).reduce((res, key) => [...res, key], []);
|
||
|
||
//Определяем структуру переменных для отображения
|
||
const variableChips = variables.map(item => ({ text: item, title: item }));
|
||
|
||
//Формирование представления
|
||
return (
|
||
<P8PEditorBox title={"Параметры панели"}>
|
||
{variableEditor.display && (
|
||
<VariableEditor
|
||
variableName={variableEditor.item}
|
||
variable={variableEditor.item !== null ? { ...valueProviders[variableEditor.item] } : null}
|
||
dependencies={variableEditor.item ? valueProviders[variableEditor.item].dependencies : []}
|
||
onDependencyClick={handleDependencyClick}
|
||
onCancel={handleVariableCancel}
|
||
onOk={handleVariableSave}
|
||
/>
|
||
)}
|
||
<P8PEditorSubHeader title={"Переменные"} />
|
||
<P8PChipList items={variableChips} onClick={handleVariableClick} onDelete={handleVariableDelete} />
|
||
<Button startIcon={<Icon>add</Icon>} onClick={handleVariableAdd}>
|
||
Добавить переменную
|
||
</Button>
|
||
</P8PEditorBox>
|
||
);
|
||
};
|
||
|
||
//Контроль свойств компонента - редактор глобальных свойств панели
|
||
PanelPropsEditor.propTypes = {
|
||
valueProviders: PropTypes.object,
|
||
onSettingsChange: PropTypes.func.isRequired,
|
||
onDependencyClick: PropTypes.func.isRequired
|
||
};
|
||
|
||
//----------------
|
||
//Интерфейс модуля
|
||
//----------------
|
||
|
||
export { PanelPropsEditor };
|