From ef397b181841f3bb9804eee9b36c225ef03e42df Mon Sep 17 00:00:00 2001 From: Dollerino Date: Fri, 28 Mar 2025 13:41:02 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-929=20-=20=D0=92?= =?UTF-8?q?=D1=8B=D0=B2=D0=BE=D0=B4=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BE=D0=B1=20=D0=BE=D1=88=D0=B8=D0=B1?= =?UTF-8?q?=D0=BA=D0=B5=20=D0=B1=D0=B5=D0=B7=20=D1=81=D1=82=D1=8D=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=D1=8B=D0=B7=D0=BE=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.text.js | 2 ++ app/components/p8p_app_message.js | 39 +++++++++++++++++++++++++++---- app/context/backend.js | 8 ++++++- app/context/messaging.js | 12 +++++++--- app/context/messaging_reducer.js | 2 ++ app/core/utils.js | 29 +++++++++++++++++++++++ 6 files changed, 84 insertions(+), 8 deletions(-) diff --git a/app.text.js b/app.text.js index f6e8b7c..34bf853 100644 --- a/app.text.js +++ b/app.text.js @@ -29,6 +29,8 @@ export const BUTTONS = { OK: "ОК", //Ок CANCEL: "Отмена", //Отмена CLOSE: "Закрыть", //Сокрытие + ERR_MORE: "Подробнее", //Отображение подробного текста ошибки + HIDE: "Скрыть", //Скрытие информации CLEAR: "Очистить", //Очистка ORDER_ASC: "По возрастанию", //Сортировка по возрастанию ORDER_DESC: "По убыванию", //Сортировка по убыванию diff --git a/app/components/p8p_app_message.js b/app/components/p8p_app_message.js index df0d88f..8fbb4c1 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 && 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..ebc0a5c 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, errMsg.fullErrorText); + } throw e; } finally { if (loader !== false) hideLoader(); diff --git a/app/context/messaging.js b/app/context/messaging.js index b1522f0..8bb8be8 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, + ERR_MORE: PropTypes.string.isRequired, + HIDE: PropTypes.string.isRequired }); //---------------- @@ -56,12 +58,13 @@ 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, fullErrorText = null, msgOnOk = null, msgOnCancel = null) => + dispatch({ type: MSG_AT.SHOW_MSG, payload: { type, text, fullErrorText, msgOnOk, msgOnCancel } }), [] ); //Отображение сообщения - ошибка - const showMsgErr = useCallback((text, msgOnOk = null) => showMsg(MSG_TYPE.ERR, text, msgOnOk), [showMsg]); + const showMsgErr = useCallback((text, fullErrorText = null, msgOnOk = null) => showMsg(MSG_TYPE.ERR, text, fullErrorText, msgOnOk), [showMsg]); //Отображение сообщения - информация const showMsgInfo = useCallback((text, msgOnOk = null) => showMsg(MSG_TYPE.INFO, text, msgOnOk), [showMsg]); @@ -126,6 +129,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 +138,8 @@ export const MessagingContext = ({ titles, texts, buttons, children }) => { cancelBtn={state.msgType == MSG_TYPE.WARN} onCancel={handleMessageCancelClick} cancelBtnCaption={buttons.CANCEL} + showErrMoreCaption={buttons.ERR_MORE} + 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 }; From a62daa4407932bd7f4979ff2918fd08565472bd8 Mon Sep 17 00:00:00 2001 From: Dollerino Date: Fri, 28 Mar 2025 13:57:36 +0300 Subject: [PATCH 2/3] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5d89ae3..255ec28 100644 --- a/README.md +++ b/README.md @@ -1099,6 +1099,7 @@ const Mui = ({ title }) => { `type` - обязательный, строка, тип отображаемого сообщения, `information|warning|error` (см. константу `MSG_TYPE` в "app/context/messaging_reducer" и константу `P8P_APP_MESSAGE_VARIANT` в "app/components/p8p_app_message")\ `text` - обязательный, строка, текст отображаемого сообщения\ +`fullErrorText` - необязательный, строка, полный текст ошибки, используется только при `type="error"`. Если параметр указан, то в окно ошибки выводится кнопка "Подробнее", по нажатию на которую будет отображаться текст, указанный в данном параметре\ `msgOnOk` - необязательный, функция, будет вызвана при нажатии на "ОК"/"ЗАКРЫТЬ" в сообщении `msgOnCancel` - необязательный, функция, будет вызвана при нажатии на "ОТМЕНА" в сообщении (только для сообщений типа `warning`) From 6a41686a842978b6c1761df3d6215fb9da17440f Mon Sep 17 00:00:00 2001 From: Dollerino Date: Mon, 31 Mar 2025 19:04:11 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-929=20-=20=D0=92?= =?UTF-8?q?=D1=8B=D0=B2=D0=BE=D0=B4=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BE=D0=B1=20=D0=BE=D1=88=D0=B8=D0=B1?= =?UTF-8?q?=D0=BA=D0=B5=20=D0=B1=D0=B5=D0=B7=20=D1=81=D1=82=D1=8D=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=D1=8B=D0=B7=D0=BE=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++++--- app.text.js | 2 +- app/components/p8p_app_message.js | 2 +- app/context/backend.js | 2 +- app/context/messaging.js | 13 ++++++++----- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 255ec28..1ee3b24 100644 --- a/README.md +++ b/README.md @@ -1099,9 +1099,9 @@ const Mui = ({ title }) => { `type` - обязательный, строка, тип отображаемого сообщения, `information|warning|error` (см. константу `MSG_TYPE` в "app/context/messaging_reducer" и константу `P8P_APP_MESSAGE_VARIANT` в "app/components/p8p_app_message")\ `text` - обязательный, строка, текст отображаемого сообщения\ -`fullErrorText` - необязательный, строка, полный текст ошибки, используется только при `type="error"`. Если параметр указан, то в окно ошибки выводится кнопка "Подробнее", по нажатию на которую будет отображаться текст, указанный в данном параметре\ `msgOnOk` - необязательный, функция, будет вызвана при нажатии на "ОК"/"ЗАКРЫТЬ" в сообщении -`msgOnCancel` - необязательный, функция, будет вызвана при нажатии на "ОТМЕНА" в сообщении (только для сообщений типа `warning`) +`msgOnCancel` - необязательный, функция, будет вызвана при нажатии на "ОТМЕНА" в сообщении (только для сообщений типа `warning`)\ +`fullErrorText` - необязательный, строка, полный текст ошибки, используется только при `type="error"`. Если параметр указан, то в окно ошибки выводится кнопка "Подробнее", по нажатию на которую будет отображаться текст, указанный в данном параметре **Результат:** функция не возвращает значимого результата @@ -1109,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 34bf853..2c153ec 100644 --- a/app.text.js +++ b/app.text.js @@ -29,7 +29,7 @@ export const BUTTONS = { OK: "ОК", //Ок CANCEL: "Отмена", //Отмена CLOSE: "Закрыть", //Сокрытие - ERR_MORE: "Подробнее", //Отображение подробного текста ошибки + DETAIL: "Подробнее", //Отображение подробного текста HIDE: "Скрыть", //Скрытие информации CLEAR: "Очистить", //Очистка ORDER_ASC: "По возрастанию", //Сортировка по возрастанию diff --git a/app/components/p8p_app_message.js b/app/components/p8p_app_message.js index 8fbb4c1..c58acb1 100644 --- a/app/components/p8p_app_message.js +++ b/app/components/p8p_app_message.js @@ -127,7 +127,7 @@ const P8PAppMessage = ({ //Кнопка Подробнее let fullErrorTextBtn; - if (fullErrorText && variant === P8P_APP_MESSAGE_VARIANT.ERR) + if (fullErrorText && showErrMoreCaption && hideErrMoreCaption && variant === P8P_APP_MESSAGE_VARIANT.ERR) fullErrorTextBtn = (