diff --git a/app.text.js b/app.text.js
index 57dd8c0..f70a11d 100644
--- a/app.text.js
+++ b/app.text.js
@@ -12,14 +12,18 @@ export const TITLES = {
INFO: "Информация", //Информационный блок
WARN: "Предупреждение", //Блок предупреждения
ERR: "Ошибка", //Информация об ошибке
- DEFAULT_PANELS_GROUP: "Без привязки к группе" //Заголовок группы панелей по умолчанию
+ DEFAULT_PANELS_GROUP: "Без привязки к группе", //Заголовок группы панелей по умолчанию
+ DATA_SOURCE_CONFIG: "Настройка источника данных" //Заголовок для настройки источника данных
};
//Текст
export const TEXTS = {
LOADING: "Ожидайте...", //Ожидание завершения процесса
NO_DATA_FOUND: "Данных не найдено", //Отсутствие данных
- NO_DATA_FOUND_SHORT: "Н.Д." //Отсутствие данных (кратко)
+ NO_DATA_FOUND_SHORT: "Н.Д.", //Отсутствие данных (кратко)
+ NO_SETTINGS: "Настройки не определены", //Отстутсвие настроек
+ UNKNOWN_SOURCE_TYPE: "Неизвестный тип источника", //Отсуствие типа источника
+ UNNAMED_SOURCE: "Источник без наименования" //Отсутствие наименования источника
};
//Текст кнопок
@@ -38,7 +42,8 @@ export const BUTTONS = {
FILTER: "Фильтр", //Фильтрация
MORE: "Ещё", //Догрузка данных
APPLY: "Применить", //Сохранение без закрытия интерфейса ввода
- SAVE: "Сохранить" //Сохранение
+ SAVE: "Сохранить", //Сохранение
+ CONFIG: "Настроить" //Настройка
};
//Метки атрибутов, сопроводительные надписи
@@ -51,7 +56,9 @@ export const CAPTIONS = {
START: "Начало",
END: "Окончание",
PROGRESS: "Прогресс",
- LEGEND: "Легенда"
+ LEGEND: "Легенда",
+ USER_PROC: "Пользовательская процедура",
+ QUERY: "Запрос"
};
//Типовые сообщения об ошибках
@@ -59,7 +66,8 @@ export const ERRORS = {
UNDER_CONSTRUCTION: "Панель в разработке",
P8O_API_UNAVAILABLE: '"ПАРУС 8 Онлайн" недоступен',
P8O_API_UNSUPPORTED: 'Функция "ПАРУС 8 Онлайн" не поддерживается',
- DEFAULT: "Неожиданная ошибка"
+ DEFAULT: "Неожиданная ошибка",
+ DATA_SOURCE_NO_REQ_ARGS: "Не заданы обязательные параметры источника данных"
};
//Типовые сообщения для ошибок HTTP
diff --git a/app/panels/panels_editor/components/views_common.js b/app/components/editors/p8p_component_inline_message.js
similarity index 60%
rename from app/panels/panels_editor/components/views_common.js
rename to app/components/editors/p8p_component_inline_message.js
index 085ed0c..4cf4176 100644
--- a/app/panels/panels_editor/components/views_common.js
+++ b/app/components/editors/p8p_component_inline_message.js
@@ -1,6 +1,6 @@
/*
- Парус 8 - Панели мониторинга - Редактор панелей
- Общие компоненты представлений элементов панели
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Компонент: Информационное сообщение внутри компонента
*/
//---------------------
@@ -10,22 +10,22 @@
import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Stack, Icon, Typography } from "@mui/material"; //Интерфейсные элементы
-import { TEXTS } from "../../../../app.text"; //Общие текстовые ресурсы
+import { TEXTS } from "../../../app.text"; //Общие текстовые ресурсы
//---------
//Константы
//---------
-//Типы сообщений
-const COMPONENT_MESSAGE_TYPE = {
+//Типы сообщений компонентов
+const P8P_COMPONENT_INLINE_MESSAGE_TYPE = {
COMMON: "COMMON",
ERROR: "ERROR"
};
-//Типовые сообщения
-const COMPONENT_MESSAGES = {
+//Типовые сообщения компонентов
+const P8P_COMPONENT_INLINE_MESSAGE = {
NO_DATA_FOUND: TEXTS.NO_DATA_FOUND,
- NO_SETTINGS: "Настройте компонент"
+ NO_SETTINGS: TEXTS.NO_SETTINGS
};
//-----------
@@ -33,7 +33,7 @@ const COMPONENT_MESSAGES = {
//-----------
//Информационное сообщение внутри компонента
-const ComponentInlineMessage = ({ icon, name, message, type = COMPONENT_MESSAGE_TYPE.COMMON }) => {
+const P8PComponentInlineMessage = ({ icon, name, message, type = P8P_COMPONENT_INLINE_MESSAGE_TYPE.COMMON }) => {
//Формирование представления
return (
@@ -45,7 +45,11 @@ const ComponentInlineMessage = ({ icon, name, message, type = COMPONENT_MESSAGE_
)}
-
+
{message}
@@ -53,15 +57,15 @@ const ComponentInlineMessage = ({ icon, name, message, type = COMPONENT_MESSAGE_
};
//Контроль свойств - Информационное сообщение внутри компонента
-ComponentInlineMessage.propTypes = {
+P8PComponentInlineMessage.propTypes = {
icon: PropTypes.string,
name: PropTypes.string,
message: PropTypes.string.isRequired,
- type: PropTypes.oneOf(Object.values(COMPONENT_MESSAGE_TYPE))
+ type: PropTypes.oneOf(Object.values(P8P_COMPONENT_INLINE_MESSAGE_TYPE))
};
//----------------
//Интерфейс модуля
//----------------
-export { COMPONENT_MESSAGE_TYPE, COMPONENT_MESSAGES, ComponentInlineMessage };
+export { P8P_COMPONENT_INLINE_MESSAGE_TYPE, P8P_COMPONENT_INLINE_MESSAGE, P8PComponentInlineMessage };
diff --git a/app/components/editors/p8p_config_dialog.js b/app/components/editors/p8p_config_dialog.js
new file mode 100644
index 0000000..133dd5b
--- /dev/null
+++ b/app/components/editors/p8p_config_dialog.js
@@ -0,0 +1,40 @@
+/*
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Компонент: Диалог настройки
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import React from "react"; //Классы React
+import PropTypes from "prop-types"; //Контроль свойств компонента
+import { P8PDialog } from "../p8p_dialog"; //Типовой диалог
+
+//-----------
+//Тело модуля
+//-----------
+
+//Диалог настройки
+const P8PConfigDialog = ({ title, children, onOk, onCancel }) => {
+ //Формирование представления
+ return (
+
+ {children}
+
+ );
+};
+
+//Контроль свойств компонента - Диалог настройки
+P8PConfigDialog.propTypes = {
+ title: PropTypes.string.isRequired,
+ children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
+ onOk: PropTypes.func,
+ onCancel: PropTypes.func
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { P8PConfigDialog };
diff --git a/app/components/editors/p8p_data_source.js b/app/components/editors/p8p_data_source.js
new file mode 100644
index 0000000..965e7a6
--- /dev/null
+++ b/app/components/editors/p8p_data_source.js
@@ -0,0 +1,113 @@
+/*
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Компонент: Источник данных
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import React, { useState } from "react"; //Классы React
+import PropTypes from "prop-types"; //Контроль свойств компонента
+import { Stack, IconButton, Icon, Typography, Chip, Button, Card, CardContent, CardActions, CardActionArea } from "@mui/material"; //Интерфейсные элементы
+import { BUTTONS, TEXTS } from "../../../app.text"; //Общие текстовые ресурсы
+import { STYLES as COMMON_STYLES } from "./p8p_editors_common"; //Общие ресурсы редаторов
+import { P8P_DATA_SOURCE_SHAPE, P8P_DATA_SOURCE_TYPE, P8P_DATA_SOURCE_TYPE_NAME, P8P_DATA_SOURCE_INITIAL } from "./p8p_data_source_common"; //Общие ресурсы компонента "Источник данных"
+import { P8PDataSourceConfigDialog } from "./p8p_data_source_config_dialog"; //Диалог настройки источника данных
+
+//-----------
+//Тело модуля
+//-----------
+
+//Источник данных
+const P8PDataSource = ({ dataSource = null, valueProviders = {}, onChange = null } = {}) => {
+ //Собственное состояние - отображение диалога настройки
+ const [configDlg, setConfigDlg] = useState(false);
+
+ //Уведомление родителя о смене настроек источника данных
+ const notifyChange = settings => onChange && onChange(settings);
+
+ //При нажатии на настройку источника данных
+ const handleSetup = () => setConfigDlg(true);
+
+ //При нажатии на настройку источника данных
+ const handleSetupOk = dataSource => {
+ setConfigDlg(false);
+ notifyChange(dataSource);
+ };
+
+ //При нажатии на настройку источника данных
+ const handleSetupCancel = () => setConfigDlg(false);
+
+ //При удалении настроек источника данных
+ const handleDelete = () => notifyChange({ ...P8P_DATA_SOURCE_INITIAL });
+
+ //Расчет флага "настроенности"
+ const configured = dataSource?.type ? true : false;
+
+ //Список аргументов
+ const args =
+ configured &&
+ dataSource.arguments.map((argument, i) => (
+
+ ));
+
+ //Формирование представления
+ return (
+ <>
+ {configDlg && (
+
+ )}
+ {configured && (
+
+
+
+
+ {dataSource.type === P8P_DATA_SOURCE_TYPE.USER_PROC ? dataSource.userProc : TEXTS.UNNAMED_SOURCE}
+
+
+ {P8P_DATA_SOURCE_TYPE_NAME[dataSource.type] || TEXTS.UNKNOWN_SOURCE_TYPE}
+
+
+ {args}
+
+
+
+
+
+ delete
+
+
+
+ )}
+ {!configured && (
+
+ )}
+ >
+ );
+};
+
+//Контроль свойств компонента - Источник данных
+P8PDataSource.propTypes = {
+ dataSource: P8P_DATA_SOURCE_SHAPE,
+ valueProviders: PropTypes.object,
+ onChange: PropTypes.func
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { P8PDataSource };
diff --git a/app/components/editors/p8p_data_source_common.js b/app/components/editors/p8p_data_source_common.js
new file mode 100644
index 0000000..722e76d
--- /dev/null
+++ b/app/components/editors/p8p_data_source_common.js
@@ -0,0 +1,86 @@
+/*
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Общие ресурсы компонента "Источник данных"
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import PropTypes from "prop-types"; //Контроль свойств компонента
+import client from "../../core/client"; //Клиент БД
+import { CAPTIONS } from "../../../app.text"; //Общие текстовые ресурсы
+
+//---------
+//Константы
+//---------
+
+//Типы даных аргументов
+const P8P_DATA_SOURCE_ARGUMENT_DATA_TYPE = {
+ STR: client.SERV_DATA_TYPE_STR,
+ NUMB: client.SERV_DATA_TYPE_NUMB,
+ DATE: client.SERV_DATA_TYPE_DATE
+};
+
+//Структура аргумента источника данных
+const P8P_DATA_SOURCE_ARGUMENT_SHAPE = PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ caption: PropTypes.string.isRequired,
+ dataType: PropTypes.oneOf(Object.values(P8P_DATA_SOURCE_ARGUMENT_DATA_TYPE)),
+ req: PropTypes.bool.isRequired,
+ value: PropTypes.any,
+ valueSource: PropTypes.string
+});
+
+//Начальное состояние аргумента источника данных
+const P8P_DATA_SOURCE_ARGUMENT_INITIAL = {
+ name: "",
+ caption: "",
+ dataType: "",
+ req: false,
+ value: "",
+ valueSource: ""
+};
+
+//Типы источников данных
+const P8P_DATA_SOURCE_TYPE = {
+ USER_PROC: "USER_PROC",
+ QUERY: "QUERY"
+};
+
+//Типы источников данных (наименования)
+const P8P_DATA_SOURCE_TYPE_NAME = {
+ [P8P_DATA_SOURCE_TYPE.USER_PROC]: CAPTIONS.USER_PROC,
+ [P8P_DATA_SOURCE_TYPE.QUERY]: CAPTIONS.QUERY
+};
+
+//Структура источника данных
+const P8P_DATA_SOURCE_SHAPE = PropTypes.shape({
+ type: PropTypes.oneOf([...Object.values(P8P_DATA_SOURCE_TYPE), ""]),
+ userProc: PropTypes.string,
+ stored: PropTypes.string,
+ respArg: PropTypes.string,
+ arguments: PropTypes.arrayOf(P8P_DATA_SOURCE_ARGUMENT_SHAPE)
+});
+
+//Начальное состояние истоника данных
+const P8P_DATA_SOURCE_INITIAL = {
+ type: "",
+ userProc: "",
+ stored: "",
+ respArg: "",
+ arguments: []
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export {
+ P8P_DATA_SOURCE_ARGUMENT_DATA_TYPE,
+ P8P_DATA_SOURCE_ARGUMENT_INITIAL,
+ P8P_DATA_SOURCE_SHAPE,
+ P8P_DATA_SOURCE_TYPE,
+ P8P_DATA_SOURCE_TYPE_NAME,
+ P8P_DATA_SOURCE_INITIAL
+};
diff --git a/app/components/editors/p8p_data_source_config_dialog.js b/app/components/editors/p8p_data_source_config_dialog.js
new file mode 100644
index 0000000..864a96f
--- /dev/null
+++ b/app/components/editors/p8p_data_source_config_dialog.js
@@ -0,0 +1,185 @@
+/*
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Компонент: Диалог настройки источника данных
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import React, { useState, useEffect, useContext } from "react"; //Классы React
+import PropTypes from "prop-types"; //Контроль свойств компонента
+import { Stack, IconButton, Icon, TextField, InputAdornment, MenuItem, Menu } from "@mui/material"; //Интерфейсные элементы
+import { ApplicationСtx } from "../../context/application"; //Контекст приложения
+import { TITLES, CAPTIONS } from "../../../app.text"; //Общие текстовые ресурсы
+import { P8PConfigDialog } from "./p8p_config_dialog"; //Типовой диалог настройки
+import { P8P_DATA_SOURCE_TYPE, P8P_DATA_SOURCE_SHAPE, P8P_DATA_SOURCE_ARGUMENT_INITIAL, P8P_DATA_SOURCE_INITIAL } from "./p8p_data_source_common"; //Общие ресурсы компонента "Источник данных"
+import { useUserProcDesc } from "./p8p_data_source_hooks"; //Хуки источников данных
+
+//-----------
+//Тело модуля
+//-----------
+
+//Диалог настройки источника данных
+const P8PDataSourceConfigDialog = ({ dataSource = null, valueProviders = {}, onOk = null, onCancel = null } = {}) => {
+ //Собственное состояние - параметры элемента формы
+ const [state, setState] = useState({ ...P8P_DATA_SOURCE_INITIAL, ...dataSource });
+
+ //Собственное состояние - флаги обновление данных
+ const [refresh, setRefresh] = useState({ userProcDesc: 0 });
+
+ //Собственное состояние - элемент привязки меню выбора источника
+ const [valueProvidersMenuAnchorEl, setValueProvidersMenuAnchorEl] = useState(null);
+
+ //Описание выбранной пользовательской процедуры
+ const [userProcDesc] = useUserProcDesc({ code: state.userProc, refresh: refresh.userProcDesc });
+
+ //Подключение к контексту приложения
+ const { pOnlineShowDictionary } = useContext(ApplicationСtx);
+
+ //Установка значения/привязки аргумента
+ const setArgumentValueSource = (index, value, valueSource) =>
+ setState(pv => ({
+ ...pv,
+ arguments: pv.arguments.map((argument, i) => ({ ...argument, ...(i == index ? { value, valueSource } : {}) }))
+ }));
+
+ //Открытие/сокрытие меню выбора источника
+ const toggleValueProvidersMenu = target => setValueProvidersMenuAnchorEl(target instanceof Element ? target : null);
+
+ //При нажатии на очистку наименования пользовательской процедуры
+ const handleUserProcClearClick = () => setState({ ...P8P_DATA_SOURCE_INITIAL });
+
+ //При нажатии на выбор пользовательской процедуры в качестве источника данных
+ const handleUserProcSelectClick = () => {
+ pOnlineShowDictionary({
+ unitCode: "UserProcedures",
+ showMethod: "main",
+ inputParameters: [{ name: "in_CODE", value: state.userProc }],
+ callBack: res => {
+ if (res.success) {
+ setState(pv => ({ ...pv, type: P8P_DATA_SOURCE_TYPE.USER_PROC, userProc: res.outParameters.out_CODE }));
+ setRefresh(pv => ({ ...pv, userProcDesc: pv.userProcDesc + 1 }));
+ }
+ }
+ });
+ };
+
+ //При закрытии дилога с сохранением
+ const handleOk = () => onOk && onOk({ ...state });
+
+ //При закртии диалога отменой
+ const handleCancel = () => onCancel && onCancel();
+
+ //При очистке значения/связывания аргумента
+ const handleArgumentClearClick = index => setArgumentValueSource(index, "", "");
+
+ //При отображении меню связывания аргумента с поставщиком данных
+ const handleArgumentLinkMenuClick = e => setValueProvidersMenuAnchorEl(e.currentTarget);
+
+ //При выборе элемента меню связывания аргумента с поставщиком данных
+ const handleArgumentLinkClick = valueSource => {
+ setArgumentValueSource(valueProvidersMenuAnchorEl.id, "", valueSource);
+ toggleValueProvidersMenu();
+ };
+
+ //При вводе значения аргумента
+ const handleArgumentChange = (index, value) => setArgumentValueSource(index, value, "");
+
+ //При изменении описания пользовательской процедуры
+ useEffect(() => {
+ if (userProcDesc)
+ setState(pv => ({
+ ...pv,
+ stored: userProcDesc?.stored?.name,
+ respArg: userProcDesc?.stored?.respArg,
+ arguments: (userProcDesc?.arguments || []).map(argument => ({ ...P8P_DATA_SOURCE_ARGUMENT_INITIAL, ...argument }))
+ }));
+ }, [userProcDesc]);
+
+ //Список значений
+ const values = Object.keys(valueProviders).reduce((res, key) => [...res, ...Object.keys(valueProviders[key])], []);
+
+ //Наличие значений
+ const isValues = values && values.length > 0 ? true : false;
+
+ //Меню привязки к поставщикам значений
+ const valueProvidersMenu = isValues && (
+
+ );
+
+ //Формирование представления
+ return (
+
+
+ {valueProvidersMenu}
+
+
+ clear
+
+
+ list
+
+
+ )
+ }}
+ />
+ {Array.isArray(state?.arguments) &&
+ state.arguments.map((argument, i) => (
+ handleArgumentChange(i, e.target.value)}
+ InputLabelProps={{ shrink: true }}
+ InputProps={{
+ endAdornment: (
+
+ handleArgumentClearClick(i)}>
+ clear
+
+ {isValues && (
+
+ settings_ethernet
+
+ )}
+
+ )
+ }}
+ />
+ ))}
+
+
+ );
+};
+
+//Контроль свойств компонента - Диалог настройки источника данных
+P8PDataSourceConfigDialog.propTypes = {
+ dataSource: P8P_DATA_SOURCE_SHAPE,
+ valueProviders: PropTypes.object,
+ onOk: PropTypes.func,
+ onCancel: PropTypes.func
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { P8PDataSourceConfigDialog };
diff --git a/app/components/editors/p8p_data_source_hooks.js b/app/components/editors/p8p_data_source_hooks.js
new file mode 100644
index 0000000..60c9cf5
--- /dev/null
+++ b/app/components/editors/p8p_data_source_hooks.js
@@ -0,0 +1,151 @@
+/*
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Пользовательские хуки компонента "Источник данных"
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import { useState, useContext, useEffect, useRef } from "react"; //Классы React
+import client from "../../core/client"; //Клиент взаимодействия с сервером приложений
+import { ERRORS } from "../../../app.text"; //Общие текстовые ресурсы
+import { formatErrorMessage } from "../../core/utils"; //Общие вспомогательные функции
+import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
+import { P8P_DATA_SOURCE_TYPE, P8P_DATA_SOURCE_ARGUMENT_DATA_TYPE } from "./p8p_data_source_common"; //Общие ресурсы источника данных
+
+//-----------
+//Тело модуля
+//-----------
+
+//Описание пользовательской процедуры
+const useUserProcDesc = ({ code, refresh }) => {
+ //Собственное состояние - флаг загрузки
+ const [isLoading, setLoading] = useState(false);
+
+ //Собственное состояние - данные
+ const [data, setData] = useState(null);
+
+ //Подключение к контексту взаимодействия с сервером
+ const { executeStored } = useContext(BackEndСtx);
+
+ //При необходимости обновить данные компонента
+ useEffect(() => {
+ //Загрузка данных с сервера
+ const loadData = async () => {
+ try {
+ setLoading(true);
+ const data = await executeStored({
+ stored: "PKG_P8PANELS_PE.USERPROCS_DESC",
+ args: { SCODE: code },
+ respArg: "COUT",
+ isArray: name => name === "arguments",
+ loader: false
+ });
+ setData(data?.XUSERPROC || null);
+ } finally {
+ setLoading(false);
+ }
+ };
+ //Если надо обновить и есть для чего получать данные
+ if (refresh > 0)
+ if (code) loadData();
+ else setData(null);
+ }, [refresh, code, executeStored]);
+
+ //Возвращаем интерфейс хука
+ return [data, isLoading];
+};
+
+//Получение данных из источника
+const useDataSource = ({ dataSource, values }) => {
+ //Контроллер для прерывания запросов
+ const abortController = useRef(null);
+
+ //Собственное состояние - параметры исполнения
+ const [state, setState] = useState({ stored: null, storedArgs: [], respArg: null, reqSet: false });
+
+ //Собственное состояние - флаг загрузки
+ const [isLoading, setLoading] = useState(false);
+
+ //Собственное состояние - данные
+ const [data, setData] = useState({ init: false });
+
+ //Собственное состояние - ошибка получения данных
+ const [error, setError] = useState(null);
+
+ //Подключение к контексту взаимодействия с сервером
+ const { executeStored } = useContext(BackEndСtx);
+
+ //При необходимости обновить данные
+ useEffect(() => {
+ //Загрузка данных с сервера
+ const loadData = async () => {
+ try {
+ setLoading(true);
+ abortController.current?.abort?.();
+ abortController.current = new AbortController();
+ const data = await executeStored({
+ stored: state.stored,
+ args: { ...(state.storedArgs ? state.storedArgs : {}) },
+ respArg: state.respArg,
+ loader: false,
+ signal: abortController.current.signal,
+ showErrorMessage: false
+ });
+ setError(null);
+ setData({ ...data, init: true });
+ } catch (e) {
+ if (e.message !== client.ERR_ABORTED) {
+ setError(formatErrorMessage(e.message).text);
+ setData({ init: false });
+ }
+ } finally {
+ setLoading(false);
+ }
+ };
+ if (state.reqSet) {
+ if (state.stored) loadData();
+ } else setData({ init: false });
+ return () => abortController.current?.abort?.();
+ }, [state.stored, state.storedArgs, state.respArg, state.reqSet, executeStored]);
+
+ //При изменении свойств
+ useEffect(() => {
+ setState(pv => {
+ if (dataSource?.type == P8P_DATA_SOURCE_TYPE.USER_PROC) {
+ const { stored, respArg } = dataSource;
+ let reqSet = true;
+ const storedArgs = {};
+ dataSource.arguments.forEach(argument => {
+ let v = argument.valueSource ? values[argument.valueSource] : argument.value;
+ storedArgs[argument.name] =
+ argument.dataType == P8P_DATA_SOURCE_ARGUMENT_DATA_TYPE.NUMB
+ ? isNaN(parseFloat(v))
+ ? null
+ : parseFloat(v)
+ : argument.dataType == P8P_DATA_SOURCE_ARGUMENT_DATA_TYPE.DATE
+ ? new Date(v)
+ : String(v === undefined ? "" : v);
+ if (argument.req === true && [undefined, null, ""].includes(storedArgs[argument.name])) reqSet = false;
+ });
+ if (pv.stored != stored || pv.respArg != respArg || JSON.stringify(pv.storedArgs) != JSON.stringify(storedArgs)) {
+ if (!reqSet) {
+ setError(ERRORS.DATA_SOURCE_NO_REQ_ARGS);
+ setData({ init: false });
+ }
+ return { stored, respArg, storedArgs, reqSet };
+ } else return pv;
+ } else return pv;
+ });
+ }, [dataSource, values]);
+
+ //Возвращаем интерфейс хука
+ return [data, error, isLoading];
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { useUserProcDesc, useDataSource };
diff --git a/app/components/editors/p8p_editor_box.js b/app/components/editors/p8p_editor_box.js
new file mode 100644
index 0000000..46ffcf6
--- /dev/null
+++ b/app/components/editors/p8p_editor_box.js
@@ -0,0 +1,54 @@
+/*
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Компонент: Контейнер редактора
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import React from "react"; //Классы React
+import PropTypes from "prop-types"; //Контроль свойств компонента
+import { Box, Divider, IconButton, Icon, Stack } from "@mui/material"; //Интерфейсные компоненты MUI
+import { BUTTONS } from "../../../app.text"; //Общие текстовые ресурсы
+
+//-----------
+//Тело модуля
+//-----------
+
+//Контейнер редактора
+const P8PEditorBox = ({ title, children, onSave }) => {
+ //При нажатии на "Сохранить"
+ const handleSaveClick = (closeEditor = false) => onSave && onSave(closeEditor);
+
+ //Формирование представления
+ return (
+
+ {title}
+
+ {children}
+
+
+ handleSaveClick(false)} title={BUTTONS.APPLY}>
+ done
+
+ handleSaveClick(true)} title={BUTTONS.SAVE}>
+ done_all
+
+
+
+ );
+};
+
+//Контроль свойств компонента - Контейнер редактора
+P8PEditorBox.propTypes = {
+ title: PropTypes.string.isRequired,
+ children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
+ onSave: PropTypes.func
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { P8PEditorBox };
diff --git a/app/components/editors/p8p_editor_sub_header.js b/app/components/editors/p8p_editor_sub_header.js
new file mode 100644
index 0000000..8d97d1a
--- /dev/null
+++ b/app/components/editors/p8p_editor_sub_header.js
@@ -0,0 +1,46 @@
+/*
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Компонент: Заголовок раздела редактора
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import React from "react"; //Классы React
+import PropTypes from "prop-types"; //Контроль свойств компонента
+import { Divider, Chip } from "@mui/material"; //Интерфейсные компоненты MUI
+
+//---------
+//Константы
+//---------
+
+//Стили
+const STYLES = {
+ DIVIDER: { paddingTop: "20px" }
+};
+
+//-----------
+//Тело модуля
+//-----------
+
+//Заголовок раздела редактора
+const P8PEditorSubHeader = ({ title }) => {
+ //Формирование представления
+ return (
+
+
+
+ );
+};
+
+//Контроль свойств компонента - Заголовок раздела редактора
+P8PEditorSubHeader.propTypes = {
+ title: PropTypes.string.isRequired
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { P8PEditorSubHeader };
diff --git a/app/components/editors/p8p_editor_toolbar.js b/app/components/editors/p8p_editor_toolbar.js
new file mode 100644
index 0000000..d68e373
--- /dev/null
+++ b/app/components/editors/p8p_editor_toolbar.js
@@ -0,0 +1,52 @@
+/*
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Компонент: Панель инструментов редактора
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import React from "react"; //Классы React
+import PropTypes from "prop-types"; //Контроль свойств компонента
+import { IconButton, Icon, Stack } from "@mui/material"; //Интерфейсные компоненты MUI
+
+//---------
+//Константы
+//---------
+
+//Структура элемента панели инструментов редактора
+const P8P_EDITOR_TOOL_BAR_ITEM_SHAPE = PropTypes.shape({
+ icon: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ onClick: PropTypes.func.isRequired
+});
+
+//-----------
+//Тело модуля
+//-----------
+
+//Панель инструментов редактора
+const P8PEditorToolBar = ({ items = [] }) => {
+ //Формирование представления
+ return (
+
+ {items.map((item, i) => (
+
+ {item.icon}
+
+ ))}
+
+ );
+};
+
+//Контроль свойств компонента - Панель инструментов редактора
+P8PEditorToolBar.propTypes = {
+ items: PropTypes.arrayOf(P8P_EDITOR_TOOL_BAR_ITEM_SHAPE)
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { P8PEditorToolBar };
diff --git a/app/components/editors/p8p_editors_common.js b/app/components/editors/p8p_editors_common.js
new file mode 100644
index 0000000..8911cc2
--- /dev/null
+++ b/app/components/editors/p8p_editors_common.js
@@ -0,0 +1,30 @@
+/*
+ Парус 8 - Панели мониторинга - Редакторы панелей
+ Общие ресурсы редакторов
+*/
+
+//---------
+//Константы
+//---------
+
+//Стили
+const STYLES = {
+ CHIP: (fullWidth = false, multiLine = false) => ({
+ ...(multiLine ? { height: "auto" } : {}),
+ "& .MuiChip-label": {
+ ...(multiLine
+ ? {
+ display: "block",
+ whiteSpace: "normal"
+ }
+ : {}),
+ ...(fullWidth ? { width: "100%" } : {})
+ }
+ })
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { STYLES };
diff --git a/app/panels/panels_editor/component_editor.js b/app/panels/panels_editor/component_editor.js
index ce3bc8d..0da26e6 100644
--- a/app/panels/panels_editor/component_editor.js
+++ b/app/panels/panels_editor/component_editor.js
@@ -11,7 +11,6 @@ import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Box, Typography } from "@mui/material"; //Интерфейсные элементы
import { useComponentModule } from "./components/components_hooks"; //Хуки компонентов
-import "./panels_editor.css"; //Стили редактора
//-----------
//Тело модуля
@@ -27,7 +26,7 @@ const ComponentEditor = ({ id, path, settings = {}, valueProviders = {}, onSetti
//Формирование представления
return (
-
+
{haveComponent && init && (
)}
diff --git a/app/panels/panels_editor/component_view.js b/app/panels/panels_editor/component_view.js
index c914010..2cac128 100644
--- a/app/panels/panels_editor/component_view.js
+++ b/app/panels/panels_editor/component_view.js
@@ -11,7 +11,6 @@ import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Box, Typography } from "@mui/material"; //Интерфейсные элементы
import { useComponentModule } from "./components/components_hooks"; //Хуки компонентов
-import "./panels_editor.css"; //Стили редактора
//-----------
//Тело модуля
diff --git a/app/panels/panels_editor/components/chart/editor.js b/app/panels/panels_editor/components/chart/editor.js
index b6aa7f3..5cf3379 100644
--- a/app/panels/panels_editor/components/chart/editor.js
+++ b/app/panels/panels_editor/components/chart/editor.js
@@ -9,8 +9,10 @@
import React, { useEffect, useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
-import { DATA_SOURCE_SHAPE, DataSource, EditorBox, EditorSubHeader } from "../editors_common"; //Общие компоненты редакторов
-import "../../panels_editor.css"; //Стили редактора
+import { P8PEditorBox } from "../../../../components/editors/p8p_editor_box"; //Контейнер редактора
+import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Заголовок раздела редактора
+import { P8P_DATA_SOURCE_SHAPE } from "../../../../components/editors/p8p_data_source_common"; //Общие ресурсы источника данных
+import { P8PDataSource } from "../../../../components/editors/p8p_data_source"; //Источник данных
//-----------
//Тело модуля
@@ -34,17 +36,17 @@ const ChartEditor = ({ id, dataSource = null, valueProviders = {}, onSettingsCha
//Формирование представления
return (
-
-
-
-
+
+
+
+
);
};
//Контроль свойств компонента - График (редактор настроек)
ChartEditor.propTypes = {
id: PropTypes.string.isRequired,
- dataSource: DATA_SOURCE_SHAPE,
+ dataSource: P8P_DATA_SOURCE_SHAPE,
valueProviders: PropTypes.object,
onSettingsChange: PropTypes.func
};
diff --git a/app/panels/panels_editor/components/chart/view.js b/app/panels/panels_editor/components/chart/view.js
index 273da15..3a31c68 100644
--- a/app/panels/panels_editor/components/chart/view.js
+++ b/app/panels/panels_editor/components/chart/view.js
@@ -11,10 +11,13 @@ import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Paper } from "@mui/material"; //Интерфейсные элементы
import { P8PChart } from "../../../../components/p8p_chart"; //График
-import { useComponentDataSource } from "../components_hooks"; //Хуки для данных
-import { DATA_SOURCE_SHAPE } from "../editors_common"; //Общие объекты компонентов
-import { COMPONENT_MESSAGE_TYPE, COMPONENT_MESSAGES, ComponentInlineMessage } from "../views_common"; //Общие компоненты представлений
-import "../../panels_editor.css"; //Стили редактора
+import { useDataSource } from "../../../../components/editors/p8p_data_source_hooks"; //Хуки для данных
+import { P8P_DATA_SOURCE_SHAPE } from "../../../../components/editors/p8p_data_source_common"; //Общие ресурсы источника данных
+import {
+ P8P_COMPONENT_INLINE_MESSAGE_TYPE,
+ P8P_COMPONENT_INLINE_MESSAGE,
+ P8PComponentInlineMessage
+} from "../../../../components/editors/p8p_component_inline_message"; //Информационное сообщение внутри компонента
//---------
//Константы
@@ -38,7 +41,7 @@ const STYLES = {
//График (представление)
const Chart = ({ dataSource = null, values = {} } = {}) => {
//Собственное состояние - данные
- const [data, error] = useComponentDataSource({ dataSource, values });
+ const [data, error] = useDataSource({ dataSource, values });
//Флаг настроенности графика
const haveConfing = dataSource?.stored ? true : false;
@@ -55,11 +58,11 @@ const Chart = ({ dataSource = null, values = {} } = {}) => {
{haveConfing && haveData ? (
) : (
-
)}
@@ -68,7 +71,7 @@ const Chart = ({ dataSource = null, values = {} } = {}) => {
//Контроль свойств компонента - График (представление)
Chart.propTypes = {
- dataSource: DATA_SOURCE_SHAPE,
+ dataSource: P8P_DATA_SOURCE_SHAPE,
values: PropTypes.object
};
diff --git a/app/panels/panels_editor/components/components.js b/app/panels/panels_editor/components/components.js
index 5c87a24..a17c301 100644
--- a/app/panels/panels_editor/components/components.js
+++ b/app/panels/panels_editor/components/components.js
@@ -11,7 +11,7 @@ const COMPONETNS = [
{
name: "Форма",
path: "form",
- settings: {
+ settings2: {
title: "Параметры формирования",
autoApply: true,
items: [
@@ -75,7 +75,7 @@ const COMPONETNS = [
{
name: "Индикатор",
path: "indicator",
- settings: {
+ settings2: {
dataSource: {
type: "USER_PROC",
userProc: "ИндКолДогКонтрТип",
@@ -95,7 +95,7 @@ const COMPONETNS = [
]
}
}
- },
+ } /*,
{
name: "Индикатор2",
path: "indicator",
@@ -119,7 +119,7 @@ const COMPONETNS = [
]
}
}
- }
+ }*/
];
//----------------
diff --git a/app/panels/panels_editor/components/components_hooks.js b/app/panels/panels_editor/components/components_hooks.js
index 518cd82..e539f52 100644
--- a/app/panels/panels_editor/components/components_hooks.js
+++ b/app/panels/panels_editor/components/components_hooks.js
@@ -7,17 +7,13 @@
//Подключение библиотек
//---------------------
-import { useState, useContext, useEffect, useRef } from "react"; //Классы React
-import client from "../../../core/client"; //Клиент взаимодействия с сервером приложений
-import { formatErrorMessage } from "../../../core/utils"; //Общие вспомогательные функции
-import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
-import { DATA_SOURCE_TYPE, ARGUMENT_DATA_TYPE } from "./editors_common"; //Общие объекты редакторов
+import { useState, useEffect } from "react"; //Классы React
//-----------
//Тело модуля
//-----------
-//Загрузка модуля компонента из модуля (можно применять как альтернативу React.lazy)
+//Отложенная загрузка модуля компонента (как альтернативу можно применять React.lazy)
const useComponentModule = ({ path = null, module = "view" } = {}) => {
//Собственное состояние - импортированный модуль компонента
const [componentModule, setComponentModule] = useState(null);
@@ -41,134 +37,8 @@ const useComponentModule = ({ path = null, module = "view" } = {}) => {
return [componentModule, init];
};
-//Описание пользовательской процедуры
-const useUserProcDesc = ({ code, refresh }) => {
- //Собственное состояние - флаг загрузки
- const [isLoading, setLoading] = useState(false);
-
- //Собственное состояние - данные
- const [data, setData] = useState(null);
-
- //Подключение к контексту взаимодействия с сервером
- const { executeStored } = useContext(BackEndСtx);
-
- //При необходимости обновить данные компонента
- useEffect(() => {
- //Загрузка данных с сервера
- const loadData = async () => {
- try {
- setLoading(true);
- const data = await executeStored({
- stored: "PKG_P8PANELS_PE.USERPROCS_DESC",
- args: { SCODE: code },
- respArg: "COUT",
- isArray: name => name === "arguments",
- loader: false
- });
- setData(data?.XUSERPROC || null);
- } finally {
- setLoading(false);
- }
- };
- //Если надо обновить и есть для чего получать данные
- if (refresh > 0)
- if (code) loadData();
- else setData(null);
- }, [refresh, code, executeStored]);
-
- //Возвращаем интерфейс хука
- return [data, isLoading];
-};
-
-//Получение данных компонента из источника
-const useComponentDataSource = ({ dataSource, values }) => {
- //Контроллер для прерывания запросов
- const abortController = useRef(null);
-
- //Собственное состояние - параметры исполнения
- const [state, setState] = useState({ stored: null, storedArgs: [], respArg: null, reqSet: false });
-
- //Собственное состояние - флаг загрузки
- const [isLoading, setLoading] = useState(false);
-
- //Собственное состояние - данные
- const [data, setData] = useState({ init: false });
-
- //Собственное состояние - ошибка получения данных
- const [error, setError] = useState(null);
-
- //Подключение к контексту взаимодействия с сервером
- const { executeStored } = useContext(BackEndСtx);
-
- //При необходимости обновить данные
- useEffect(() => {
- //Загрузка данных с сервера
- const loadData = async () => {
- try {
- setLoading(true);
- abortController.current?.abort?.();
- abortController.current = new AbortController();
- const data = await executeStored({
- stored: state.stored,
- args: { ...(state.storedArgs ? state.storedArgs : {}) },
- respArg: state.respArg,
- loader: false,
- signal: abortController.current.signal,
- showErrorMessage: false
- });
- setError(null);
- setData({ ...data, init: true });
- } catch (e) {
- if (e.message !== client.ERR_ABORTED) {
- setError(formatErrorMessage(e.message).text);
- setData({ init: false });
- }
- } finally {
- setLoading(false);
- }
- };
- if (state.reqSet) {
- if (state.stored) loadData();
- } else setData({ init: false });
- return () => abortController.current?.abort?.();
- }, [state.stored, state.storedArgs, state.respArg, state.reqSet, executeStored]);
-
- //При изменении свойств
- useEffect(() => {
- setState(pv => {
- if (dataSource?.type == DATA_SOURCE_TYPE.USER_PROC) {
- const { stored, respArg } = dataSource;
- let reqSet = true;
- const storedArgs = {};
- dataSource.arguments.forEach(argument => {
- let v = argument.valueSource ? values[argument.valueSource] : argument.value;
- storedArgs[argument.name] =
- argument.dataType == ARGUMENT_DATA_TYPE.NUMB
- ? isNaN(parseFloat(v))
- ? null
- : parseFloat(v)
- : argument.dataType == ARGUMENT_DATA_TYPE.DATE
- ? new Date(v)
- : String(v === undefined ? "" : v);
- if (argument.req === true && [undefined, null, ""].includes(storedArgs[argument.name])) reqSet = false;
- });
- if (pv.stored != stored || pv.respArg != respArg || JSON.stringify(pv.storedArgs) != JSON.stringify(storedArgs)) {
- if (!reqSet) {
- setError("Не заданы обязательные параметры источника данных");
- setData({ init: false });
- }
- return { stored, respArg, storedArgs, reqSet };
- } else return pv;
- } else return pv;
- });
- }, [dataSource, values]);
-
- //Возвращаем интерфейс хука
- return [data, error, isLoading];
-};
-
//----------------
//Интерфейс модуля
//----------------
-export { useComponentModule, useUserProcDesc, useComponentDataSource };
+export { useComponentModule };
diff --git a/app/panels/panels_editor/components/editors_common.js b/app/panels/panels_editor/components/editors_common.js
deleted file mode 100644
index 20bf1d0..0000000
--- a/app/panels/panels_editor/components/editors_common.js
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- Парус 8 - Панели мониторинга - Редактор панелей
- Общие компоненты редакторов свойств
-*/
-
-//---------------------
-//Подключение библиотек
-//---------------------
-
-import React, { useState, useContext, useEffect } from "react"; //Классы React
-import PropTypes from "prop-types"; //Контроль свойств компонента
-import {
- Box,
- Stack,
- IconButton,
- Icon,
- Typography,
- Divider,
- Chip,
- Button,
- TextField,
- InputAdornment,
- MenuItem,
- Menu,
- Card,
- CardContent,
- CardActions,
- CardActionArea
-} from "@mui/material"; //Интерфейсные элементы
-import client from "../../../core/client"; //Клиент БД
-import { ApplicationСtx } from "../../../context/application"; //Контекст приложения
-import { BUTTONS } from "../../../../app.text"; //Общие текстовые ресурсы
-import { P8PDialog } from "../../../components/p8p_dialog"; //Типовой диалог
-import { useUserProcDesc } from "./components_hooks"; //Общие хуки компонентов
-import "../panels_editor.css"; //Стили редактора
-
-//---------
-//Константы
-//---------
-
-//Стили
-const STYLES = {
- CHIP: (fullWidth = false, multiLine = false) => ({
- ...(multiLine ? { height: "auto" } : {}),
- "& .MuiChip-label": {
- ...(multiLine
- ? {
- display: "block",
- whiteSpace: "normal"
- }
- : {}),
- ...(fullWidth ? { width: "100%" } : {})
- }
- })
-};
-
-//Типы даных аргументов
-const ARGUMENT_DATA_TYPE = {
- STR: client.SERV_DATA_TYPE_STR,
- NUMB: client.SERV_DATA_TYPE_NUMB,
- DATE: client.SERV_DATA_TYPE_DATE
-};
-
-//Типы источников данных
-const DATA_SOURCE_TYPE = {
- USER_PROC: "USER_PROC",
- QUERY: "QUERY"
-};
-
-//Типы источников данных (наименования)
-const DATA_SOURCE_TYPE_NAME = {
- [DATA_SOURCE_TYPE.USER_PROC]: "Пользовательская процедура",
- [DATA_SOURCE_TYPE.QUERY]: "Запрос"
-};
-
-//Структура аргумента источника данных
-const DATA_SOURCE_ARGUMENT_SHAPE = PropTypes.shape({
- name: PropTypes.string.isRequired,
- caption: PropTypes.string.isRequired,
- dataType: PropTypes.oneOf(Object.values(ARGUMENT_DATA_TYPE)),
- req: PropTypes.bool.isRequired,
- value: PropTypes.any,
- valueSource: PropTypes.string
-});
-
-//Начальное состояние аргумента источника данных
-const DATA_SOURCE_ARGUMENT_INITIAL = {
- name: "",
- caption: "",
- dataType: "",
- req: false,
- value: "",
- valueSource: ""
-};
-
-//Структура источника данных
-const DATA_SOURCE_SHAPE = PropTypes.shape({
- type: PropTypes.oneOf([...Object.values(DATA_SOURCE_TYPE), ""]),
- userProc: PropTypes.string,
- stored: PropTypes.string,
- respArg: PropTypes.string,
- arguments: PropTypes.arrayOf(DATA_SOURCE_ARGUMENT_SHAPE)
-});
-
-//Начальное состояние истоника данных
-const DATA_SOURCE_INITIAL = {
- type: "",
- userProc: "",
- stored: "",
- respArg: "",
- arguments: []
-};
-
-//-----------
-//Тело модуля
-//-----------
-
-//Контейнер редактора
-const EditorBox = ({ title, children, onSave }) => {
- //При нажатии на "Сохранить"
- const handleSaveClick = (closeEditor = false) => onSave && onSave(closeEditor);
-
- //Формирование представления
- return (
-
- {title}
-
- {children}
-
-
- handleSaveClick(false)} title={BUTTONS.APPLY}>
- done
-
- handleSaveClick(true)} title={BUTTONS.SAVE}>
- done_all
-
-
-
- );
-};
-
-//Контроль свойств компонента - контейнер редактора
-EditorBox.propTypes = {
- title: PropTypes.string.isRequired,
- children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
- onSave: PropTypes.func
-};
-
-//Заголовок раздела редактора
-const EditorSubHeader = ({ title }) => {
- //Формирование представления
- return (
-
-
-
- );
-};
-
-//Контроль свойств компонента - заголовок раздела редактора
-EditorSubHeader.propTypes = {
- title: PropTypes.string.isRequired
-};
-
-//Диалог настройки
-const ConfigDialog = ({ title, children, onOk, onCancel }) => {
- //Формирование представления
- return (
-
- {children}
-
- );
-};
-
-//Контроль свойств компонента - диалог настройки
-ConfigDialog.propTypes = {
- title: PropTypes.string.isRequired,
- children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
- onOk: PropTypes.func,
- onCancel: PropTypes.func
-};
-
-//Диалог настройки источника данных
-const ConfigDataSourceDialog = ({ dataSource = null, valueProviders = {}, onOk = null, onCancel = null } = {}) => {
- //Собственное состояние - параметры элемента формы
- const [state, setState] = useState({ ...DATA_SOURCE_INITIAL, ...dataSource });
-
- //Собственное состояние - флаги обновление данных
- const [refresh, setRefresh] = useState({ userProcDesc: 0 });
-
- //Собственное состояние - элемент привязки меню выбора источника
- const [valueProvidersMenuAnchorEl, setValueProvidersMenuAnchorEl] = useState(null);
-
- //Описание выбранной пользовательской процедуры
- const [userProcDesc] = useUserProcDesc({ code: state.userProc, refresh: refresh.userProcDesc });
-
- //Подключение к контексту приложения
- const { pOnlineShowDictionary } = useContext(ApplicationСtx);
-
- //Установка значения/привязки аргумента
- const setArgumentValueSource = (index, value, valueSource) =>
- setState(pv => ({
- ...pv,
- arguments: pv.arguments.map((argument, i) => ({ ...argument, ...(i == index ? { value, valueSource } : {}) }))
- }));
-
- //Открытие/сокрытие меню выбора источника
- const toggleValueProvidersMenu = target => setValueProvidersMenuAnchorEl(target instanceof Element ? target : null);
-
- //При нажатии на очистку наименования пользовательской процедуры
- const handleUserProcClearClick = () => setState({ ...DATA_SOURCE_INITIAL });
-
- //При нажатии на выбор пользовательской процедуры в качестве источника данных
- const handleUserProcSelectClick = () => {
- pOnlineShowDictionary({
- unitCode: "UserProcedures",
- showMethod: "main",
- inputParameters: [{ name: "in_CODE", value: state.userProc }],
- callBack: res => {
- if (res.success) {
- setState(pv => ({ ...pv, type: DATA_SOURCE_TYPE.USER_PROC, userProc: res.outParameters.out_CODE }));
- setRefresh(pv => ({ ...pv, userProcDesc: pv.userProcDesc + 1 }));
- }
- }
- });
- };
-
- //При закрытии дилога с сохранением
- const handleOk = () => onOk && onOk({ ...state });
-
- //При закртии диалога отменой
- const handleCancel = () => onCancel && onCancel();
-
- //При очистке значения/связывания аргумента
- const handleArgumentClearClick = index => setArgumentValueSource(index, "", "");
-
- //При отображении меню связывания аргумента с поставщиком данных
- const handleArgumentLinkMenuClick = e => setValueProvidersMenuAnchorEl(e.currentTarget);
-
- //При выборе элемента меню связывания аргумента с поставщиком данных
- const handleArgumentLinkClick = valueSource => {
- setArgumentValueSource(valueProvidersMenuAnchorEl.id, "", valueSource);
- toggleValueProvidersMenu();
- };
-
- //При вводе значения аргумента
- const handleArgumentChange = (index, value) => setArgumentValueSource(index, value, "");
-
- //При изменении описания пользовательской процедуры
- useEffect(() => {
- if (userProcDesc)
- setState(pv => ({
- ...pv,
- stored: userProcDesc?.stored?.name,
- respArg: userProcDesc?.stored?.respArg,
- arguments: (userProcDesc?.arguments || []).map(argument => ({ ...DATA_SOURCE_ARGUMENT_INITIAL, ...argument }))
- }));
- }, [userProcDesc]);
-
- //Список значений
- const values = Object.keys(valueProviders).reduce((res, key) => [...res, ...Object.keys(valueProviders[key])], []);
-
- //Наличие значений
- const isValues = values && values.length > 0 ? true : false;
-
- //Меню привязки к поставщикам значений
- const valueProvidersMenu = isValues && (
-
- );
-
- //Формирование представления
- return (
-
-
- {valueProvidersMenu}
-
-
- clear
-
-
- list
-
-
- )
- }}
- />
- {Array.isArray(state?.arguments) &&
- state.arguments.map((argument, i) => (
- handleArgumentChange(i, e.target.value)}
- InputLabelProps={{ shrink: true }}
- InputProps={{
- endAdornment: (
-
- handleArgumentClearClick(i)}>
- clear
-
- {isValues && (
-
- settings_ethernet
-
- )}
-
- )
- }}
- />
- ))}
-
-
- );
-};
-
-//Контроль свойств компонента - Диалог настройки источника данных
-ConfigDataSourceDialog.propTypes = {
- dataSource: DATA_SOURCE_SHAPE,
- valueProviders: PropTypes.object,
- onOk: PropTypes.func,
- onCancel: PropTypes.func
-};
-
-//Источник данных
-const DataSource = ({ dataSource = null, valueProviders = {}, onChange = null } = {}) => {
- //Собственное состояние - отображение диалога настройки
- const [configDlg, setConfigDlg] = useState(false);
-
- //Уведомление родителя о смене настроек источника данных
- const notifyChange = settings => onChange && onChange(settings);
-
- //При нажатии на настройку источника данных
- const handleSetup = () => setConfigDlg(true);
-
- //При нажатии на настройку источника данных
- const handleSetupOk = dataSource => {
- setConfigDlg(false);
- notifyChange(dataSource);
- };
-
- //При нажатии на настройку источника данных
- const handleSetupCancel = () => setConfigDlg(false);
-
- //При удалении настроек источника данных
- const handleDelete = () => notifyChange({ ...DATA_SOURCE_INITIAL });
-
- //Расчет флага "настроенности"
- const configured = dataSource?.type ? true : false;
-
- //Список аргументов
- const args =
- configured &&
- dataSource.arguments.map((argument, i) => (
-
- ));
-
- //Формирование представления
- return (
- <>
- {configDlg && (
-
- )}
- {configured && (
-
-
-
-
- {dataSource.type === DATA_SOURCE_TYPE.USER_PROC ? dataSource.userProc : "Источник без наименования"}
-
-
- {DATA_SOURCE_TYPE_NAME[dataSource.type] || "Неизвестный тип источника"}
-
-
- {args}
-
-
-
-
-
- delete
-
-
-
- )}
- {!configured && (
-
- )}
- >
- );
-};
-
-//Контроль свойств компонента - Источник данных
-DataSource.propTypes = {
- dataSource: DATA_SOURCE_SHAPE,
- valueProviders: PropTypes.object,
- onChange: PropTypes.func
-};
-
-//----------------
-//Интерфейс модуля
-//----------------
-
-export { STYLES, ARGUMENT_DATA_TYPE, DATA_SOURCE_TYPE, DATA_SOURCE_SHAPE, DATA_SOURCE_INITIAL, EditorBox, EditorSubHeader, ConfigDialog, DataSource };
diff --git a/app/panels/panels_editor/components/form/editor.js b/app/panels/panels_editor/components/form/editor.js
index 719a82b..4020b6c 100644
--- a/app/panels/panels_editor/components/form/editor.js
+++ b/app/panels/panels_editor/components/form/editor.js
@@ -27,7 +27,10 @@ import {
IconButton
} from "@mui/material"; //Интерфейсные элементы
import { ApplicationСtx } from "../../../../context/application"; //Контекст приложения
-import { STYLES as COMMON_STYLES, EditorBox, EditorSubHeader, ConfigDialog } from "../editors_common"; //Общие компоненты редакторов
+import { P8PEditorBox } from "../../../../components/editors/p8p_editor_box"; //Контейнер редактора
+import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Заголовок раздела редактора
+import { P8PConfigDialog } from "../../../../components/editors/p8p_config_dialog"; //Диалог настройки
+import { STYLES as COMMON_STYLES } from "../../../../components/editors/p8p_editors_common"; //Общие ресурсы редакторов
import { ITEM_SHAPE, ITEM_INITIAL, ITEMS_INITIAL, ORIENTATION } from "./common"; //Общие ресурсы и константы формы
//---------
@@ -122,7 +125,7 @@ const ItemEditor = ({ item = null, onOk = null, onCancel = null } = {}) => {
//Формирование представления
return (
-
+
@@ -172,7 +175,7 @@ const ItemEditor = ({ item = null, onOk = null, onCancel = null } = {}) => {
}}
/>
-
+
);
};
@@ -241,7 +244,7 @@ const FormEditor = ({ id, title = "", orientation = ORIENTATION.V, autoApply = f
//Формирование представления
return (
settings && (
-
+
{itemEditor.display && (
)}
-
+
Ориентация
@@ -268,7 +271,7 @@ const FormEditor = ({ id, title = "", orientation = ORIENTATION.V, autoApply = f
control={}
label={"Автоподтверждение"}
/>
-
+
{Array.isArray(settings?.items) &&
settings.items.length > 0 &&
settings.items.map((item, i) => (
@@ -284,7 +287,7 @@ const FormEditor = ({ id, title = "", orientation = ORIENTATION.V, autoApply = f
-
+
)
);
};
diff --git a/app/panels/panels_editor/components/form/view.js b/app/panels/panels_editor/components/form/view.js
index 77965c2..a24dd1f 100644
--- a/app/panels/panels_editor/components/form/view.js
+++ b/app/panels/panels_editor/components/form/view.js
@@ -11,9 +11,8 @@ import React, { useEffect, useState, useContext } from "react"; //Классы R
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Paper, Stack, Typography, Icon, TextField, IconButton, InputAdornment } from "@mui/material"; //Интерфейсные элементы
import { ApplicationСtx } from "../../../../context/application"; //Контекст приложения
-import { COMPONENT_MESSAGES, ComponentInlineMessage } from "../views_common"; //Общие компоненты представлений
+import { P8P_COMPONENT_INLINE_MESSAGE, P8PComponentInlineMessage } from "../../../../components/editors/p8p_component_inline_message"; //Информационное сообщение внутри компонента
import { ITEM_SHAPE, ITEMS_INITIAL, ORIENTATION } from "./common"; //Общие ресурсы и константы формы
-import "../../panels_editor.css"; //Стили редактора
//---------
//Константы
@@ -50,6 +49,7 @@ const FormItem = ({ item = null, fullWidth = false, value = "", onChange = null
inputParameters: [{ name: item.inputParameter, value }],
callBack: res => res.success && onChange && onChange(item.name, res.outParameters[item.outputParameter])
});
+
//Формирование представления
return (
item && (
@@ -144,7 +144,7 @@ const Form = ({ title = null, orientation = ORIENTATION.V, autoApply = false, it
) : (
-
+
)}
);
diff --git a/app/panels/panels_editor/components/indicator/editor.js b/app/panels/panels_editor/components/indicator/editor.js
index 5d8a3f4..81b4666 100644
--- a/app/panels/panels_editor/components/indicator/editor.js
+++ b/app/panels/panels_editor/components/indicator/editor.js
@@ -9,8 +9,10 @@
import React, { useEffect, useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
-import { DATA_SOURCE_SHAPE, DataSource, EditorBox, EditorSubHeader } from "../editors_common"; //Общие компоненты редакторов
-import "../../panels_editor.css"; //Стили редактора
+import { P8PEditorBox } from "../../../../components/editors/p8p_editor_box"; //Контейнер редактора
+import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Заголовок раздела редактора
+import { P8P_DATA_SOURCE_SHAPE } from "../../../../components/editors/p8p_data_source_common"; //Общие ресурсы источника данных
+import { P8PDataSource } from "../../../../components/editors/p8p_data_source"; //Источник данных
//-----------
//Тело модуля
@@ -34,17 +36,17 @@ const IndicatorEditor = ({ id, dataSource = null, valueProviders = {}, onSetting
//Формирование представления
return (
-
-
-
-
+
+
+
+
);
};
//Контроль свойств компонента - Индикатор (редактор настроек)
IndicatorEditor.propTypes = {
id: PropTypes.string.isRequired,
- dataSource: DATA_SOURCE_SHAPE,
+ dataSource: P8P_DATA_SOURCE_SHAPE,
valueProviders: PropTypes.object,
onSettingsChange: PropTypes.func
};
diff --git a/app/panels/panels_editor/components/indicator/view.js b/app/panels/panels_editor/components/indicator/view.js
index 82495ad..6526a5d 100644
--- a/app/panels/panels_editor/components/indicator/view.js
+++ b/app/panels/panels_editor/components/indicator/view.js
@@ -11,10 +11,13 @@ import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Paper } from "@mui/material"; //Интерфейсные элементы
import { P8PIndicator } from "../../../../components/p8p_indicator"; //Компонент индикатора
-import { useComponentDataSource } from "../components_hooks"; //Хуки для данных
-import { DATA_SOURCE_SHAPE } from "../editors_common"; //Общие объекты компонентов
-import { COMPONENT_MESSAGE_TYPE, COMPONENT_MESSAGES, ComponentInlineMessage } from "../views_common"; //Общие компоненты представлений
-import "../../panels_editor.css"; //Стили редактора
+import { useDataSource } from "../../../../components/editors/p8p_data_source_hooks"; //Хуки для данных
+import { P8P_DATA_SOURCE_SHAPE } from "../../../../components/editors/p8p_data_source_common"; //Общие ресурсы источника данных
+import {
+ P8P_COMPONENT_INLINE_MESSAGE_TYPE,
+ P8P_COMPONENT_INLINE_MESSAGE,
+ P8PComponentInlineMessage
+} from "../../../../components/editors/p8p_component_inline_message"; //Информационное сообщение внутри компонента
//---------
//Константы
@@ -38,7 +41,7 @@ const STYLES = {
//Индикатор (представление)
const Indicator = ({ dataSource = null, values = {} } = {}) => {
//Собственное состояние - данные
- const [data, error] = useComponentDataSource({ dataSource, values });
+ const [data, error] = useDataSource({ dataSource, values });
//Флаг настроенности индикатора
const haveConfing = dataSource?.stored ? true : false;
@@ -60,11 +63,11 @@ const Indicator = ({ dataSource = null, values = {} } = {}) => {
{haveConfing && haveData ? (
) : (
-
)}
@@ -73,7 +76,7 @@ const Indicator = ({ dataSource = null, values = {} } = {}) => {
//Контроль свойств компонента - Индикатор (представление)
Indicator.propTypes = {
- dataSource: DATA_SOURCE_SHAPE,
+ dataSource: P8P_DATA_SOURCE_SHAPE,
values: PropTypes.object
};
diff --git a/app/panels/panels_editor/components/table/editor.js b/app/panels/panels_editor/components/table/editor.js
index d0dba28..b61a220 100644
--- a/app/panels/panels_editor/components/table/editor.js
+++ b/app/panels/panels_editor/components/table/editor.js
@@ -9,8 +9,10 @@
import React, { useEffect, useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
-import { DATA_SOURCE_SHAPE, DataSource, EditorBox, EditorSubHeader } from "../editors_common"; //Общие компоненты редакторов
-import "../../panels_editor.css"; //Стили редактора
+import { P8PEditorBox } from "../../../../components/editors/p8p_editor_box"; //Контейнер редактора
+import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Заголовок раздела редактора
+import { P8P_DATA_SOURCE_SHAPE } from "../../../../components/editors/p8p_data_source_common"; //Общие ресурсы источника данных
+import { P8PDataSource } from "../../../../components/editors/p8p_data_source"; //Источник данных
//-----------
//Тело модуля
@@ -34,17 +36,17 @@ const TableEditor = ({ id, dataSource = null, valueProviders = {}, onSettingsCha
//Формирование представления
return (
-
-
-
-
+
+
+
+
);
};
//Контроль свойств компонента - Таблица (редактор настроек)
TableEditor.propTypes = {
id: PropTypes.string.isRequired,
- dataSource: DATA_SOURCE_SHAPE,
+ dataSource: P8P_DATA_SOURCE_SHAPE,
valueProviders: PropTypes.object,
onSettingsChange: PropTypes.func
};
diff --git a/app/panels/panels_editor/components/table/view.js b/app/panels/panels_editor/components/table/view.js
index 4b86d1c..d9b976f 100644
--- a/app/panels/panels_editor/components/table/view.js
+++ b/app/panels/panels_editor/components/table/view.js
@@ -13,10 +13,13 @@ import { Paper } from "@mui/material"; //Интерфейсные элемент
import { APP_STYLES } from "../../../../../app.styles"; //Типовые стили
import { P8PDataGrid } from "../../../../components/p8p_data_grid"; //Таблица данных
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../../../config_wrapper"; //Подключение компонентов к настройкам приложения
-import { useComponentDataSource } from "../components_hooks"; //Хуки для данных
-import { DATA_SOURCE_SHAPE } from "../editors_common"; //Общие объекты компонентов
-import { COMPONENT_MESSAGE_TYPE, COMPONENT_MESSAGES, ComponentInlineMessage } from "../views_common"; //Общие компоненты представлений
-import "../../panels_editor.css"; //Стили редактора
+import { useDataSource } from "../../../../components/editors/p8p_data_source_hooks"; //Хуки для данных
+import { P8P_DATA_SOURCE_SHAPE } from "../../../../components/editors/p8p_data_source_common"; //Общие ресурсы источника данных
+import {
+ P8P_COMPONENT_INLINE_MESSAGE_TYPE,
+ P8P_COMPONENT_INLINE_MESSAGE,
+ P8PComponentInlineMessage
+} from "../../../../components/editors/p8p_component_inline_message"; //Информационное сообщение внутри компонента
//---------
//Константы
@@ -45,7 +48,7 @@ const STYLES = {
//Таблица (представление)
const Table = ({ dataSource = null, values = {} } = {}) => {
//Собственное состояние - данные
- const [data, error] = useComponentDataSource({ dataSource, values });
+ const [data, error] = useDataSource({ dataSource, values });
//Флаг настроенности таблицы
const haveConfing = dataSource?.stored ? true : false;
@@ -72,11 +75,11 @@ const Table = ({ dataSource = null, values = {} } = {}) => {
containerComponentProps={{ sx: STYLES.DATA_GRID_CONTAINER, elevation: 0 }}
/>
) : (
-
)}
@@ -85,7 +88,7 @@ const Table = ({ dataSource = null, values = {} } = {}) => {
//Контроль свойств компонента - Таблица (представление)
Table.propTypes = {
- dataSource: DATA_SOURCE_SHAPE,
+ dataSource: P8P_DATA_SOURCE_SHAPE,
values: PropTypes.object
};
diff --git a/app/panels/panels_editor/layout_item.js b/app/panels/panels_editor/layout_item.js
index db6f650..f4754d4 100644
--- a/app/panels/panels_editor/layout_item.js
+++ b/app/panels/panels_editor/layout_item.js
@@ -10,7 +10,6 @@
import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { IconButton, Icon, Stack } from "@mui/material"; //Интерфейсные элементы
-import "./panels_editor.css"; //Кастомные стили
//---------
//Константы
diff --git a/app/panels/panels_editor/panels_editor.css b/app/panels/panels_editor/panels_editor.css
index 0729e89..8c8c221 100644
--- a/app/panels/panels_editor/panels_editor.css
+++ b/app/panels/panels_editor/panels_editor.css
@@ -12,17 +12,6 @@
border-radius: 4px;
}
-.component-editor__wrap {
-}
-
-.component-editor__container {
- padding: 10px;
-}
-
-.component-editor__divider {
- padding-top: 20px;
-}
-
.component-view__wrap {
height: 100%;
}
diff --git a/app/panels/panels_editor/panels_editor.js b/app/panels/panels_editor/panels_editor.js
index 04ce0a3..0af2219 100644
--- a/app/panels/panels_editor/panels_editor.js
+++ b/app/panels/panels_editor/panels_editor.js
@@ -9,9 +9,10 @@
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 { Box, Grid, Menu, MenuItem, Icon, Fab } from "@mui/material"; //Интерфейсные элементы
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Рабочая область приложения
+import { P8PEditorToolBar } from "../../components/editors/p8p_editor_toolbar"; //Панель инструментов редактора
import { genGUID } from "../../core/utils"; //Общие вспомогательные функции
import { LayoutItem } from "./layout_item"; //Элемент макета
import { ComponentView } from "./component_view"; //Представление компонента панели
@@ -19,6 +20,7 @@ import { ComponentEditor } from "./component_editor"; //Редактор сво
import { COMPONETNS } from "./components/components"; //Описание доступных компонентов
import "react-grid-layout/css/styles.css"; //Стили для адаптивного макета
import "react-resizable/css/styles.css"; //Стили для адаптивного макета
+import "./panels_editor.css"; //Стили редактора панелей
//---------
//Константы
@@ -140,9 +142,9 @@ const PanelsEditor = () => {
//При подключении к странице
useEffect(() => {
- addComponent(COMPONETNS[0]);
- addComponent(COMPONETNS[3]);
- addComponent(COMPONETNS[4]);
+ //addComponent(COMPONETNS[0]);
+ //addComponent(COMPONETNS[3]);
+ //addComponent(COMPONETNS[4]);
//addComponent(COMPONETNS[1]);
//addComponent(COMPONETNS[2]);
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -171,14 +173,16 @@ const PanelsEditor = () => {
//Панель инструмментов
const toolBar = (
-
-
- play_arrow
-
-
- add
-
-
+
);
//Генерация содержимого