640 lines
27 KiB
JavaScript
640 lines
27 KiB
JavaScript
/*
|
||
Парус 8 - Панели мониторинга - Редактор панелей
|
||
Компоненты: Хуки компонентов
|
||
*/
|
||
|
||
//---------------------
|
||
//Подключение библиотек
|
||
//---------------------
|
||
|
||
import { useState, useEffect, useContext, useCallback, useLayoutEffect } from "react"; //Классы React
|
||
import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
|
||
import { MessagingСtx } from "../../../context/messaging"; //Контекст сообщений
|
||
import { object2Base64XML, genUID, xml2JSON } from "../../../core/utils"; //Вспомогательные функции
|
||
import { exportXMLFile } from "../layouts"; //Дополнительная разметка и вёрстка клиентских элементов
|
||
import { P8P_COMPONENT_SETTINGS_PATHS } from "../../../components/editors/p8p_component_settings"; //Дополнительные настройки источников
|
||
import { getActionsVariables } from "../../../components/editors/p8p_component_action/util"; //Вспомогательный функционал действий компонентов
|
||
import { P8P_CA_TYPE } from "../../../components/editors/p8p_component_action/common"; //Общие ресурсы действий
|
||
|
||
//---------
|
||
//Константы
|
||
//---------
|
||
|
||
//Начальное состояние размера макета
|
||
const INITIAL_BREAKPOINT = "lg";
|
||
|
||
//Начальное состояние макета
|
||
const INITIAL_LAYOUTS = {
|
||
[INITIAL_BREAKPOINT]: []
|
||
};
|
||
|
||
//---------
|
||
//Константы расчета высоты строки ResponsiveGridLayout
|
||
//---------
|
||
|
||
//Структура параметров для расчета высоты строки ResponsiveGridLayout
|
||
const GRID_LAYOUT_PARAMS = {
|
||
//Высота главного меню (px)
|
||
APP_BAR_HEIGHT: 64,
|
||
//Дополнительный отступ (px)
|
||
SAFE_OFFSET: 20,
|
||
//Максимальное количество строк (число)
|
||
MAX_ROWS: 68,
|
||
//Высота отступа (px)
|
||
MARGIN: 10
|
||
};
|
||
|
||
//------------------------------------
|
||
//Вспомогательные функции и компоненты
|
||
//------------------------------------
|
||
|
||
//Проверка на массив загружаемых данных панели
|
||
const isArrayPanelDesc = (name, jPath) =>
|
||
["items", "arguments", "conditions", "actions", "dependencies", "inputParams"].includes(name) || /(.*)XLAYOUTS\.[^.]*$/.test(jPath);
|
||
|
||
//Обработка значений тэгов загружаемых данных панели
|
||
const tagValueProcessorPanelDesc = (name, val, jPath) =>
|
||
["condValue", "resValue", "description"].includes(name)
|
||
? undefined
|
||
: /(.*)dataSource.arguments.value$/.test(jPath) || /(.*)XVALUE_PROVIDERS(.*)$/.test(jPath)
|
||
? undefined
|
||
: val;
|
||
|
||
//Конвертация серверного описания компонентов в данные для редактора панелей
|
||
const convertServerData2Components = components => {
|
||
//Корректировка информации о действия (Для типа "setVariable" значение ключа "params" - обязательно массив, в иных случаях - объект)
|
||
const correctionActions = actions => {
|
||
return actions.reduce(
|
||
(prevActions, action) => [
|
||
...prevActions,
|
||
{
|
||
...(action.type === P8P_CA_TYPE.setVariable.code && !Array.isArray(action.params)
|
||
? { ...action, params: [{ ...action.params }] }
|
||
: { ...action })
|
||
}
|
||
],
|
||
[]
|
||
);
|
||
};
|
||
|
||
//Форматируем устанавливая пустой объект для dataSource, если он пуст
|
||
return Object.keys(components).reduce(
|
||
(prev, cur) => ({
|
||
...prev,
|
||
[cur]: {
|
||
...components[cur],
|
||
settings: {
|
||
...components[cur].settings,
|
||
//dataSource - обязательно объект
|
||
...(components[cur].settings?.dataSource ? { dataSource: components[cur].settings.dataSource || {} } : {}),
|
||
//actions - требуют корректировки
|
||
...(components[cur].settings?.actions
|
||
? {
|
||
actions: correctionActions(components[cur].settings.actions)
|
||
}
|
||
: {})
|
||
}
|
||
}
|
||
}),
|
||
{}
|
||
);
|
||
};
|
||
|
||
//Конвертация серверного описания проводников значений в данные для редактора панелей
|
||
const convertServerData2ValueProviders = valueProviders => {
|
||
//Форматируем инициализируя dependencies, если требуется
|
||
return Object.keys(valueProviders).reduce(
|
||
(prev, cur) => ({ ...prev, [cur]: { ...valueProviders[cur], dependencies: valueProviders[cur].dependencies || [] } }),
|
||
{}
|
||
);
|
||
};
|
||
|
||
//Конвертация серверного описания панели в данные для редактора панелей
|
||
const serverPanelData2PanelDesc = (components, valueProviders, layouts, breakpoint) => {
|
||
//Возвращаем информацию о панеле с учетом конвертаций
|
||
return {
|
||
components: convertServerData2Components(components),
|
||
valueProviders: convertServerData2ValueProviders(valueProviders),
|
||
layouts: layouts[breakpoint] ? { [breakpoint]: [...layouts[breakpoint]] } : INITIAL_LAYOUTS,
|
||
breakpoint: breakpoint
|
||
};
|
||
};
|
||
|
||
//Считывание общего списка зависимостей от проводника значений
|
||
const getValueProvidersLinks = (componentPath, settings) => {
|
||
//Если это индикатор/график/таблица
|
||
if ([P8P_COMPONENT_SETTINGS_PATHS.INDICATOR, P8P_COMPONENT_SETTINGS_PATHS.CHART, P8P_COMPONENT_SETTINGS_PATHS.TABLE].includes(componentPath)) {
|
||
//Собираем зависимости из настройки источника
|
||
let argumentsSources = Array.isArray(settings?.dataSource?.arguments)
|
||
? settings.dataSource.arguments.reduce((prev, cur) => (cur.valueSource ? [...prev, cur.valueSource] : [...prev]), [])
|
||
: [];
|
||
//Собираем зависимости из параметров действий
|
||
let actionsSources = Array.isArray(settings?.actions) ? getActionsVariables(settings.actions) : [];
|
||
//Возвращаем зависимости компонента
|
||
return [...new Set([...argumentsSources, ...actionsSources])];
|
||
}
|
||
//Если это форма
|
||
if (P8P_COMPONENT_SETTINGS_PATHS.FORM === componentPath) {
|
||
//Собираем зависимости из элементов формы
|
||
let items = Array.isArray(settings?.items) ? settings.items.map(item => item.name) : [];
|
||
//Возвращаем зависимости компонента
|
||
return [...new Set(items)];
|
||
}
|
||
};
|
||
|
||
//-----------
|
||
//Тело модуля
|
||
//-----------
|
||
|
||
//Отложенная загрузка модуля компонента (как альтернативу можно применять React.lazy)
|
||
const useComponentModule = ({ path = null, module = "view" } = {}) => {
|
||
//Собственное состояние - импортированный модуль компонента
|
||
const [componentModule, setComponentModule] = useState(null);
|
||
|
||
//Собственное состояние - флаг готовности
|
||
const [init, setInit] = useState(false);
|
||
|
||
//При подмонтировании к странице
|
||
useEffect(() => {
|
||
//Динамическая загрузка модуля компонента из библиотеки
|
||
const importComponentModule = async () => {
|
||
setInit(false);
|
||
const moduleContent = await import(`./${path}/${module}`);
|
||
setComponentModule(moduleContent);
|
||
setInit(true);
|
||
};
|
||
if (path) importComponentModule();
|
||
}, [path, module]);
|
||
|
||
//Возвращаем интерфейс хука
|
||
return [componentModule, init];
|
||
};
|
||
|
||
//Работа с панелью
|
||
const usePanel = () => {
|
||
//Собственное состояние - рабочая панель
|
||
const [panel, setPanel] = useState();
|
||
//Собственное состояние - имя рабочей панели
|
||
const [panelName, setPanelName] = useState(null);
|
||
//Собственное состояние - наличие изменений рабочей панели
|
||
const [isPanelChanged, setIsPanelChanged] = useState(false);
|
||
//Собственное состояние - возможность редактирования
|
||
const [isEditAvaliable, setIsEditAvaliable] = useState(true);
|
||
//Собственное состояние - режим редактирования
|
||
const [editMode, setEditMode] = useState(true);
|
||
|
||
//Подключение к контексту взаимодействия с сервером
|
||
const { executeStored } = useContext(BackEndСtx);
|
||
|
||
//При необходимости загрузки информации о панели
|
||
const loadPanel = async panel => {
|
||
//Считываем информацию с сервера
|
||
const res = await executeStored({
|
||
stored: "PKG_P8PANELS_PE.PANEL_ATTRS_GET_BY_CODE",
|
||
args: {
|
||
SCODE: panel
|
||
},
|
||
respArg: "COUT",
|
||
loader: true
|
||
});
|
||
//Устанавливаем рабочую панель
|
||
setPanel(res.XPANEL_ATTRS.rn);
|
||
//Устанавливаем наименование рабочей панели
|
||
setPanelName(res.XPANEL_ATTRS.name);
|
||
//Сбрасываем наличие изменений рабочей панели
|
||
setIsPanelChanged(false);
|
||
//Загружаемую панель запрещено редактировать
|
||
setIsEditAvaliable(false);
|
||
setEditMode(false);
|
||
};
|
||
|
||
//При выборе панели
|
||
const selectPanel = (panel, panelName, isPanelEditAvaliable) => {
|
||
//Обновляем информацию о панели
|
||
setPanel(panel);
|
||
setPanelName(panelName);
|
||
setIsEditAvaliable(isPanelEditAvaliable);
|
||
setEditMode(isPanelEditAvaliable);
|
||
setIsPanelChanged(false);
|
||
};
|
||
|
||
//При закрытии панели
|
||
const closePanel = () => {
|
||
setPanel(null);
|
||
setPanelName(null);
|
||
setIsPanelChanged(false);
|
||
};
|
||
|
||
//При установке признака изменений панели
|
||
const setPanelChanged = isChanged => setIsPanelChanged(isChanged);
|
||
|
||
//При установке признака режима редактирования
|
||
const changeEditMode = isEditMode => setEditMode(isEditMode);
|
||
|
||
//Возвращаем интерфейс хука
|
||
return [panel, panelName, editMode, isEditAvaliable, isPanelChanged, loadPanel, selectPanel, closePanel, changeEditMode, setPanelChanged];
|
||
};
|
||
|
||
//Работа с менеджером панелей
|
||
const usePanelManager = () => {
|
||
//Собственное состояние - флаг необходимости обновления
|
||
const [refresh, setRefresh] = useState(true);
|
||
|
||
//Собственное состояние - данные
|
||
const [data, setData] = useState(null);
|
||
|
||
//Подключение к контексту взаимодействия с сервером
|
||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||
|
||
//Добавление панели
|
||
const insertPanel = useCallback(
|
||
async (code, name) => {
|
||
await executeStored({ stored: "PKG_P8PANELS_PE.PANEL_INSERT", args: { SCODE: code, SNAME: name }, loader: false });
|
||
setRefresh(true);
|
||
},
|
||
[executeStored]
|
||
);
|
||
|
||
//Изменение панели
|
||
const updatePanel = useCallback(
|
||
async (query, code, name) => {
|
||
await executeStored({ stored: "PKG_P8PANELS_PE.PANEL_UPDATE", args: { NRN: query, SCODE: code, SNAME: name }, loader: false });
|
||
setRefresh(true);
|
||
},
|
||
[executeStored]
|
||
);
|
||
|
||
//Удаление панели
|
||
const deletePanel = useCallback(
|
||
async query => {
|
||
await executeStored({ stored: "PKG_P8PANELS_PE.PANEL_DELETE", args: { NRN: query }, loader: false });
|
||
setRefresh(true);
|
||
},
|
||
[executeStored]
|
||
);
|
||
|
||
//Установка флага готовности панели
|
||
const setPanelReady = useCallback(
|
||
async (query, ready) => {
|
||
await executeStored({ stored: "PKG_P8PANELS_PE.PANEL_READY_SET", args: { NRN: query, NREADY: ready }, loader: false });
|
||
setRefresh(true);
|
||
},
|
||
[executeStored]
|
||
);
|
||
|
||
//Установка флага публичности панели
|
||
const setPanelPbl = useCallback(
|
||
async (query, pbl) => {
|
||
await executeStored({ stored: "PKG_P8PANELS_PE.PANEL_PBL_SET", args: { NRN: query, NPBL: pbl }, loader: false });
|
||
setRefresh(true);
|
||
},
|
||
[executeStored]
|
||
);
|
||
|
||
//Импорт новой панели
|
||
const importPanel = useCallback(
|
||
async fileData => {
|
||
await executeStored({
|
||
stored: "PKG_P8PANELS_PE.PANEL_IMPORT",
|
||
args: {
|
||
CPANEL: {
|
||
//Форматируем данные документа в base64
|
||
VALUE: btoa(unescape(encodeURIComponent(fileData))),
|
||
SDATA_TYPE: SERV_DATA_TYPE_CLOB
|
||
}
|
||
},
|
||
loader: true
|
||
});
|
||
setRefresh(true);
|
||
},
|
||
[SERV_DATA_TYPE_CLOB, executeStored]
|
||
);
|
||
|
||
//При необходимости получить/обновить данные
|
||
useEffect(() => {
|
||
//Загрузка данных с сервера
|
||
const loadData = async () => {
|
||
try {
|
||
const data = await executeStored({
|
||
stored: "PKG_P8PANELS_PE.PANEL_LIST",
|
||
respArg: "COUT",
|
||
isArray: name => ["XPANEL"].includes(name),
|
||
attributeValueProcessor: (name, val) => (["code", "name"].includes(name) ? undefined : val),
|
||
loader: true
|
||
});
|
||
setData(data?.XPANELS?.XPANEL || []);
|
||
} finally {
|
||
setRefresh(false);
|
||
}
|
||
};
|
||
//Если надо обновить
|
||
if (refresh)
|
||
//Получим данные
|
||
loadData();
|
||
}, [refresh, executeStored]);
|
||
|
||
//Возвращаем интерфейс хука
|
||
return [data, insertPanel, updatePanel, deletePanel, setPanelReady, setPanelPbl, importPanel];
|
||
};
|
||
|
||
//Работа с содержимым панели
|
||
const usePanelDesc = panel => {
|
||
//Собственное состояние - флаг инициализированности
|
||
const [isInit, setInit] = useState(false);
|
||
|
||
//Собственное состояние - флаг необходимости обновления
|
||
const [refresh, setRefresh] = useState(true);
|
||
|
||
//Собственное состояние - данные
|
||
const [data, setData] = useState({
|
||
components: {},
|
||
valueProviders: {},
|
||
layouts: INITIAL_LAYOUTS,
|
||
breakpoint: INITIAL_BREAKPOINT
|
||
});
|
||
|
||
//Подключение к контексту взаимодействия с сервером
|
||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
||
|
||
//Подключение к контексту сообщений
|
||
const { showMsgErr } = useContext(MessagingСtx);
|
||
|
||
//Считывание базовой информации о панели
|
||
const getPanelInfo = useCallback(async () => {
|
||
//Считываем информацию с сервера
|
||
const res = await executeStored({
|
||
stored: "PKG_P8PANELS_PE.PANEL_ATTRS_GET",
|
||
args: {
|
||
NRN: panel
|
||
},
|
||
respArg: "COUT",
|
||
loader: true
|
||
});
|
||
//Забираем все без RN
|
||
// eslint-disable-next-line no-unused-vars
|
||
const { rn, ...panelAttrs } = res.XPANEL_ATTRS;
|
||
//Возвращаем результат
|
||
return panelAttrs;
|
||
}, [executeStored, panel]);
|
||
|
||
//Формирования данных панели для выгрузки
|
||
const makeXMLPanelDesc = useCallback(
|
||
async (includePanelInfo = false, isBase64 = true) => {
|
||
//Считываем информацию о выгружаемой панели
|
||
const panelInfo = includePanelInfo ? await getPanelInfo() : {};
|
||
//Сформируем данные в формат XML
|
||
const xmlData = object2Base64XML(
|
||
{
|
||
XPANEL: {
|
||
...(includePanelInfo ? { XPANEL_INFO: panelInfo } : {}),
|
||
XCOMPONENTS: data.components,
|
||
XVALUE_PROVIDERS: data.valueProviders,
|
||
XLAYOUTS: data.layouts,
|
||
XOPTIONS: {
|
||
breakpoint: data.breakpoint
|
||
}
|
||
}
|
||
},
|
||
{ suppressEmptyNode: false }
|
||
);
|
||
//Возвращаем данные в формате XML (формат исходит от признака)
|
||
return isBase64 ? xmlData : decodeURIComponent(escape(atob(xmlData)));
|
||
},
|
||
[data.breakpoint, data.components, data.layouts, data.valueProviders, getPanelInfo]
|
||
);
|
||
|
||
//Добавление компонента в макет
|
||
const addComponent = component => {
|
||
//Генерируем ID
|
||
const id = genUID(component.path);
|
||
//Добавляем компонент и его макет
|
||
setData(pv => ({
|
||
...pv,
|
||
components: { ...pv.components, [id]: { ...component, settings: { ...component.settings, id: id } } },
|
||
layouts: { ...pv.layouts, [data.breakpoint]: [...pv.layouts[data.breakpoint], { i: id, x: 0, y: 0, w: 4, h: 10 }] }
|
||
}));
|
||
};
|
||
|
||
//Удаление компонента из макета
|
||
const deleteComponent = id => {
|
||
//Удаляем все старые зависимости от компонента
|
||
const newValueProviders = Object.keys(data.valueProviders).reduce(
|
||
(prev, cur) => ({
|
||
...prev,
|
||
[cur]: { ...data.valueProviders[cur], dependencies: data.valueProviders[cur].dependencies.filter(el => el !== id) }
|
||
}),
|
||
{}
|
||
);
|
||
//Обновляем данные
|
||
setData(pv => ({
|
||
...pv,
|
||
layouts: { ...pv.layouts, [data.breakpoint]: data.layouts[data.breakpoint].filter(item => item.i !== id) },
|
||
components: { ...pv.components, [id]: { ...pv.components[id], deleted: true } },
|
||
valueProviders: { ...newValueProviders }
|
||
}));
|
||
};
|
||
|
||
//Изменение размера холста
|
||
const breakpointChange = breakpoint => setData(pv => ({ ...pv, breakpoint: breakpoint }));
|
||
|
||
//Изменение состояния макета
|
||
const layoutsChange = layouts => setData(pv => ({ ...pv, layouts: layouts }));
|
||
|
||
//Изменение значений в компоненте
|
||
const changeValueProviders = values => {
|
||
//Считываем проводники
|
||
const newValueProviders = { ...data.valueProviders };
|
||
//Переносим новые значения в проводники
|
||
Object.keys(values).map(el => (newValueProviders[el].value = values[el]));
|
||
//Обновляем проводники
|
||
setData(pv => ({ ...pv, valueProviders: { ...newValueProviders } }));
|
||
};
|
||
|
||
//Изменение настроек компонента
|
||
const changeComponentSettings = (id = null, settings = {}, onChanged = null) => {
|
||
//Считываем новые зависимости компонента
|
||
const providedValues = getValueProvidersLinks(data.components[id].path, settings);
|
||
//Удаляем все старые зависимости от компонента
|
||
const newValueProviders = Object.keys(data.valueProviders).reduce(
|
||
(prev, cur) => ({
|
||
...prev,
|
||
[cur]: { ...data.valueProviders[cur], dependencies: data.valueProviders[cur].dependencies.filter(el => el !== id) }
|
||
}),
|
||
{}
|
||
);
|
||
//Добавляем новые зависимости
|
||
providedValues.map(providerName => newValueProviders[providerName].dependencies.push(id));
|
||
//Обновляем данные
|
||
setData(pv => ({
|
||
...pv,
|
||
components: { ...pv.components, [id]: { ...pv.components[id], settings: { ...settings } } },
|
||
valueProviders: { ...newValueProviders }
|
||
}));
|
||
//Выполняем действия после изменения
|
||
onChanged && onChanged();
|
||
};
|
||
|
||
//Изменение настроек панели
|
||
const changePanelSettings = valueProviders => {
|
||
//Обновляем данные
|
||
setData(pv => ({
|
||
...pv,
|
||
valueProviders: { ...valueProviders }
|
||
}));
|
||
};
|
||
|
||
//Сохранение описания панели
|
||
const savePanelDesc = useCallback(
|
||
async (callBack = null) => {
|
||
try {
|
||
await executeStored({
|
||
stored: "PKG_P8PANELS_PE.PANEL_DESC_SET",
|
||
args: {
|
||
NRN: panel,
|
||
CPANEL: {
|
||
VALUE: await makeXMLPanelDesc(),
|
||
SDATA_TYPE: SERV_DATA_TYPE_CLOB
|
||
}
|
||
},
|
||
loader: true
|
||
});
|
||
callBack && callBack(false);
|
||
} catch (e) {
|
||
callBack && callBack(true);
|
||
}
|
||
},
|
||
[SERV_DATA_TYPE_CLOB, executeStored, makeXMLPanelDesc, panel]
|
||
);
|
||
|
||
//Загрузка описания панели из файла
|
||
const importPanelDesc = async (fileData, callBack = null) => {
|
||
//Формируем данные панели
|
||
const panelData = await xml2JSON({
|
||
xmlDoc: fileData,
|
||
isArray: isArrayPanelDesc,
|
||
tagValueProcessor: tagValueProcessorPanelDesc
|
||
});
|
||
//Если файл содержит тэг XPANEL
|
||
if (panelData.XPANEL) {
|
||
setData(
|
||
serverPanelData2PanelDesc(
|
||
panelData.XPANEL?.XCOMPONENTS || {},
|
||
panelData.XPANEL?.XVALUE_PROVIDERS || {},
|
||
panelData.XPANEL?.XLAYOUTS || {},
|
||
panelData.XPANEL?.XOPTIONS?.breakpoint || INITIAL_BREAKPOINT
|
||
)
|
||
);
|
||
callBack && callBack(true);
|
||
} else {
|
||
showMsgErr("Загружаемые данные не соответствуют формату настройки панели.");
|
||
callBack && callBack(false);
|
||
}
|
||
};
|
||
|
||
//Выгрузка панели в файл
|
||
const exportPanelDesc = async panelName => {
|
||
//Формируем XML-представление панели
|
||
const xmlPanelDesc = await makeXMLPanelDesc(true, false);
|
||
//Выгружаем в файл
|
||
exportXMLFile(xmlPanelDesc, panelName);
|
||
};
|
||
|
||
//При необходимости получить/обновить данные
|
||
useEffect(() => {
|
||
//Загрузка данных с сервера
|
||
const loadData = async () => {
|
||
try {
|
||
const data = await executeStored({
|
||
stored: "PKG_P8PANELS_PE.PANEL_DESC_GET",
|
||
args: { NRN: panel },
|
||
respArg: "COUT",
|
||
isArray: isArrayPanelDesc,
|
||
tagValueProcessor: tagValueProcessorPanelDesc,
|
||
loader: true
|
||
});
|
||
setData(
|
||
serverPanelData2PanelDesc(
|
||
data?.XCOMPONENTS || {},
|
||
data?.XVALUE_PROVIDERS || {},
|
||
data?.XLAYOUTS || {},
|
||
data?.XOPTIONS?.breakpoint || INITIAL_BREAKPOINT
|
||
)
|
||
);
|
||
setInit(true);
|
||
} finally {
|
||
setRefresh(false);
|
||
}
|
||
};
|
||
//Если надо обновить
|
||
if (refresh)
|
||
if (panel)
|
||
//Если есть для чего получать данные
|
||
loadData();
|
||
//Нет идентификатора запроса - нет данных
|
||
else
|
||
setData({
|
||
components: {},
|
||
valueProviders: {},
|
||
layouts: INITIAL_LAYOUTS,
|
||
breakpoint: INITIAL_BREAKPOINT
|
||
});
|
||
}, [refresh, panel, executeStored]);
|
||
|
||
//При изменении входных свойств - поднимаем флаг обновления
|
||
useEffect(() => {
|
||
setInit(false);
|
||
setRefresh(true);
|
||
}, [panel]);
|
||
|
||
//Возвращаем интерфейс хука
|
||
return [
|
||
data,
|
||
isInit,
|
||
addComponent,
|
||
deleteComponent,
|
||
breakpointChange,
|
||
layoutsChange,
|
||
changeValueProviders,
|
||
changeComponentSettings,
|
||
changePanelSettings,
|
||
savePanelDesc,
|
||
importPanelDesc,
|
||
exportPanelDesc
|
||
];
|
||
};
|
||
|
||
//Работа с соотношением размеров
|
||
const useWindowResize = () => {
|
||
//Состояние высоты строки ResponsiveGridLayout
|
||
const [rowHeight, setRowHeight] = useState(1);
|
||
//При изменении размера
|
||
useLayoutEffect(() => {
|
||
//Расчет высоты строки
|
||
const updateRowHeight = () => {
|
||
//Определяем доступную область
|
||
const availableHeight = window.innerHeight - GRID_LAYOUT_PARAMS.APP_BAR_HEIGHT - GRID_LAYOUT_PARAMS.SAFE_OFFSET;
|
||
//Промежутки между рядами
|
||
const totalMargins = (GRID_LAYOUT_PARAMS.MAX_ROWS - 1) * GRID_LAYOUT_PARAMS.MARGIN;
|
||
//Рассчитываем высоту строки
|
||
const result = (availableHeight - totalMargins) / GRID_LAYOUT_PARAMS.MAX_ROWS;
|
||
//Устанавливаем
|
||
setRowHeight(result);
|
||
};
|
||
//Запускаем при открытии панели
|
||
updateRowHeight();
|
||
//Устанавливаем обработчик на событие
|
||
window.addEventListener("resize", updateRowHeight);
|
||
//Удаляем обработчик на событие
|
||
return () => window.removeEventListener("resize", updateRowHeight);
|
||
}, []);
|
||
|
||
//Возвращаем интерфейс хука
|
||
return [rowHeight];
|
||
};
|
||
|
||
//----------------
|
||
//Интерфейс модуля
|
||
//----------------
|
||
|
||
export { useComponentModule, usePanel, usePanelManager, usePanelDesc, useWindowResize };
|