diff --git a/app/panels/query_editor/components/entity_attrs_dialog/attrs_list.js b/app/panels/query_editor/components/entity_attrs_dialog/attrs_list.js new file mode 100644 index 0000000..705aac1 --- /dev/null +++ b/app/panels/query_editor/components/entity_attrs_dialog/attrs_list.js @@ -0,0 +1,97 @@ +/* + Парус 8 - Панели мониторинга - Редактор запросов + Компонент: Список атрибутов сущности +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Stack, List, ListItem, IconButton, Icon, ListItemButton, ListItemText, ListItemIcon, Checkbox, Typography } from "@mui/material"; //Интерфейсные компоненты MUI +import { ATTRIBUTE_DATA_SHAPE, attrGetUse, attrGetShow } from "../attribute/attribute"; //Атрибут сущности +import { APP_STYLES } from "../../../../../app.styles"; //Общие стили приложения + +//--------- +//Константы +//--------- + +//Стили +const STYLES = { + SMALL_TOOL_ICON: { + fontSize: 20 + }, + LIST: { height: "500px", width: "360px", bgcolor: "background.paper", overflowY: "auto", ...APP_STYLES.SCROLL } +}; + +//----------- +//Тело модуля +//----------- + +//Список атрибутов сущности +const AttrsList = ({ attrs = [], filter, onSelect = null, onShow = null } = {}) => { + //При выборе элемента списка + const handleSelectClick = attr => { + onSelect && onSelect(attr); + }; + + //При нажатии на исправлении + const handleShowClick = (e, attr) => { + e.stopPropagation(); + onShow && onShow(attr); + }; + + //Рег. выражение для фильтра + const filterRegExp = filter ? new RegExp(filter, "i") : null; + + //Формирование представления + return ( + + {attrs && + attrs + .filter(attr => (filterRegExp ? filterRegExp.test(attr.name) || filterRegExp.test(attr.title) : true)) + .map((attr, i) => { + const [selected, selectedTitle] = attrGetUse(attr, true); + const [showTitle, showIcon] = attrGetShow(attr, true); + return ( + + handleSelectClick(attr)} selected={selected} dense> + + + + + {`${attr.alias || attr.name}`} + + } + /> + + handleShowClick(e, attr)} title={showTitle}> + {showIcon} + + + + + ); + })} + + ); +}; + +//Контроль свойств компонента - Список атрибутов сущности +AttrsList.propTypes = { + attrs: PropTypes.arrayOf(ATTRIBUTE_DATA_SHAPE), + filter: PropTypes.string, + onSelect: PropTypes.func, + onShow: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { AttrsList }; diff --git a/app/panels/query_editor/components/entity_attrs_dialog/entity_attrs_dialog.js b/app/panels/query_editor/components/entity_attrs_dialog/entity_attrs_dialog.js index 972d74a..d588f5b 100644 --- a/app/panels/query_editor/components/entity_attrs_dialog/entity_attrs_dialog.js +++ b/app/panels/query_editor/components/entity_attrs_dialog/entity_attrs_dialog.js @@ -7,28 +7,97 @@ //Подключение библиотек //--------------------- -import React from "react"; //Классы React +import React, { useState, useEffect } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента +import { TextField, InputAdornment, Icon, IconButton } from "@mui/material"; //Интерфейсные элементы MUI import { P8PDialog } from "../../../../components/p8p_dialog"; //Типовой диалог +import { AttrsList } from "./attrs_list"; //Список атрибутов сущности +import { useEntityAttrs } from "./hooks"; //Хуки диалога настройки атрибутов сущности //----------- //Тело модуля //----------- //Диалог настройки атрибутов сущности -const EntityAttrsDialog = ({ id, title, onOk, onCancel }) => { +const EntityAttrsDialog = ({ query, id, title, onOk, onCancel }) => { + //Собственное состояние - фильтр атрибутов + const [filter, setFilter] = useState(""); + + //Собственное состояние - список атрибутов + const [attrs, setAttrs] = useState([]); + + //Хук для взаимодействия с сервером + const [srvAttrs, saveAttrs] = useEntityAttrs(query, id); + //Нажатие на кнопку "Ok" - const handleOk = values => onOk && onOk({ ...values }); + const handleOk = async () => { + await saveAttrs(attrs); + onOk && onOk(); + }; //Нажатие на кнопку "Отмена" const handleCancel = () => onCancel && onCancel(); + //Выбор/исключение атрибута из запроса + const handleAttrSelect = attr => + setAttrs( + attrs.map(a => ({ + ...(a.id === attr.id ? { ...a, use: a.use === 1 ? 0 : 1, show: a.use === 1 ? 0 : a.show } : a) + })) + ); + + //Отображение/сокрытие атрибута в запросе + const handleAttrShow = attr => + setAttrs( + attrs.map(a => ({ + ...(a.id === attr.id ? { ...a, show: a.show === 1 ? 0 : 1, use: a.show === 0 ? 1 : a.use } : a) + })) + ); + + //При изменении значения фильтра + const handleFilterChange = e => setFilter(e.target.value); + + //При очистке фильтра + const handleFilterClear = () => setFilter(""); + + //При загрузке данных с сервера + useEffect(() => { + if (srvAttrs) setAttrs(srvAttrs.map(srvAttr => ({ ...srvAttr }))); + }, [srvAttrs]); + //Генерация содержимого - return ; + return ( + + + search + + ), + endAdornment: ( + + + clear + + + ) + }} + /> + + + ); }; //Контроль свойств - Диалог настройки атрибутов сущности EntityAttrsDialog.propTypes = { + query: PropTypes.number.isRequired, id: PropTypes.string.isRequired, title: PropTypes.string.isRequired, onOk: PropTypes.func, diff --git a/app/panels/query_editor/components/entity_attrs_dialog/hooks.js b/app/panels/query_editor/components/entity_attrs_dialog/hooks.js new file mode 100644 index 0000000..5532430 --- /dev/null +++ b/app/panels/query_editor/components/entity_attrs_dialog/hooks.js @@ -0,0 +1,92 @@ +/* + Парус 8 - Панели мониторинга - Редактор запросов + Пользовательские хуки диалога настройки атрибутов сущности +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import { useState, useContext, useEffect, useCallback } from "react"; //Классы React +import { BackEndСtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером +import { object2Base64XML } from "../../../../core/utils"; //Вспомогательные функции + +//------------------------------------ +//Вспомогательные функции и компоненты +//------------------------------------ + +//----------- +//Тело модуля +//----------- + +//Работа с атрибутами сущности +const useEntityAttrs = (query, entity) => { + //Собственное состояние - флаг загрузки + const [isLoading, setLoading] = useState(false); + + //Собственное состояние - флаг необходимости обновления + const [refresh, setRefresh] = useState(true); + + //Собственное состояние - данные + const [data, setData] = useState(null); + + //Подключение к контексту взаимодействия с сервером + const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx); + + //Обновление данных + const doRefresh = () => setRefresh(true); + + //Установка атрибутов сущности + const setAttrs = useCallback( + async attrs => { + await executeStored({ + stored: "PKG_P8PANELS_QE.QUERY_ENT_ATTRS_SET", + args: { + NRN: query, + SID: entity, + CATTRS: { + VALUE: object2Base64XML(attrs, { arrayNodeName: "XATTR", ignoreAttributes: false, attributeNamePrefix: "" }), + SDATA_TYPE: SERV_DATA_TYPE_CLOB + } + }, + loader: false + }); + }, + [query, entity, executeStored, SERV_DATA_TYPE_CLOB] + ); + + //При необходимости получить/обновить данные + useEffect(() => { + //Загрузка данных с сервера + const loadData = async () => { + try { + setLoading(true); + const data = await executeStored({ + stored: "PKG_P8PANELS_QE.QUERY_ENT_ATTRS_GET", + args: { NRN: query, SID: entity }, + respArg: "COUT", + isArray: name => ["XATTR"].includes(name), + attributeValueProcessor: (name, val) => (["name", "title", "agg"].includes(name) ? undefined : val), + loader: true + }); + setData(data?.XATTRS?.XATTR || []); + } finally { + setRefresh(false); + setLoading(false); + } + }; + //Если надо обновить + if (refresh) + //Получим данные + loadData(); + }, [refresh, query, entity, executeStored]); + + //Возвращаем интерфейс хука + return [data, setAttrs, doRefresh, isLoading]; +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { useEntityAttrs }; diff --git a/app/panels/query_editor/components/query_options/query_options.js b/app/panels/query_editor/components/query_options/query_options.js index d3c9f9d..0fbb2f0 100644 --- a/app/panels/query_editor/components/query_options/query_options.js +++ b/app/panels/query_editor/components/query_options/query_options.js @@ -24,7 +24,7 @@ import { RELATION_DATA_SHAPE } from "../relation/relation"; //Описание //----------- //Свойства запроса -const QueryOptions = ({ onEntityAdd, onEntityRemove, onRelationRemove, onQueryOptionsChanged, entity, relation }) => { +const QueryOptions = ({ query, entity, relation, onEntityAdd, onEntityRemove, onRelationRemove, onQueryOptionsChanged }) => { //Отображение диалога добавления сущности const [openEntityAddDialog, setOpenEntityAddDialog] = useState(false); @@ -70,8 +70,12 @@ const QueryOptions = ({ onEntityAdd, onEntityRemove, onRelationRemove, onQueryOp return ( <> {openEntityAddDialog && } - {openEntityAttrsDialog && } - + {openEntityAttrsDialog && ( + + )} + + +