# P8-Panels
# "Панели" расширение к "ПАРУС 8 Онлайн"
## Оглавление
[Термины и сокращения](#термины-и-сокращения)\
[I. Назначение](#i-назначение)\
[II. Состав](#ii-состав)\
[III. Требования к разработчику](#iii-требования-к-разработчику)\
[IV. Установка](#iv-установка)\
[V. Подключение панелей](#v-подключение-панелей)\
[VI. Разработка панелей](#vi-разработка-панелей)
## Термины и сокращения
**Система** - "ПАРУС 8 Предприятие"\
**БД** - База Данных\
**СУБД** - Система Управления Базами Данных\
**Расширение** - программный комплекс, дополняющий функциональность той или иной программной системы. В контексте данного документа (если не указано иное) - описываемое расширение "Панели".\
**Фреймворк** - программная платформа, определяющая структуру программной системы, программное обеспечение, облегчающее разработку и объединение разных компонентов большого программного проекта. В контексте данного документа (если не указано иное) - описываемое расширение "Панели".\
**Панель** - представление данных и функций Системы, реализованное с применением описываемого фреймворка\
**SPA** - Single Page Application - технология разработки WEB-приложений, предполагающая динамическую генерацию интерфейса внутри одного HTML-документа, отображаемого браузером\
**HTML** - HyperText Markup Language — язык гипертекстовой разметки\
**CSS** - Cascading Style Sheets - каскадные таблицы стилей\
**DOM** - Document Object Model - объектная модель документа (в контексте данного документа - HTML)\
**JS** - JavaScript — мультипарадигменный интерпретируемый язык программирования\
**JSX** - JavaScript eXtension - расширение JavaScript, которое позволяет создавать деревья DOM с использованием синтаксиса, подобного XML\
**АРМ** - Автоматизированное Рабочее Место
## I. Назначение
Расширение представляет собой фреймворк, основной задачей которого является сокращение времени разработки нестандартных графических интерфейсов и панелей мониторинга, работающих в составе WEB-приложения "ПАРУС 8 Онлайн".
## II. Состав
В расширение входят:
- Библиотека расширения "P8-Panels-ParusOnlineExt.dll" для сервера приложений "ПАРУС 8 Онлайн" - обеспечивает низкоуровневое взаимодействие разрабатываемых панелей с Системой
- Хранимые объекты сервера БД Системы, обеспечивающие обмен данными между панелями и учётными регистрами Системы
- API для высокоуровневого взаимодействия с сервером БД Системы
- API для взаимодействия разрабатываемых панелей с WEB-приложением "ПАРУС 8 Онлайн"
- WEB-приложение "Парус 8 - Панели мониторинга", являющееся "точкой входа" для подключения реализуемых панелей, включающее в себя:
- Подключенные и настроенные библиотеки ["React"](https://react.dev/), ["React-Router"](https://reactrouter.com/), ["MUI"](https://mui.com/)
- Настроенный транспайлер ["Babel"](https://babeljs.io/)
- Настроенный сборщик WEB-приложений ["WebPack"](https://webpack.js.org/)
- Настроенный статический анализатор кода ["ESLint"]()
- Настройки среды разработки ["Visual Studio Code"](https://code.visualstudio.com/)
- Готовый контекст React-приложения
- Компоненты для отображения единого бокового меню подключенных панелей, галереи подключенных панелей, интеграции в рабочий стол WEB-приложения "ПАРУС 8 Онлайн"
- Готовые панели мониторинга для ряда прикланых приложений Системы
## III. Требования к разработчику
Для успешной разработки собственных панелей, с применением описываемого фреймворка потребуются знания следующих технологий:
- HTML, CSS, JS, JSX
- Разработка SPA WEB-приложений
- Знакомство с основами работы перечисленных выше библиотек и системных средств (в первую очередь "React")
- Знание архитектуры Системы, принципов работы и организации её серверной части
На видеохостинге YouTube можно ознакомиться с уроками и обучающими курсами по большинству из перечисленных технологий. Например, с [этими](https://www.youtube.com/results?search_query=%D0%BF%D0%BE%D0%BB%D0%BD%D1%8B%D0%B9+%D0%BA%D1%83%D1%80%D1%81+react).
## IV. Установка
1. Установите сервер приложений "ПАРУС 8 Онлайн" согласно документации (см. "Парус-Онлайн 2. Часть 1. Установка ГГГГ.ММ.docx").
2. Разместите на диске сервера приложений библиотеку расширения "P8-Panels-ParusOnlineExt", для этого скопируйте содержимое папки "bin" из [репозитория расширения "P8-Panels-ParusOnlineExt"](https://github.com/CITKParus/P8-Panels-ParusOnlineExt), например, в каталог "C:\p8web20\Ext\P8-Panels-ParusOnlineExt".
3. Подключите библиотеку расширения к серверу приложений "ПАРУС 8 Онлайн". Для этого добавьте ссылку на библиотеку в файл "Config\extensions.config" сервера приложений:
```
```
Где:
- `rootPath="c:\p8web20\Ext\"` - атрибут, указывающий на корневой каталог хранения расширений для сервера приложений "ПАРУС 8 Онлайн"
- `path="P8-Panels-ParusOnlineExt\bin\P8-Panels-ParusOnlineExt.dll"` - атрибут, указывающий на каталог размещения библиотеки расширения "Панели" относительного коревого `rootPath`
4. Установите в файле конфигурации "PrecompiledApp.config" сервера приложений атрибут `updatable` в `true`:
```
```
5. Разместите WEB-приложение "Парус 8 - Панели мониторинга" на сервере приложений "ПАРУС 8 Онлайн". Для этого в каталоге "Modules" сервера приложений создайте подкаталог "P8-Panels" и проведите клонирование репозитория ["P8-Panels"](https://github.com/CITKParus/P8-Panels) в него:
```
git clone https://github.com/CITKParus/P8-Panels.git
```
6. Проведите компиляцию хранимых объектов БД из каталога "db" клонированного репозитория (компиляцию проводить под пользователем-владельцем схемы серверной части Системы, с последующей перекомпиляцией зависимых инвалидных объектов), затем исполните скрипт "grants.sql", размещённый в этом же каталоге.
7. Перезапустите сервер приложений "ПАРУС 8 Онлайн"
## V. Подключение панелей
Файл "p8panels.config", располагаемый в каталоге "Config" сервера приложений "ПАРУС 8 Онлайн", определяет какие панели подключены к WEB-приложению, порядок формирования пунктов главного меню "ПАРУС 8 Онлайн" для доступа к подключенным панелям, состав галереи панелей и бокового меню навигации WEB-приложения "Парус 8 - Панели мониторинга", работающего в контексте "ПАРУС 8 Онлайн".

В корневом каталоге репозитория ["P8-Panels"](https://github.com/CITKParus/P8-Panels) расположен файл "p8panels.config", содержащий конфигурацию поставляемых с расширением типовых панелей.
Данный файл конфигурации необходимо разместить локально, в каталоге "Config" сервера приложений "ПАРУС 8 Онлайн".
Например, если сервер приложений установлен в "c:\p8web20\WebClient", то путь к "p8panels.config" должен быть "c:\p8web20\WebClient\Config\p8panels.config".
Рассмотрим формат файла конфигурации панелей на примере. Ниже приведён фрагмет "p8panels.config" из поставки расширения.
```
...
...
```
Настройки хранятся в формате XML. Корневым тэгом документа должен быть `CITK.P8Panels`. Дочерними для него могут быть две ветки конфигурации:
- `MenuItems` - настройка пунктов главного меню WEB-приложения "ПАРУС 8 Online"
- `Panels` - общий список панелей, подключаемых к приложению (не все панели обязательно выводить в виде пунктов меню)
`MenuItems` состоит из элементов `App`, каждый из которых определяет для какого из приложений Системы описываются пункты меню. `MenuItems` может содержать несколько элементов `App`. Каждый элемент `App` должен иметь обязательный атрибут `name`, определяющий код приложения Системы (см. колонку `APPCODE` в таблице `APPLIST`), в которое будут добавлены пункты меню. Дочерними для элемента `App` являются элементы `MenuItem`, каждый из которых описывает создаваемый расширением пункт меню. `App` может содержать несколько `MenuItem`. Каждый из `MenuItem` может иметь следующие атрибуты:
- `parent` - обязательный, содержит GUID родительского пункта меню, к которому будет добавлен описываемый дочерний пункт (см. `P_MENUS_CREATE_*_MENU`, где `*` - код приложения Системы)
- `separator` - необязательный, принимает значения "true" или "false", если "true" - создаваемый пункт меню будет разделителем, остальные атрибуты, описанные ниже будут проигнорированы
- `name` - необязательный для `separator="true"`, в прочих случаях - обязательный, уникальное имя пункта меню
- `caption` - необязательный для `separator="true"`, в прочих случаях - обязательный, видимый текст пункта меню
- `panelName` - необязательный для `separator="true"` или если указан атрибут `url`, в прочих случаях - обязательный, определяет код панели, открываемой при выборе данного пункта меню конечным пользователем (коды панелей объявляются в секции `Panels` данного файла конфигурации, описана ниже)
- `url` - необязательный для `separator="true"` или если указан атрибут `panelName`, в прочих случаях - обязательный, определяет URL, который будет открыт в отдельной закладке "ПАРУС 8 Онлайн" при выборе данного пункта меню конечным пользователем (в приведённом примере, для пункта меню "ShowPrjPanelsRoot" открывает домашнюю страницу WEB-приложения "Парус 8 - Панели мониторинга", отображающую галерею доступных панелей, см. ниже описание атрибута `urlBase` элемента `Panels`)
`Panels` - содержит список элементов `Panel`, описывающих подключенные панели. Элемент `Panels` имеет атрибут `urlBase`, определяющий корневой URL WEB-приложения "Парус 8 - Панели мониторинга", относительно него формируются URL панелей. Значение `urlBase` определяется физическим расположением WEB-приложения "Парус 8 - Панели мониторинга" на диске сервера приложений (см. пункт 5 в главе "IV. Установка"). В данном примеры, файлы WEB-приложения распологаются в каталоге "Modules/p8-panels" сервера приложений. Каждый из элементов `Panel`, дочерних для `Panels`, описывает одну панель и имеет следующие атрибуты:
- `name` - обязательный, строка, указывается латиницей, определяет уникальное имя панели
- `group` - необязательный, строка, указывается кириллицей, определяет имя группы, в которую входит панель (применяется при формировании галереи панелей, главного меню панелей и ссылок на рабочем столе)
- `caption` - обязательный, строка, видимое наименование панели (применяется в галереи панелей, главном меню панелей, ссылках на рабочем столе, заголовках закладок)
- `desc` - необязательный, строка,
- `url` - обязательный, строка, указывается латиницей, относительй URL панели (по адресу `Panel.urlBase` + `Panel.Panels.url` сервер приложений "ПАРУС 8 Онлайн" будет выдавать HTML-страницу панели), для простоты навигации может повторять значение атрибута `path`
- `path` - обязательный, строка, путь к исходному коду панели в структуре каталогов WEB-приложения "Парус 8 - Панели мониторинга" (панели должны размещаться в "app/panels", в данном атрибуте указыватся только имя каталога, созданного для панели в "app/panels")
- `icon` - обязательный, строка, код иконки панели из символов шрифта [Google Material Icons](https://fonts.google.com/icons?icon.set=Material+Icons) (применяется при формировании галереи панелей, главного меню панелей и ссылок на рабочем столе)
- `showInPanelsList` - обязательный, принимает значения "true" или "false", определяет отображение ссылки на панель в галереи панелей, главном меню панелей, виджете рабочего стола
- `preview` - полный путь и имя файла из каталога "img" WEB-приложения "Парус 8 - Панели мониторинга" (в каталог могут быть добавлены пользовательские изображения), служит в качестве изображения панели в галерее панелей
На рисунках ниже проиллюстрировано применение атрибутов элемента `Panel`.


Подключение разработанных пользователем панелей осуществляется путём добавления элементов `Panels` в файл конфигурации (при необходимости и элементов `App\MenuItems`, если предполагается открытие панели через главное меню WEB-приложения "ПАРУС 8 Онлайн").
Изменения файла конфигурации в части элементов `MenuItems` требуют перезапуска сервера приложений "ПАРУС 8 Онлайн" и завершения/начала сеансов конечных пользователей.
> **Будьте внимательны при обновлении:** если в локальном файле "p8panels.config" содержится конфигурация пользовательских панелей, то его нельзя заменять копированием дистрибутивной версии файла при обновлении - будут утеряны сделанные настройки. В этом случае файл следует модифицировать экспертным путём, добавив в локальный "p8panels.config" изменения из дистрибутивного вручную.
## VI. Разработка панелей
> **Внимание:** данное руководство не является обучающим курсом по WEB-разработке как таковой. Изложенные ниже сведения о порядке реализации пользовательских панелей, даны с учётом приведённых ранее требований к разработчику.
### Общие сведения
Расширение "Панели" позволяет подключать нестандартные интерфейсы разрабатываемые на местах, без привлечения вендора. Это могут быть не только панели мониторинга, но и формы ввода данных, различные АРМ, выполняющие бизнес-функции в Системе.
С точки зрения клиенсткой части, Панели представляют собой функциональные компоненты React, автоматически (благодаря описанному выше файлу конфигурации) встраиваемые в систему маршрутизации WEB-приложения "Парус 8 - Панели мониторинга" (далее "приложения" или "WEB-приложения", если контекст явно не указывает на иное). Каждая панель состоит из:
- Набора JS-объектов и функций, управляющих состоянием панели
- Функций для обмена данными с сервером БД Системы и выполнения бизнес-процедур в ней
- JSX разметки, отражающей смену состояния панели
Такая структура исходного кода панели продиктована архитектурными требованиями к функциональным React-компонентам. Каждая панель (и все необходимые для её функционирования JS-модули и вспомогательный файлы) размещается в отдельном каталоге (см. выше - "app/panels", здесь и далее каталоги указаны относительно корневого каталога размещения приложения, если явно не указано иное) WEB-приложения "Парус 8 - Панели мониторинга".
Каждая панель должна иметь в составе "index.js" - точку входа по умолчанию. "index.js" должен экспортировать фунциональный React-компонент панели с имененем `RootClass` (см. для примера "app/panels/prj_fin/index.js").
После добавления новых панелей в состав приложения необходима его "пересборка". Для этого предусмотрены преднастроенные скрипты `dev` и `build`. Скрипты размещены в секции `scripts` файла зависимостей `package.json` WEB-приложения. Исполнение скриптов сборки выполняется через пакетный менеджер `npm` из корневого каталога приложения:
```
REM Запуск скрипта для отладочной сборки
c:\inetpub\p8web20\WebClient\Modules\P8-Panels>npm run dev
REM Запуск скрипта финальной сборки
c:\inetpub\p8web20\WebClient\Modules\P8-Panels>npm run build
```
Скрипт финальной сборки формирует обновлённое WEB-приложение в каталоге "dist" и завершает работу. Скрипт отладочной сборки обновляет WEB-приложение в каталоге "dist" и остаётся в активном режиме, "слушая" измнения файлов исходного кода приложения и автоматически обновляя "dist", если таковые изменения будут зафиксированы. Это позволяет отлаживать панели не выполняя пересборку вручную.
После пересборки обновлённые/новые панели доступны конечному пользователю для эксплуатации через WEB-приложение "ПАРУС 8 Онлайн".
Серверная часть любой из панелей - набор хранимых процедур/функций/пакетов БД Системы. Состав объектов, их алгоритмы, входные параметры и выходные данные зависят от специфики панели и специально не регламентируются. Необходимо понимать, что с помощью специального API из клиентской JS-функции панели можно обращаться к хранимым объектам БД - исполнять их, передавать значения входных параметров (например, считанные из форм ввода, размещённых на панели), получать и отображать на панели значения выходных параметров исполненного серверного объекта (в виде таблиц, карточек, графиков и прочими способами, отвечающими функциональным требованиям реализуемой панели).
### API для взаимодействия с сервером "ПАРУС 8 Предприятие"
Для исполнения хранимых процедур/функций БД Системы в составе расширения предусмотрен специальный API. Его подключение к компоненте панели осуществляется через контекст `BackEndСtx` ("app/context/backend.js").
В состав API входят:
- `SERV_DATA_TYPE_STR` - константа для типа данных "строка", при описании параметров исполняемых хранимых объектов
- `SERV_DATA_TYPE_NUMB` - константа для типа данных "число", при описании параметров исполняемых хранимых объектов
- `SERV_DATA_TYPE_DATE` - константа для типа данных "дата", при описании параметров исполняемых хранимых объектов
- `SERV_DATA_TYPE_CLOB` - константа для типа данных "текст", при описании параметров исполняемых хранимых объектов
- `isRespErr` - проверка результата исполнения серверного объекта на наличие ошибок
- `getRespErrMessage` - получение ошибки исполнения серверного объекта
- `getRespPayload` - получение выходных значений, полученных после успешного исполнения
- `executeStored` - асинхронное исполнение хранимой процедуры/функции БД Системы
- `getConfig` - асинхронное считывание параметров конфигурации, определённых в "p8panels.config" (возвращает их JSON-представление)
При формировании ответов, функции, получающие данные с сервера, возвращают типовые значения:
```
//Типовой успех
{
SSTATUS: "OK",
XPAYLOAD: Object
}
//Типовая ошибка
{
SSTATUS: "ERR",
SMESSAGE: String
}
```
Где:
- `SSTATUS` - строка, состояние исполнения (`"OK"` - успех или `"ERR"` - ошибка)
- `XPAYLOAD` - объект, полезная нагрузка, данные полученные от серверного объекта (отсутствует, если `SSTATUS = "ERR"`)
- `SMESSAGE` - строка, текст сообщения об ошибке (отсутствует, если `SSTATUS = "OK"`)
#### `boolean isRespErr(Object)`
**Входные параметры:** обязательный, объект, результат вызова `executeStored`
**Результат:** `true` - если полученный на вход результат исполнения `executeStored` содержит ошибку, `false` - в остальных случаях
#### `String getRespErrMessage(Object)`
**Входные параметры:** обязательный, объект, результат вызова `executeStored`
**Результат:** текст сообщения об ошибке - если полученный на вход результат исполнения `executeStored` содержит ошибку, пустая строка (`""`) - в остальных случаях
#### `Object getRespPayload(Object)`
**Входные параметры:** обязательный, объект, результат вызова `executeStored` (вызов должен осуществляться с параметром `fullResponse = true`)
**Результат:** объект с данными, размещёнными в `XPAYLOAD` ответа сервера - если полученный на вход результат исполнения `executeStored` содержит полезную нагрузку, `null` - в остальных случаях
#### `async Object executeStored(Object)`
**Входные параметры:**
```
{
stored,
args,
respArg,
isArray,
tagValueProcessor,
attributeValueProcessor,
loader = true,
loaderMessage = "",
throwError = true,
showErrorMessage = true,
fullResponse = false,
spreadOutArguments = true
}
```
`stored` - обязательный, строка, имя исполняемого хранимого объекта (для пакетных - "ПАКЕТ.ОБЪЕКТ")\
`args` - необязательный, объект, описание параметров исполняемого хранимого объета вида: `{"ПАРАМЕТР": "ЗНАЧЕНИЕ"|{VALUE: "ЗНАЧЕНИЕ", SDATA_TYPE: SERV_DATA_TYPE_*}}` (если тип данных параметров не указан явно - произойдёт попытка их автоматического определения, с CLOB-параметрами это не всегда может произойти корректно)\
`respArg` - необязательный, строка, имя выходного параметра исполняемого объекта, значение которого необходимо вернуть как данные ответа (если не указан - возвращвется типовой ответ)\
`isArray`, `tagValueProcessor`, `attributeValueProcessor` - необязательны, функции, позволяющие провести корректировку парсинга XML-ответа сервера в JSON (сигнатура и назначение функций описаны в документации к [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser/blob/HEAD/docs/v4/2.XMLparseOptions.md))\
`loader` - необязательный, логический, признак отображения типового индикатора процесса\
`loaderMessage` - необязательный, строка, текст индикатора процесса (при отсутствии будет использован типовой)\
`throwError` - необязательный, логический, признак генерации исключения, если `false` - возвращает ошибку в типовом формате\
`showErrorMessage` - необязательный, логический, признак отображения типового клиентского сообщение об ошибке, в случае её возникновения (только если `throwError = true`)\
`fullResponse` - необязательный, логический, признак возврата полного типового ответа сервера, если `false` - возвращается только содержимое `XPAYLOAD`\
`spreadOutArguments` - необязательный, логический, признак "разделения" значений выходных параметров исполняемого обхекта (игнорируется при наличии `respArg`), если `true` - `XPAYLOAD` будет содержать ответ в виде `{"ВЫХОДНОЙ_ПАРАМЕТР1": "ЗНАЧЕНИЕ", "ВЫХОДНОЙ_ПАРАМЕТР2": "ЗНАЧЕНИЕ", ...}`, если `false` - `XPAYLOAD` будет содержать ответ в виде `{XOUT_ARGUMENTS: [{SNAME: "ВЫХОДНОЙ_ПАРАМЕТР1", VALUE: "ЗНАЧЕНИЕ"}, {SNAME: "ВЫХОДНОЙ_ПАРАМЕТР2", VALUE: "ЗНАЧЕНИЕ"}, ...]}`
**Результат:** объект с данными, размещёнными в `XPAYLOAD` ответа сервера (если `fullResponse = false`) или полный типовой ответ (описан выше).
**Пример:**
```
import React, { useState, useContext } from "react"; //Классы React
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
//Функциональный компонент панели (или её части)
const MyPanel = () => {
//Собственное состояние
const [state, setState] = useState({ dataLoaded: false, data: [], filters: null, orders: null });
//Подключение к контексту взаимодействия с сервером
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
//Загрузка данных проектов с сервера
const loadProjects = async (agentName) => {
//Исполняем процедуру
const data = await executeStored({
stored: "UDO_P_GET_MY_DATA",
args: {
CFILTERS: { VALUE: state.filters, SDATA_TYPE: SERV_DATA_TYPE_CLOB },
CORDERS: { VALUE: state.orders, SDATA_TYPE: SERV_DATA_TYPE_CLOB },
SAGENT: agentName
},
respArg: "COUT"
});
//Отражаем данные в состоянии
setState(pv => ({ ...pv, data: [...data], dataLoaded: true }));
}
};
```
#### `async Object getConfig(Object)`
**Входные параметры:**
```
{
loader = true,
loaderMessage = "",
throwError = true,
showErrorMessage = true
}
```
`loader` - необязательный, логический, признак отображения типового индикатора процесса\
`loaderMessage` - необязательный, строка, текст индикатора процесса (при отсутствии будет использован типовой)\
`throwError` - необязательный, логический, признак генерации исключения, если `false` - возвращает ошибку в типовом формате\
`showErrorMessage` - необязательный, логический, признак отображения типового клиентского сообщения об ошибке, в случае её возникновения (только если `throwError = true`)
**Результат:** объект, типовой ответ, где `XPAYLOAD` объект вида (см. описание атрибутов выше, в описании "p8panels.config"):
```
{
"MenuItems": {
"App": [
{
"MenuItem": [
{
"parent": ...,
"name": ...,
"caption": ...,
"url": ...,
"separator": ...
},
...
],
"name": "Realiz"
},
...
]
},
"Panels": {
"Panel": [
{
"name": ...,
"group": ...,
"caption": ...,
"desc": ...,
"url": ...,
"path": ...,
"icon": ...,
"showInPanelsList": ...,
"preview": ...
},
...
],
"urlBase": ...
}
}
```
### API для взаимодействия с WEB-приложением "ПАРУС 8 Онлайн"
### Компоненты пользовательского интерфейса
#### Типовые интерфейсные примитивы
##### Компоненты MUI
##### Сообщения "P8PAppMessage", "P8PAppInlineMessage"
##### Индикатор загрузки "P8PAppProgress"
#### Высокоуровневые компоненты
##### Таблица данных "P8PDataGrid"
##### Графики "P8PChart"
##### Диаграмма ганта "P8PGantt"