diff --git a/README.md b/README.md
index 5d89ae3..1ee3b24 100644
--- a/README.md
+++ b/README.md
@@ -1100,7 +1100,8 @@ const Mui = ({ title }) => {
`type` - обязательный, строка, тип отображаемого сообщения, `information|warning|error` (см. константу `MSG_TYPE` в "app/context/messaging_reducer" и константу `P8P_APP_MESSAGE_VARIANT` в "app/components/p8p_app_message")\
`text` - обязательный, строка, текст отображаемого сообщения\
`msgOnOk` - необязательный, функция, будет вызвана при нажатии на "ОК"/"ЗАКРЫТЬ" в сообщении
-`msgOnCancel` - необязательный, функция, будет вызвана при нажатии на "ОТМЕНА" в сообщении (только для сообщений типа `warning`)
+`msgOnCancel` - необязательный, функция, будет вызвана при нажатии на "ОТМЕНА" в сообщении (только для сообщений типа `warning`)\
+`fullErrorText` - необязательный, строка, полный текст ошибки, используется только при `type="error"`. Если параметр указан, то в окно ошибки выводится кнопка "Подробнее", по нажатию на которую будет отображаться текст, указанный в данном параметре
**Результат:** функция не возвращает значимого результата
@@ -1108,7 +1109,11 @@ const Mui = ({ title }) => {
Декоратор для `showMsg`, отображает модальное окно сообщения типа "Ошибка" (`type="error"`).
-**Входные параметры:** аналогично `showMsg`
+**Входные параметры:**
+
+`text` - обязательный, строка, текст отображаемого сообщения\
+`msgOnOk` - необязательный, функция, будет вызвана при нажатии на "ЗАКРЫТЬ" в сообщении
+`fullErrorText` - необязательный, строка, полный текст ошибки. Если параметр указан, то в окно ошибки выводится кнопка "Подробнее", по нажатию на которую будет отображаться текст, указанный в данном параметре
**Результат:** аналогично `showMsg`
diff --git a/app.text.js b/app.text.js
index f6e8b7c..2c153ec 100644
--- a/app.text.js
+++ b/app.text.js
@@ -29,6 +29,8 @@ export const BUTTONS = {
OK: "ОК", //Ок
CANCEL: "Отмена", //Отмена
CLOSE: "Закрыть", //Сокрытие
+ DETAIL: "Подробнее", //Отображение подробного текста
+ HIDE: "Скрыть", //Скрытие информации
CLEAR: "Очистить", //Очистка
ORDER_ASC: "По возрастанию", //Сортировка по возрастанию
ORDER_DESC: "По убыванию", //Сортировка по убыванию
diff --git a/app/components/p8p_app_message.js b/app/components/p8p_app_message.js
index df0d88f..c58acb1 100644
--- a/app/components/p8p_app_message.js
+++ b/app/components/p8p_app_message.js
@@ -7,7 +7,7 @@
//Подключение библиотек
//---------------------
-import React from "react"; //Классы React
+import React, { useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import Dialog from "@mui/material/Dialog"; //базовый класс диалога Material UI
import DialogTitle from "@mui/material/DialogTitle"; //Заголовок диалога
@@ -66,7 +66,25 @@ const STYLES = {
//-----------
//Сообщение
-const P8PAppMessage = ({ variant, title, titleText, cancelBtn, onCancel, cancelBtnCaption, okBtn, onOk, okBtnCaption, open, text }) => {
+const P8PAppMessage = ({
+ variant,
+ title,
+ titleText,
+ cancelBtn,
+ onCancel,
+ cancelBtnCaption,
+ okBtn,
+ onOk,
+ okBtnCaption,
+ open,
+ text,
+ fullErrorText,
+ showErrMoreCaption,
+ hideErrMoreCaption
+}) => {
+ //Состояние подробной информации об ошибке
+ const [showFullErrorText, setShowFullErrorText] = useState(false);
+
//Подбор стиля и ресурсов
let style = STYLES.INFO;
switch (variant) {
@@ -107,11 +125,21 @@ const P8PAppMessage = ({ variant, title, titleText, cancelBtn, onCancel, cancelB
);
+ //Кнопка Подробнее
+ let fullErrorTextBtn;
+ if (fullErrorText && showErrMoreCaption && hideErrMoreCaption && variant === P8P_APP_MESSAGE_VARIANT.ERR)
+ fullErrorTextBtn = (
+
+ );
+
//Все действия
let actionsPart;
if (cancelBtnPart || okBtnPart)
actionsPart = (
+ {fullErrorTextBtn}
{okBtnPart}
{cancelBtnPart}
@@ -128,7 +156,7 @@ const P8PAppMessage = ({ variant, title, titleText, cancelBtn, onCancel, cancelB
{titlePart}
- {text}
+ {!showFullErrorText ? text : fullErrorText}
{actionsPart}
@@ -148,7 +176,10 @@ P8PAppMessage.propTypes = {
onOk: PropTypes.func,
okBtnCaption: PropTypes.string,
open: PropTypes.bool,
- text: PropTypes.string
+ text: PropTypes.string,
+ fullErrorText: PropTypes.string,
+ showErrMoreCaption: PropTypes.string,
+ hideErrMoreCaption: PropTypes.string
};
//Встроенное сообщение
diff --git a/app/context/backend.js b/app/context/backend.js
index d6192a7..5e0e4f3 100644
--- a/app/context/backend.js
+++ b/app/context/backend.js
@@ -10,6 +10,7 @@
import React, { createContext, useContext, useCallback } from "react"; //ReactJS
import PropTypes from "prop-types"; //Контроль свойств компонента
import { MessagingСtx } from "./messaging"; //Контекст сообщений
+import { formatErrorMessage } from "../core/utils"; //Вспомогательные функции
//---------
//Константы
@@ -80,7 +81,12 @@ export const BackEndContext = ({ client, children }) => {
if (fullResponse === true || isRespErr(result)) return result;
else return result.XPAYLOAD;
} catch (e) {
- if (showErrorMessage) showMsgErr(e.message);
+ if (showErrorMessage) {
+ //Разбираем текст ошибки
+ let errMsg = formatErrorMessage(e.message);
+ //Отображаем ошибку
+ showMsgErr(errMsg.text, null, errMsg.fullErrorText);
+ }
throw e;
} finally {
if (loader !== false) hideLoader();
diff --git a/app/context/messaging.js b/app/context/messaging.js
index b1522f0..bd69c95 100644
--- a/app/context/messaging.js
+++ b/app/context/messaging.js
@@ -33,7 +33,9 @@ const MESSAGING_CONTEXT_TEXTS_SHAPE = PropTypes.shape({
const MESSAGING_CONTEXT_BUTTONS_SHAPE = PropTypes.shape({
CLOSE: PropTypes.string.isRequired,
OK: PropTypes.string.isRequired,
- CANCEL: PropTypes.string.isRequired
+ CANCEL: PropTypes.string.isRequired,
+ DETAIL: PropTypes.string.isRequired,
+ HIDE: PropTypes.string.isRequired
});
//----------------
@@ -56,12 +58,16 @@ export const MessagingContext = ({ titles, texts, buttons, children }) => {
//Отображение сообщения
const showMsg = useCallback(
- (type, text, msgOnOk = null, msgOnCancel = null) => dispatch({ type: MSG_AT.SHOW_MSG, payload: { type, text, msgOnOk, msgOnCancel } }),
+ (type, text, msgOnOk = null, msgOnCancel = null, fullErrorText = null) =>
+ dispatch({ type: MSG_AT.SHOW_MSG, payload: { type, text, msgOnOk, msgOnCancel, fullErrorText } }),
[]
);
//Отображение сообщения - ошибка
- const showMsgErr = useCallback((text, msgOnOk = null) => showMsg(MSG_TYPE.ERR, text, msgOnOk), [showMsg]);
+ const showMsgErr = useCallback(
+ (text, msgOnOk = null, fullErrorText = null) => showMsg(MSG_TYPE.ERR, text, msgOnOk, null, fullErrorText),
+ [showMsg]
+ );
//Отображение сообщения - информация
const showMsgInfo = useCallback((text, msgOnOk = null) => showMsg(MSG_TYPE.INFO, text, msgOnOk), [showMsg]);
@@ -126,6 +132,7 @@ export const MessagingContext = ({ titles, texts, buttons, children }) => {
open={true}
variant={state.msgType}
text={state.msgText}
+ fullErrorText={state.msgFullErrorText}
title
titleText={state.msgType == MSG_TYPE.ERR ? titles.ERR : state.msgType == MSG_TYPE.WARN ? titles.WARN : titles.INFO}
okBtn={true}
@@ -134,6 +141,8 @@ export const MessagingContext = ({ titles, texts, buttons, children }) => {
cancelBtn={state.msgType == MSG_TYPE.WARN}
onCancel={handleMessageCancelClick}
cancelBtnCaption={buttons.CANCEL}
+ showErrMoreCaption={buttons.DETAIL}
+ hideErrMoreCaption={buttons.HIDE}
/>
) : null}
{children}
diff --git a/app/context/messaging_reducer.js b/app/context/messaging_reducer.js
index b6bd068..c5d7e69 100644
--- a/app/context/messaging_reducer.js
+++ b/app/context/messaging_reducer.js
@@ -35,6 +35,7 @@ const INITIAL_STATE = {
msg: false,
msgType: MSG_TYPE.ERR,
msgText: null,
+ msgFullErrorText: null,
msgOnOk: null,
msgOnCancel: null
};
@@ -59,6 +60,7 @@ const handlers = {
msg: true,
msgType: payload.type || MSG_TYPE.APP_ERR,
msgText: payload.text,
+ msgFullErrorText: payload.fullErrorText,
msgOnOk: payload.msgOnOk,
msgOnCancel: payload.msgOnCancel
}),
diff --git a/app/core/utils.js b/app/core/utils.js
index 65e24b3..95b20ae 100644
--- a/app/core/utils.js
+++ b/app/core/utils.js
@@ -158,6 +158,34 @@ const formatDateJSONDateOnly = value => (value ? dayjs(value).format("YYYY-MM-DD
//Форматирование числа в "Денежном" формате РФ
const formatNumberRFCurrency = value => (hasValue(value) ? new Intl.NumberFormat("ru-RU", { minimumFractionDigits: 2 }).format(value) : null);
+//Форматирование текста ошибки
+const formatErrorMessage = errorMsg => {
+ //Инициализируем текст заголовка ошибки
+ let text = "";
+ //Пробуем извлечь заголовок текста ошибки
+ try {
+ //Если это ошибка Oracle
+ if (errorMsg.match(/^ORA-/)) {
+ //Считываем первую строку с заголовочным текстом ошибки
+ text = errorMsg.match(/^.*(?=(\nORA-))/)[0];
+ //Убираем лишнюю информацию и пробелы
+ text = text.replace(/ORA-\d*:/g, "").trim();
+ }
+ //Если это ошибка PG
+ if (errorMsg.match(/^SQL Error/)) {
+ //Считываем первую строку с заголовочным текстом ошибки
+ text = errorMsg.match(/.*(?=(\n.*Where)|(.*Where))/)[0];
+ //Убираем лишнюю информацию и пробелы
+ text = text.replace(/SQL Error \[\d*\]: ERROR:/g, "").trim();
+ }
+ } catch {
+ //Если произошла ошибка - оставляем полный текст ошибки
+ text = errorMsg;
+ }
+ //Возвращаем результат
+ return { text: text || errorMsg, fullErrorText: text ? errorMsg : null };
+};
+
//Формирование уникального идентификатора
const genGUID = () =>
"10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
@@ -178,5 +206,6 @@ export {
formatDateTimeRF,
formatDateJSONDateOnly,
formatNumberRFCurrency,
+ formatErrorMessage,
genGUID
};