/* Парус 8 - Панели мониторинга - Редактор панелей Корневой компонент */ //--------------------- //Подключение библиотек //--------------------- import React, { useEffect, useState, useContext } from "react"; //Классы React import { Responsive, WidthProvider } from "react-grid-layout"; //Адаптивный макет import { Box, Grid, Stack, Menu, MenuItem, IconButton, Icon, Fab } from "@mui/material"; //Интерфейсные элементы import { ApplicationСtx } from "../../context/application"; //Контекст приложения import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Рабочая область приложения import { genGUID } from "../../core/utils"; //Общие вспомогательные функции import { LayoutItem } from "./layout_item"; //Элемент макета import { ComponentView } from "./component_view"; //Представление компонента панели import { ComponentEditor } from "./component_editor"; //Редактор свойств компонента панели import { COMPONETNS } from "./components/components"; //Описание доступных компонентов import "react-grid-layout/css/styles.css"; //Стили для адаптивного макета import "react-resizable/css/styles.css"; //Стили для адаптивного макета //--------- //Константы //--------- //Стили const STYLES = { CONTAINER: { display: "flex" }, GRID_CONTAINER: { height: `calc(100vh - ${APP_BAR_HEIGHT})` }, GRID_ITEM_INSPECTOR: { backgroundColor: "#e9ecef" }, FAB_EDIT: { position: "absolute", top: 12, right: 12, zIndex: 2000 } }; //Заголовоки по умолчанию const PANEL_CAPTION_EDIT_MODE = "Редактор панелей"; const PANEL_CAPTION_EXECUTE_MODE = "Исполнение панели"; //Начальное состояние размера макета const INITIAL_BREAKPOINT = "lg"; //Начальное состояние макета const INITIAL_LAYOUTS = { [INITIAL_BREAKPOINT]: [] }; //----------- //Тело модуля //----------- //Обёрдка для динамического макета const ResponsiveGridLayout = WidthProvider(Responsive); //Корневой компонент редактора панелей const PanelsEditor = () => { //Собственное состояние const [components, setComponents] = useState({}); const [valueProviders, setValueProviders] = useState({}); const [layouts, setLayouts] = useState(INITIAL_LAYOUTS); const [breakpoint, setBreakpoint] = useState(INITIAL_BREAKPOINT); const [editMode, setEditMode] = useState(true); const [editComponent, setEditComponent] = useState(null); const [addMenuAnchorEl, setAddMenuAnchorEl] = useState(null); //Подключение к контексту приложения const { setAppBarTitle } = useContext(ApplicationСtx); //Добвление компонента в макет const addComponent = component => { const id = genGUID(); setLayouts(pv => ({ ...pv, [breakpoint]: [...pv[breakpoint], { i: id, x: 0, y: 0, w: 4, h: 10 }] })); setComponents(pv => ({ ...pv, [id]: { ...component } })); }; //Удаление компонента из макета const deleteComponent = id => { setLayouts(pv => ({ ...pv, [breakpoint]: layouts[breakpoint].filter(item => item.i !== id) })); setComponents(pv => ({ ...pv, [id]: { ...pv[id], deleted: true } })); if (valueProviders[id]) { const vPTmp = { ...valueProviders }; delete vPTmp[id]; setValueProviders(vPTmp); } editComponent === id && closeComponentSettingsEditor(); }; //Включение/выключение режима редиктирования const toggleEditMode = () => { if (!editMode) setAppBarTitle(PANEL_CAPTION_EDIT_MODE); else setAppBarTitle(PANEL_CAPTION_EXECUTE_MODE); setEditMode(!editMode); }; //Открытие редактора настроек компонента const openComponentSettingsEditor = id => setEditComponent(id); //Закрытие реактора настроек компонента const closeComponentSettingsEditor = () => setEditComponent(null); //Открытие/сокрытие меню добавления const toggleAddMenu = target => setAddMenuAnchorEl(target instanceof Element ? target : null); //При изменении размера холста const handleBreakpointChange = breakpoint => setBreakpoint(breakpoint); //При изменении состояния макета const handleLayoutChange = (currentLayout, layouts) => setLayouts(layouts); //При нажатии на кнопку добалвения const handleAddClick = e => toggleAddMenu(e.currentTarget); //При выборе элемента меню добавления const handleAddMenuItemClick = component => { toggleAddMenu(); addComponent(component); }; //При изменении значений в компоненте const handleComponentValuesChange = (id, values) => setValueProviders(pv => ({ ...pv, [id]: { ...values } })); //При нажатии на настройки компонента const handleComponentSettingsClick = id => (editComponent === id ? closeComponentSettingsEditor() : openComponentSettingsEditor(id)); //При изменении настроек компонента const handleComponentSettingsChange = ({ id = null, settings = {}, providedValues = [], closeEditor = false } = {}) => { if (id && components[id]) { const providedValuesInit = providedValues.reduce((res, providedValue) => ({ ...res, [providedValue]: undefined }), {}); if (valueProviders[id]) { const vPTmp = { ...valueProviders[id] }; Object.keys(valueProviders[id]).forEach(key => !providedValues.includes(key) && delete vPTmp[key]); setValueProviders(pv => ({ ...pv, [id]: { ...providedValuesInit, ...vPTmp } })); } else setValueProviders(pv => ({ ...pv, [id]: providedValuesInit })); setComponents(pv => ({ ...pv, [editComponent]: { ...pv[editComponent], settings: { ...settings } } })); if (closeEditor === true) closeComponentSettingsEditor(); } }; //При удалении компоненета const handleComponentDeleteClick = id => deleteComponent(id); //При подключении к странице useEffect(() => { addComponent(COMPONETNS[0]); addComponent(COMPONETNS[3]); addComponent(COMPONETNS[4]); //addComponent(COMPONETNS[1]); //addComponent(COMPONETNS[2]); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); //Текущие значения панели const values = Object.keys(valueProviders).reduce((res, key) => ({ ...res, ...valueProviders[key] }), {}); //Меню добавления const addMenu = ( {COMPONETNS.map((comp, i) => ( handleAddMenuItemClick(comp)}> {comp.name} ))} ); //Кнопка редактирования const editButton = !editMode && ( edit ); //Панель инструмментов const toolBar = ( play_arrow add ); //Генерация содержимого return ( {editButton} {addMenu} {layouts[breakpoint].map(item => ( ))} {editMode && ( {toolBar} {editComponent && ( <> )} )} ); }; //---------------- //Интерфейс модуля //---------------- export { PanelsEditor };