ЦИТК-979 - Настройка запроса - аргументы (клиент) + рефакторинг инспектора свойств

This commit is contained in:
Mikhail Chechnev 2025-08-22 14:31:06 +03:00
parent 38af01c9ef
commit eef77cbd2d
19 changed files with 953 additions and 303 deletions

View File

@ -0,0 +1,89 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Компоненты: Аргумент запроса
*/
//---------------------
//Подключение библиотек
//---------------------
import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Stack, ListItem, IconButton, Icon, ListItemButton, ListItemText, Typography, ListItemIcon, Chip } from "@mui/material"; //Компоненты UI
import { STYLES as COMMON_STYLES } from "../../../../components/editors/p8p_editors_common"; //Общие ресурсы редаторов
import { DATA_TYPE, DATA_TYPE_ICON } from "../../common"; //Общие ресурсы и константы редактора запросов
//---------
//Константы
//---------
//Варианты представления
const ARGUMENT_VARIANT = {
LIST_ITEM: "LIST_ITEM",
CHIP: "CHIP"
};
//Структура аргумента
const ARGUMENT_SHAPE = PropTypes.shape({
name: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
dataType: PropTypes.oneOf(Object.values(DATA_TYPE)),
mandatory: PropTypes.oneOf([0, 1]).isRequired
});
//Иконки
const ICONS = { ...DATA_TYPE_ICON, DEFAULT: "category" };
//-----------
//Тело модуля
//-----------
//Аргумент запроса
const Argument = ({ arg, variant, onClick = null, onDelete = null }) => {
//Заголовок аргумента
const title = `${arg.mandatory == 1 ? "*" : ""}${arg.title}`;
//Иконка аргумента
const icon = ICONS[arg.dataType] || ICONS.DEFAULT;
//Формирование представления
return variant == ARGUMENT_VARIANT.LIST_ITEM ? (
<ListItem disablePadding>
<ListItemButton onClick={() => onClick && onClick(arg)} dense>
<ListItemIcon>
<Icon>{icon}</Icon>
</ListItemIcon>
<ListItemText
primary={title}
secondaryTypographyProps={{ component: "div" }}
secondary={
<Stack direction={"column"}>
<Typography variant={"caption"}>{arg.name}</Typography>
</Stack>
}
/>
<Stack direction={"row"}>
<IconButton onClick={e => onDelete && onDelete(e, arg)} title={"Удалить"}>
<Icon>delete</Icon>
</IconButton>
</Stack>
</ListItemButton>
</ListItem>
) : variant == ARGUMENT_VARIANT.CHIP ? (
<Chip icon={<Icon>{icon}</Icon>} label={title} variant={"outlined"} sx={COMMON_STYLES.CHIP(true)} />
) : null;
};
//Контроль свойств компонента - Аргумент запроса
Argument.propTypes = {
arg: ARGUMENT_SHAPE,
variant: PropTypes.oneOf(Object.values(ARGUMENT_VARIANT)).isRequired,
onClick: PropTypes.func,
onDelete: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { Argument, ARGUMENT_VARIANT, ARGUMENT_SHAPE };

View File

@ -0,0 +1,62 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Инспектор свойств
*/
//---------------------
//Подключение библиотек
//---------------------
import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { P8PEditorBox } from "../../../../components/editors/p8p_editor_box"; //Контейнер параметров редактора
import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Подзаголовок группы параметров редактора
import { ENTITY_DATA_SHAPE } from "../entity/entity"; //Описание сущности
import { RELATION_DATA_SHAPE } from "../relation/relation"; //Описание связи
import { InspectorQueryArguments } from "../inspector_query_args/inspector_query_args"; //Управление аргументами запроса
import { InspectorQueryEntities } from "../inspector_query_ents/inspector_query_ents"; //Управление сущностями запроса
import { InspectorQueryRelations } from "../inspector_query_rls/inspector_query_rls"; //Управление связями запроса
import { ARGUMENT_SHAPE } from "../argument/argument"; //Аргументы запроса
//-----------
//Тело модуля
//-----------
//Инспектор свойств
const Inspector = ({ query, entity, relation, args = [], cond = null, onOptionsChanged = null }) => {
//При изменении настроек запроса
const handleOptionsChanged = () => onOptionsChanged && onOptionsChanged();
//Генерация содержимого
return (
<P8PEditorBox title={"Настройки запроса"}>
<P8PEditorSubHeader title={"Аргументы"} />
<InspectorQueryArguments query={query} args={args} onOptionsChanged={handleOptionsChanged} />
<P8PEditorSubHeader title={"Условия отбора"} />
<P8PEditorSubHeader title={"Сущности"} />
<InspectorQueryEntities query={query} entity={entity} onOptionsChanged={handleOptionsChanged} />
{relation && (
<>
<P8PEditorSubHeader title={"Связь"} />
<InspectorQueryRelations query={query} relation={relation} onOptionsChanged={handleOptionsChanged} />
</>
)}
</P8PEditorBox>
);
};
//Контроль свойств компонента - Инспектор свойств
Inspector.propTypes = {
query: PropTypes.number.isRequired,
entity: ENTITY_DATA_SHAPE,
relation: RELATION_DATA_SHAPE,
args: PropTypes.arrayOf(ARGUMENT_SHAPE),
cond: PropTypes.string,
onOptionsChanged: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { Inspector };

View File

@ -0,0 +1,76 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Компонент: Диалог добавления/исправления аргумента запроса
*/
//---------------------
//Подключение библиотек
//---------------------
import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { P8PDialog } from "../../../../components/p8p_dialog"; //Типовой диалог
import { TITLES } from "../../../../../app.text"; //Общие текстовые ресурсы приложения
import { DATA_TYPE } from "../../common"; //Общие константы редактора
//-----------
//Тело модуля
//-----------
//Диалог добавления/исправления аргумента запроса
const ArgIUDialog = ({ name = "", title = "", dataType = DATA_TYPE.NUMB, mandatory = 0, insert = true, onOk, onCancel }) => {
//Нажатие на кнопку "Ok"
const handleOk = values => onOk && onOk({ ...values });
//Нажатие на кнопку "Отмена"
const handleCancel = () => onCancel && onCancel();
//Генерация содержимого
return (
<P8PDialog
title={`${insert === true ? TITLES.INSERT : TITLES.UPDATE} аргумента`}
inputs={[
{ name: "name", value: name, label: "Имя", disabled: insert != true },
{ name: "title", value: title, label: "Приглашение" },
{
name: "dataType",
value: dataType,
label: "Тип данных",
list: [
{ name: "Строка", value: DATA_TYPE.STR },
{ name: "Число", value: DATA_TYPE.NUMB },
{ name: "Дата", value: DATA_TYPE.DATE }
]
},
{
name: "mandatory",
value: mandatory,
label: "Обязательный",
list: [
{ name: "Нет", value: 0 },
{ name: "Да", value: 1 }
]
}
]}
onOk={handleOk}
onCancel={handleCancel}
/>
);
};
//Контроль свойств - Диалог добавления/исправления аргумента запроса
ArgIUDialog.propTypes = {
name: PropTypes.string,
title: PropTypes.string,
dataType: PropTypes.number,
mandatory: PropTypes.number,
insert: PropTypes.bool,
onOk: PropTypes.func,
onCancel: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { ArgIUDialog };

View File

@ -0,0 +1,63 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Компонент: Список аргументов
*/
//---------------------
//Подключение библиотек
//---------------------
import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { List } from "@mui/material"; //Интерфейсные компоненты MUI
import { APP_STYLES } from "../../../../../app.styles"; //Общие стили приложения
import { Argument, ARGUMENT_VARIANT, ARGUMENT_SHAPE } from "../argument/argument"; //Аргумент запроса
//---------
//Константы
//---------
//Стили
const STYLES = {
LIST: { height: "500px", width: "360px", bgcolor: "background.paper", overflowY: "auto", ...APP_STYLES.SCROLL }
};
//-----------
//Тело модуля
//-----------
//Список аргументов
const ArgsList = ({ args = [], onSelect = null, onDelete = null } = {}) => {
//При нажатии на элемент списка
const handleItemClick = arg => onSelect && onSelect(arg);
//При нажатии на удалении элемента списка
const handleItemDeleteClick = (e, arg) => {
e.stopPropagation();
onDelete && onDelete(arg);
};
//Формирование представления
return (
<List sx={STYLES.LIST}>
{args &&
args.map((arg, i) => (
<Argument key={i} arg={arg} variant={ARGUMENT_VARIANT.LIST_ITEM} onClick={handleItemClick} onDelete={handleItemDeleteClick} />
))}
</List>
);
};
//Контроль свойств компонента - Список аргументов
ArgsList.propTypes = {
args: PropTypes.arrayOf(ARGUMENT_SHAPE),
onSelect: PropTypes.func,
onDelete: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { ArgsList };

View File

@ -0,0 +1,66 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Пользовательские хуки настройки аргументов запроса
*/
//---------------------
//Подключение библиотек
//---------------------
import { useContext, useCallback } from "react"; //Классы React
import { BackEndСtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером
//------------------------------------
//Вспомогательные функции и компоненты
//------------------------------------
//-----------
//Тело модуля
//-----------
//Работа с аргументами запроса
const useQueryArgs = query => {
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//Добавление аргумента запроса
const addArg = useCallback(
async (name, title, dataType, mandatory) => {
await executeStored({
stored: "PKG_P8PANELS_QE.QUERY_OPT_ARG_ADD",
args: { NRN: query, SNAME: name, STITLE: title, NDATA_TYPE: dataType, NMANDATORY: mandatory },
loader: false
});
},
[query, executeStored]
);
//Исправление аргумента запроса
const editArg = useCallback(
async (name, title, dataType, mandatory) => {
await executeStored({
stored: "PKG_P8PANELS_QE.QUERY_OPT_ARG_EDIT",
args: { NRN: query, SNAME: name, STITLE: title, NDATA_TYPE: dataType, NMANDATORY: mandatory },
loader: false
});
},
[query, executeStored]
);
//Удаление аргумента запроса
const removeArg = useCallback(
async name => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_OPT_ARG_REMOVE", args: { NRN: query, SNAME: name }, loader: false });
},
[query, executeStored]
);
//Возвращаем интерфейс хука
return { addArg, editArg, removeArg };
};
//----------------
//Интерфейс модуля
//----------------
export { useQueryArgs };

View File

@ -0,0 +1,107 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Компонент инспектора - Аргументы запроса
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Stack, Icon, Button, Card, CardContent, CardActionArea } from "@mui/material"; //Интерфейсные элементы
import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы
import { useQueryArgs } from "./hooks"; //Хуки для работы с аргументами запроса на сервере
import { QueryArgsDialog } from "./query_args_dialog"; //Диалог настройки состава атрибутов
import { Argument, ARGUMENT_SHAPE, ARGUMENT_VARIANT } from "../argument/argument"; //Аргумент запроса
//-----------
//Тело модуля
//-----------
//Компонент инспектора - Аргументы запроса
const InspectorQueryArguments = ({ query, args = [], onOptionsChanged = null }) => {
//Собственное состояние - отображение диалога настройки состава аргументов
const [openQueryArgsDialog, setOpenQueryArgsDialog] = useState(false);
//Хук для взаимодействия с сервером
const { addArg, editArg, removeArg } = useQueryArgs(query);
//Уведомление родителя об изменении свойств
const notifyOptionsChanged = () => onOptionsChanged && onOptionsChanged();
//При нажатии на настройку аргументов
const handleSetup = () => setOpenQueryArgsDialog(true);
//При добавлении аргумента
const handleArgAdd = async (arg, cb) => {
await addArg(arg.name, arg.title, arg.dataType, arg.mandatory);
cb && cb();
notifyOptionsChanged();
};
//При изменении аргумента
const handleArgEdit = async (arg, cb) => {
await editArg(arg.name, arg.title, arg.dataType, arg.mandatory);
cb && cb();
notifyOptionsChanged();
};
//При удалении аргумента
const handleArgRemove = async arg => {
await removeArg(arg.name);
notifyOptionsChanged();
};
//Закрытие диалога настройки состава аргументов по "Закрыть"
const handleQueryArgsDialogClose = () => setOpenQueryArgsDialog(false);
//Расчет флага "настроенности"
const configured = args && args.length > 0 ? true : false;
//Формирование представления
return (
<>
{openQueryArgsDialog && (
<QueryArgsDialog
args={args}
onArgAdd={handleArgAdd}
onArgEdit={handleArgEdit}
onArgRemove={handleArgRemove}
onClose={handleQueryArgsDialogClose}
/>
)}
{configured && (
<Card variant={"outlined"}>
<CardActionArea onClick={handleSetup}>
<CardContent>
<Stack direction={"column"} spacing={1}>
{args.map((arg, i) => (
<Argument key={i} arg={arg} variant={ARGUMENT_VARIANT.CHIP} />
))}
</Stack>
</CardContent>
</CardActionArea>
</Card>
)}
{!configured && (
<Button startIcon={<Icon>build</Icon>} onClick={handleSetup}>
{BUTTONS.CONFIG}
</Button>
)}
</>
);
};
//Контроль свойств компонента - Компонент инспектора - Аргументы запроса
InspectorQueryArguments.propTypes = {
query: PropTypes.number.isRequired,
args: PropTypes.arrayOf(ARGUMENT_SHAPE),
onOptionsChanged: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { InspectorQueryArguments };

View File

@ -0,0 +1,80 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Компонент: Диалог настройки аргументов запроса
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useState, useContext } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Button, Icon } from "@mui/material"; //Интерфейсные компоненты MUI
import { MessagingСtx } from "../../../../context/messaging"; //Контекст сообщений
import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы приложения
import { P8PDialog } from "../../../../components/p8p_dialog"; //Типовой диалог
import { ARGUMENT_SHAPE } from "../argument/argument"; //Аргумент запроса
import { ArgsList } from "./args_list"; //Список аргументов запроса
import { ArgIUDialog } from "./arg_iu_dialog"; //Диалог добавления/исправления аргумента
//-----------
//Тело модуля
//-----------
//Диалог настройки аргументов запроса
const QueryArgsDialog = ({ args, onArgAdd, onArgEdit, onArgRemove, onClose }) => {
//Собственное состояние - изменяемый аргумент
const [modArg, setModArg] = useState(null);
//Подключение к контексту сообщений
const { showMsgWarn } = useContext(MessagingСtx);
//Нажатие на кнопку "Закрыть"
const handleClose = () => onClose && onClose();
//При выборе аргумента в списке
const handleArgSelect = arg => setModArg({ ...arg });
//При добавлении аргумента
const handleArgAdd = () => setModArg(true);
//Удаление аргумента
const handleArgRemove = arg => showMsgWarn("Удалить аргумент?", () => onArgRemove && onArgRemove(arg));
//При закрытии диалога добавления/исправления по "ОК"
const handleIUDialogOk = async values => {
if (modArg === true) onArgAdd && onArgAdd(values, handleIUDialogCancel);
else onArgEdit && onArgEdit(values, handleIUDialogCancel);
};
//При закрытии диалога добавления/исправления по "Отмена"
const handleIUDialogCancel = () => setModArg(null);
//Генерация содержимого
return (
<P8PDialog title={`Аргументы запроса`} onClose={handleClose}>
{modArg && (
<ArgIUDialog {...(modArg === true ? {} : modArg)} insert={modArg === true} onOk={handleIUDialogOk} onCancel={handleIUDialogCancel} />
)}
<Button startIcon={<Icon>add</Icon>} onClick={handleArgAdd}>
{BUTTONS.INSERT}
</Button>
<ArgsList args={args} onSelect={handleArgSelect} onDelete={handleArgRemove} />
</P8PDialog>
);
};
//Контроль свойств - Диалог настройки аргументов запроса
QueryArgsDialog.propTypes = {
args: PropTypes.arrayOf(ARGUMENT_SHAPE),
onArgAdd: PropTypes.func,
onArgEdit: PropTypes.func,
onArgRemove: PropTypes.func,
onClose: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { QueryArgsDialog };

View File

@ -1,24 +1,53 @@
/* /*
Парус 8 - Панели мониторинга - Редактор запросов Парус 8 - Панели мониторинга - Редактор запросов
Пользовательские хуки диалога настройки атрибутов сущности Пользовательские хуки для работы с сущностями
*/ */
//--------------------- //---------------------
//Подключение библиотек //Подключение библиотек
//--------------------- //---------------------
import { useState, useContext, useEffect, useCallback } from "react"; //Классы React import { useContext, useCallback, useEffect, useState } from "react"; //Классы React
import { BackEndСtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером import { BackEndСtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером
import { object2Base64XML } from "../../../../core/utils"; //Вспомогательные функции import { object2Base64XML } from "../../../../core/utils"; //Вспомогательные функции
//------------------------------------
//Вспомогательные функции и компоненты
//------------------------------------
//----------- //-----------
//Тело модуля //Тело модуля
//----------- //-----------
//Работа с сущностями запроса
const useQueryEntities = query => {
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//Добавление сущности в запрос
const addEnt = useCallback(
async (name, type) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_ENT_ADD", args: { NRN: query, SNAME: name, STYPE: type }, loader: false });
},
[query, executeStored]
);
//Удаление сущности из запроса
const removeEnt = useCallback(
async ent => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_ENT_REMOVE", args: { NRN: query, SID: ent }, loader: false });
},
[query, executeStored]
);
//Сохранение координат сущности на диаграммем
const setEntPosition = useCallback(
async (ent, x, y) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_ENT_POSITION_SET", args: { NRN: query, SID: ent, NX: x, NY: y }, loader: false });
},
[query, executeStored]
);
//Возвращаем интерфейс хука
return { addEnt, removeEnt, setEntPosition };
};
//Работа с атрибутами сущности //Работа с атрибутами сущности
const useEntityAttrs = (query, entity) => { const useEntityAttrs = (query, entity) => {
//Собственное состояние - флаг загрузки //Собственное состояние - флаг загрузки
@ -89,4 +118,4 @@ const useEntityAttrs = (query, entity) => {
//Интерфейс модуля //Интерфейс модуля
//---------------- //----------------
export { useEntityAttrs }; export { useQueryEntities, useEntityAttrs };

View File

@ -0,0 +1,112 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Компонент инспектора - Сущности запроса
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useContext, useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Icon, Button } from "@mui/material"; //Интерфейсные элементы
import { MessagingСtx } from "../../../../context/messaging"; //Контекст сообщений приложения
import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Подзаголовок группы параметров редактора
import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы
import { ENTITY_DATA_SHAPE } from "../entity/entity"; //Описание сущности
import { EntityAddDialog } from "./entity_add_dialog"; //Диалог добавления сущности
import { EntityAttrsDialog } from "./entity_attrs_dialog"; //Диалог настройки атрибутов сущности
import { useQueryEntities } from "./hooks"; //Хуки для работы с сущностями на сервере
//-----------
//Тело модуля
//-----------
//Компонент инспектора - Сущности запроса
const InspectorQueryEntities = ({ query, entity, onOptionsChanged }) => {
//Отображение диалога добавления сущности
const [openEntityAddDialog, setOpenEntityAddDialog] = useState(false);
//Отображение диалога настройки атрибутов сущности
const [openEntityAttrsDialog, setOpenEntityAttrsDialog] = useState(false);
//Работа с сущностями на сервере
const { addEnt, removeEnt } = useQueryEntities(query);
//Подключение к контексту сообщений
const { showMsgWarn } = useContext(MessagingСtx);
//Уведомление родителя об изменении свойств
const notifyOptionsChanged = () => onOptionsChanged && onOptionsChanged();
//При нажатии на кнопку добавлении сущности в запрос
const handleEntityAddClick = () => setOpenEntityAddDialog(true);
//При нажатии на кнопку настройки атрибутов сущности
const handleEntityAttrsClick = () => setOpenEntityAttrsDialog(true);
//При нажатии на кнопку даления сущности из запроса
const handleEntityRemoveClick = () =>
showMsgWarn(`Удалить сущность "${entity.title}"?`, async () => {
if (entity?.id) {
await removeEnt(entity.id);
notifyOptionsChanged();
}
});
//Закрытие диалога добавления сущности по "Отмена"
const handleEntityAddDialogCancel = () => setOpenEntityAddDialog(false);
//Закрытие диалога добавления сущности по "ОК"
const handleEntityAddDialogOk = async values => {
await addEnt(values.name, "VIEW");
setOpenEntityAddDialog(false);
notifyOptionsChanged();
};
//Закрытие диалога настройки атрибутов сущности по "Отмена"
const handleEntityAttrsDialogCancel = () => setOpenEntityAttrsDialog(false);
//Закрытие диалога настройки атрибутов сущности по "ОК"
const handleEntityAttrsDialogOk = () => {
notifyOptionsChanged();
setOpenEntityAttrsDialog();
};
//Формирование представления
return (
<>
{openEntityAddDialog && <EntityAddDialog onOk={handleEntityAddDialogOk} onCancel={handleEntityAddDialogCancel} />}
{openEntityAttrsDialog && (
<EntityAttrsDialog query={query} {...entity} onOk={handleEntityAttrsDialogOk} onCancel={handleEntityAttrsDialogCancel} />
)}
<Button startIcon={<Icon>add</Icon>} onClick={handleEntityAddClick}>
{BUTTONS.INSERT}
</Button>
{entity && (
<>
<P8PEditorSubHeader title={entity.title} />
<Button startIcon={<Icon>edit_attributes</Icon>} onClick={handleEntityAttrsClick}>
Атрибуты
</Button>
<Button startIcon={<Icon>delete</Icon>} onClick={handleEntityRemoveClick}>
{BUTTONS.DELETE}
</Button>
</>
)}
</>
);
};
//Контроль свойств компонента - Компонент инспектора - Сущности запроса
InspectorQueryEntities.propTypes = {
query: PropTypes.number.isRequired,
entity: ENTITY_DATA_SHAPE,
onOptionsChanged: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { InspectorQueryEntities };

View File

@ -0,0 +1,46 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Пользовательские хуки для работы со связями
*/
//---------------------
//Подключение библиотек
//---------------------
import { useContext, useCallback } from "react"; //Классы React
import { BackEndСtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером
//-----------
//Тело модуля
//-----------
//Работа со связами запроса
const useQueryRelations = query => {
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//Добавление отношения сущностей в запрос
const addRl = useCallback(
async (source, target) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_RL_ADD", args: { NRN: query, SSOURCE: source, STARGET: target }, loader: false });
},
[query, executeStored]
);
//Удаление отношения сущностей из запроса
const removeRl = useCallback(
async rl => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_RL_REMOVE", args: { NRN: query, SID: rl }, loader: false });
},
[query, executeStored]
);
//Возвращаем интерфейс хука
return { addRl, removeRl };
};
//----------------
//Интерфейс модуля
//----------------
export { useQueryRelations };

View File

@ -0,0 +1,61 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Компонент инспектора - Связи запроса
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useContext } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Icon, Button } from "@mui/material"; //Интерфейсные элементы
import { MessagingСtx } from "../../../../context/messaging"; //Контекст сообщений приложения
import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы
import { RELATION_DATA_SHAPE } from "../relation/relation"; //Описание связи
import { useQueryRelations } from "./hooks"; //Хуки для работы со связями
//-----------
//Тело модуля
//-----------
//Компонент инспектора - Связи запроса
const InspectorQueryRelations = ({ query, relation, onOptionsChanged }) => {
//Подключение к контексту сообщений
const { showMsgWarn } = useContext(MessagingСtx);
//Работа со связями на сервере
const { removeRl } = useQueryRelations(query);
//Уведомление родителя об изменении свойств
const notifyOptionsChanged = () => onOptionsChanged && onOptionsChanged();
//При нажатии на кнопку даления связи из запроса
const handleRelationRemoveClick = () =>
showMsgWarn(`Удалить связь "${relation.source}" - "${relation.target}"?`, async () => {
if (relation?.id) {
await removeRl(relation.id);
notifyOptionsChanged();
}
});
//Формирование представления
return (
<Button startIcon={<Icon>delete</Icon>} onClick={handleRelationRemoveClick}>
{BUTTONS.DELETE}
</Button>
);
};
//Контроль свойств компонента - Компонент инспектора - Связи запроса
InspectorQueryRelations.propTypes = {
query: PropTypes.number.isRequired,
relation: RELATION_DATA_SHAPE.isRequired,
onOptionsChanged: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { InspectorQueryRelations };

View File

@ -0,0 +1,116 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Пользовательские хуки для работы с запросами
*/
//---------------------
//Подключение библиотек
//---------------------
import { useState, useContext, useEffect, useCallback } from "react"; //Классы React
import { BackEndСtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером
//-----------
//Тело модуля
//-----------
//Работа с запросами
const useQueries = () => {
//Собственное состояние - флаг инициализированности
const [isInit, setInit] = useState(false);
//Собственное состояние - флаг загрузки
const [isLoading, setLoading] = useState(false);
//Собственное состояние - флаг необходимости обновления
const [refresh, setRefresh] = useState(true);
//Собственное состояние - данные
const [data, setData] = useState(null);
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//Обновление данных
const doRefresh = () => setRefresh(true);
//Добавление запроса
const insertQuery = useCallback(
async (code, name) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_INSERT", args: { SCODE: code, SNAME: name }, loader: false });
setRefresh(true);
},
[executeStored]
);
//Изменение запроса
const updateQuery = useCallback(
async (query, code, name) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_UPDATE", args: { NRN: query, SCODE: code, SNAME: name }, loader: false });
setRefresh(true);
},
[executeStored]
);
//Удаление запроса
const deleteQuery = useCallback(
async query => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_DELETE", args: { NRN: query }, loader: false });
setRefresh(true);
},
[executeStored]
);
//Установка флага готовности запроса
const setQueryReady = useCallback(
async (query, ready) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_READY_SET", args: { NRN: query, NREADY: ready }, loader: false });
setRefresh(true);
},
[executeStored]
);
//Установка флага публичности запроса
const setQueryPbl = useCallback(
async (query, pbl) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_PBL_SET", args: { NRN: query, NPBL: pbl }, loader: false });
setRefresh(true);
},
[executeStored]
);
//При необходимости получить/обновить данные
useEffect(() => {
//Загрузка данных с сервера
const loadData = async () => {
try {
setLoading(true);
const data = await executeStored({
stored: "PKG_P8PANELS_QE.QUERY_LIST",
respArg: "COUT",
isArray: name => ["XQUERY"].includes(name),
attributeValueProcessor: (name, val) => (["code", "name"].includes(name) ? undefined : val),
loader: true
});
setData(data?.XQUERIES?.XQUERY || []);
setInit(true);
} finally {
setRefresh(false);
setLoading(false);
}
};
//Если надо обновить
if (refresh)
//Получим данные
loadData();
}, [refresh, executeStored]);
//Возвращаем интерфейс хука
return [data, insertQuery, updateQuery, deleteQuery, setQueryReady, setQueryPbl, doRefresh, isLoading, isInit];
};
//----------------
//Интерфейс модуля
//----------------
export { useQueries };

View File

@ -13,7 +13,7 @@ import { Button, Icon } from "@mui/material"; //Интерфейсные ком
import { MessagingСtx } from "../../../../context/messaging"; //Контекст сообщений import { MessagingСtx } from "../../../../context/messaging"; //Контекст сообщений
import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы приложения import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы приложения
import { P8PConfigDialog } from "../../../../components/editors/p8p_config_dialog"; //Типовой диалог настройки import { P8PConfigDialog } from "../../../../components/editors/p8p_config_dialog"; //Типовой диалог настройки
import { useQuery } from "../../hooks"; //Пользовательские хуки import { useQueries } from "./hooks"; //Хуки для работы с запросами
import { QueriesList } from "./queries_list"; //Список запросов import { QueriesList } from "./queries_list"; //Список запросов
import { QueryIUDialog } from "./query_iu_dialog"; //Диалог добавления/исправления запроса import { QueryIUDialog } from "./query_iu_dialog"; //Диалог добавления/исправления запроса
@ -27,7 +27,7 @@ const QueriesManager = ({ current = null, onQuerySelect = null, onCancel = null
const [modQuery, setModQuery] = useState(null); const [modQuery, setModQuery] = useState(null);
//Работа со списком запросов //Работа со списком запросов
const [queries, insertQuery, updateQuery, deleteQuery, setQueryReady, setQueryPbl] = useQuery(); const [queries, insertQuery, updateQuery, deleteQuery, setQueryReady, setQueryPbl] = useQueries();
//Подключение к контексту сообщений //Подключение к контексту сообщений
const { showMsgWarn } = useContext(MessagingСtx); const { showMsgWarn } = useContext(MessagingСtx);

View File

@ -1,122 +0,0 @@
/*
Парус 8 - Панели мониторинга - Редактор запросов
Свойства запроса
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useState, useContext } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Button, Icon } from "@mui/material"; //Интерфейсные компоненты MUI
import { MessagingСtx } from "../../../../context/messaging"; //Контекст сообщений приложения
import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы приложения
import { EntityAddDialog } from "../entity_add_dialog/entity_add_dialog"; //Диалог добавления сущности
import { EntityAttrsDialog } from "../entity_attrs_dialog/entity_attrs_dialog"; //Диалог настройки атрибутов сущности
import { P8PEditorBox } from "../../../../components/editors/p8p_editor_box"; //Контейнер параметров редактора
import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Подзаголовок группы параметров редактора
import { ENTITY_DATA_SHAPE } from "../entity/entity"; //Описание сущности
import { RELATION_DATA_SHAPE } from "../relation/relation"; //Описание связи
//-----------
//Тело модуля
//-----------
//Свойства запроса
const QueryOptions = ({ query, entity, relation, onEntityAdd, onEntityRemove, onRelationRemove, onQueryOptionsChanged }) => {
//Отображение диалога добавления сущности
const [openEntityAddDialog, setOpenEntityAddDialog] = useState(false);
//Отображение диалога настройки атрибутов сущности
const [openEntityAttrsDialog, setOpenEntityAttrsDialog] = useState(false);
//Подключение к контексту сообщений
const { showMsgWarn } = useContext(MessagingСtx);
//При нажатии на кнопку добавлении сущности в запрос
const handleEntityAddClick = () => setOpenEntityAddDialog(true);
//При нажатии на кнопку настройки атрибутов сущности
const handleEntityAttrsClick = () => setOpenEntityAttrsDialog(true);
//При нажатии на кнопку даления сущности из запроса
const handleEntityRemoveClick = () =>
showMsgWarn(`Удалить сущность "${entity.title}"?`, () => entity?.id && onEntityRemove && onEntityRemove(entity.id));
//При нажатии на кнопку даления связи из запроса
const handleRelationRemoveClick = () =>
showMsgWarn(
`Удалить связь "${relation.source}" - "${relation.target}"?`,
() => relation?.id && onRelationRemove && onRelationRemove(relation.id)
);
//Закрытие диалога добавления сущности по "Отмена"
const handleEntityAddDialogCancel = () => setOpenEntityAddDialog(false);
//Закрытие диалога добавления сущности по "ОК"
const handleEntityAddDialogOk = values => onEntityAdd && onEntityAdd(values.name, res => res && setOpenEntityAddDialog(false));
//Закрытие диалога настройки атрибутов сущности по "Отмена"
const handleEntityAttrsDialogCancel = () => setOpenEntityAttrsDialog(false);
//Закрытие диалога настройки атрибутов сущности по "ОК"
const handleEntityAttrsDialogOk = () => {
onQueryOptionsChanged && onQueryOptionsChanged();
setOpenEntityAttrsDialog();
};
//Генерация содержимого
return (
<>
{openEntityAddDialog && <EntityAddDialog onOk={handleEntityAddDialogOk} onCancel={handleEntityAddDialogCancel} />}
{openEntityAttrsDialog && (
<EntityAttrsDialog query={query} {...entity} onOk={handleEntityAttrsDialogOk} onCancel={handleEntityAttrsDialogCancel} />
)}
<P8PEditorBox title={"Настройки запроса"}>
<P8PEditorSubHeader title={"Параметры"} />
<P8PEditorSubHeader title={"Условия отбора"} />
<P8PEditorSubHeader title={"Сущности"} />
<Button startIcon={<Icon>add</Icon>} onClick={handleEntityAddClick}>
{BUTTONS.INSERT}
</Button>
{entity && (
<>
<P8PEditorSubHeader title={entity.title} />
<Button startIcon={<Icon>edit_attributes</Icon>} onClick={handleEntityAttrsClick}>
Атрибуты
</Button>
<Button startIcon={<Icon>delete</Icon>} onClick={handleEntityRemoveClick}>
{BUTTONS.DELETE}
</Button>
</>
)}
{relation && (
<>
<P8PEditorSubHeader title={"Связь"} />
<Button startIcon={<Icon>delete</Icon>} onClick={handleRelationRemoveClick}>
{BUTTONS.DELETE}
</Button>
</>
)}
</P8PEditorBox>
</>
);
};
//Контроль свойств компонента - Свойства запроса
QueryOptions.propTypes = {
query: PropTypes.number.isRequired,
entity: ENTITY_DATA_SHAPE,
relation: RELATION_DATA_SHAPE,
onEntityAdd: PropTypes.func,
onEntityRemove: PropTypes.func,
onRelationRemove: PropTypes.func,
onQueryOptionsChanged: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { QueryOptions };

View File

@ -1,13 +1,13 @@
/* /*
Парус 8 - Панели мониторинга - Редактор запросов Парус 8 - Панели мониторинга - Редактор запросов
Пользовательские хуки Пользовательские хуки для работы с метаданными запроса
*/ */
//--------------------- //---------------------
//Подключение библиотек //Подключение библиотек
//--------------------- //---------------------
import { useState, useContext, useEffect, useCallback } from "react"; //Классы React import { useState, useContext, useEffect } from "react"; //Классы React
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { NODE_TYPE } from "./common"; //Общие ресурсы и константы редактора import { NODE_TYPE } from "./common"; //Общие ресурсы и константы редактора
@ -88,8 +88,8 @@ const serverQueryData2QueryDiagram = (entities, relations) => {
//Тело модуля //Тело модуля
//----------- //-----------
//Работа с запросами //Работа с метаданными запроса
const useQuery = () => { const useQuery = query => {
//Собственное состояние - флаг инициализированности //Собственное состояние - флаг инициализированности
const [isInit, setInit] = useState(false); const [isInit, setInit] = useState(false);
@ -99,8 +99,11 @@ const useQuery = () => {
//Собственное состояние - флаг необходимости обновления //Собственное состояние - флаг необходимости обновления
const [refresh, setRefresh] = useState(true); const [refresh, setRefresh] = useState(true);
//Собственное состояние - данные //Собственное состояние - данные диаграммы
const [data, setData] = useState(null); const [queryDiagram, setQueryDiagram] = useState(null);
//Собственное состояние - данные настроек
const [queryOption, setQueryOption] = useState(null);
//Подключение к контексту взаимодействия с сервером //Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx); const { executeStored } = useContext(BackEndСtx);
@ -108,51 +111,6 @@ const useQuery = () => {
//Обновление данных //Обновление данных
const doRefresh = () => setRefresh(true); const doRefresh = () => setRefresh(true);
//Добавление запроса
const insertQuery = useCallback(
async (code, name) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_INSERT", args: { SCODE: code, SNAME: name }, loader: false });
setRefresh(true);
},
[executeStored]
);
//Изменение запроса
const updateQuery = useCallback(
async (query, code, name) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_UPDATE", args: { NRN: query, SCODE: code, SNAME: name }, loader: false });
setRefresh(true);
},
[executeStored]
);
//Удаление запроса
const deleteQuery = useCallback(
async query => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_DELETE", args: { NRN: query }, loader: false });
setRefresh(true);
},
[executeStored]
);
//Установка флага готовности запроса
const setQueryReady = useCallback(
async (query, ready) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_READY_SET", args: { NRN: query, NREADY: ready }, loader: false });
setRefresh(true);
},
[executeStored]
);
//Установка флага публичности запроса
const setQueryPbl = useCallback(
async (query, pbl) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_PBL_SET", args: { NRN: query, NPBL: pbl }, loader: false });
setRefresh(true);
},
[executeStored]
);
//При необходимости получить/обновить данные //При необходимости получить/обновить данные
useEffect(() => { useEffect(() => {
//Загрузка данных с сервера //Загрузка данных с сервера
@ -160,107 +118,14 @@ const useQuery = () => {
try { try {
setLoading(true); setLoading(true);
const data = await executeStored({ const data = await executeStored({
stored: "PKG_P8PANELS_QE.QUERY_LIST", stored: "PKG_P8PANELS_QE.QUERY",
respArg: "COUT",
isArray: name => ["XQUERY"].includes(name),
attributeValueProcessor: (name, val) => (["code", "name"].includes(name) ? undefined : val),
loader: true
});
setData(data?.XQUERIES?.XQUERY || []);
setInit(true);
} finally {
setRefresh(false);
setLoading(false);
}
};
//Если надо обновить
if (refresh)
//Получим данные
loadData();
}, [refresh, executeStored]);
//Возвращаем интерфейс хука
return [data, insertQuery, updateQuery, deleteQuery, setQueryReady, setQueryPbl, doRefresh, isLoading, isInit];
};
//Работа с содержимым запроса
const useQueryDesc = query => {
//Собственное состояние - флаг инициализированности
const [isInit, setInit] = useState(false);
//Собственное состояние - флаг загрузки
const [isLoading, setLoading] = useState(false);
//Собственное состояние - флаг необходимости обновления
const [refresh, setRefresh] = useState(true);
//Собственное состояние - данные
const [data, setData] = useState(null);
//Подключение к контексту взаимодействия с сервером
const { executeStored } = useContext(BackEndСtx);
//Обновление данных
const doRefresh = () => setRefresh(true);
//Добавление сущности в запрос
const addEnt = useCallback(
async (name, type) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_ENT_ADD", args: { NRN: query, SNAME: name, STYPE: type }, loader: false });
setRefresh(true);
},
[query, executeStored]
);
//Удаление сущности из запроса
const removeEnt = useCallback(
async ent => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_ENT_REMOVE", args: { NRN: query, SID: ent }, loader: false });
setRefresh(true);
},
[query, executeStored]
);
//Сохранение координат сущности на диаграммем
const setEntPosition = useCallback(
async (ent, x, y) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_ENT_POSITION_SET", args: { NRN: query, SID: ent, NX: x, NY: y }, loader: false });
},
[query, executeStored]
);
//Добавление отношения сущностей в запрос
const addRl = useCallback(
async (source, target) => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_RL_ADD", args: { NRN: query, SSOURCE: source, STARGET: target }, loader: false });
setRefresh(true);
},
[query, executeStored]
);
//Удаление отношения сущностей из запроса
const removeRl = useCallback(
async rl => {
await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_RL_REMOVE", args: { NRN: query, SID: rl }, loader: false });
setRefresh(true);
},
[query, executeStored]
);
//При необходимости получить/обновить данные
useEffect(() => {
//Загрузка данных с сервера
const loadData = async () => {
try {
setLoading(true);
const data = await executeStored({
stored: "PKG_P8PANELS_QE.QUERY_DESC",
args: { NRN: query }, args: { NRN: query },
respArg: "COUT", respArg: "COUT",
isArray: name => ["XENT", "XATTR", "XRL"].includes(name), isArray: name => ["XENT", "XATTR", "XRL", "XARG"].includes(name),
loader: true loader: true
}); });
setData(serverQueryData2QueryDiagram(data?.XENTS?.XENT || [], data?.XRLS?.XRL || [])); setQueryDiagram(serverQueryData2QueryDiagram(data?.XENTS?.XENT || [], data?.XRLS?.XRL || []));
setQueryOption({ args: data?.XOPT?.XARGS?.XARG || [], cond: data?.XOPT?.XCOND || null });
setInit(true); setInit(true);
} finally { } finally {
setRefresh(false); setRefresh(false);
@ -273,18 +138,21 @@ const useQueryDesc = query => {
//Если есть для чего получать данные //Если есть для чего получать данные
loadData(); loadData();
//Нет идентификатора запроса - нет данных //Нет идентификатора запроса - нет данных
else setData(null); else {
setQueryDiagram(null);
setQueryOption(null);
}
}, [refresh, query, executeStored]); }, [refresh, query, executeStored]);
//При изменении входных свойств - поднимаем флаг обновления //При изменении входных свойств - поднимаем флаг обновления
useEffect(() => setRefresh(true), [query]); useEffect(() => setRefresh(true), [query]);
//Возвращаем интерфейс хука //Возвращаем интерфейс хука
return [data, addEnt, removeEnt, setEntPosition, addRl, removeRl, doRefresh, isLoading, isInit]; return [queryDiagram, queryOption, doRefresh, isLoading, isInit];
}; };
//---------------- //----------------
//Интерфейс модуля //Интерфейс модуля
//---------------- //----------------
export { useQuery, useQueryDesc }; export { useQuery };

View File

@ -13,9 +13,11 @@ import { ApplicationСtx } from "../../context/application"; //Контекст
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Компоненты рабочего стола import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Компоненты рабочего стола
import { P8PEditorToolBar } from "../../components/editors/p8p_editor_toolbar"; //Панель инструментов редактора import { P8PEditorToolBar } from "../../components/editors/p8p_editor_toolbar"; //Панель инструментов редактора
import { QueryDiagram } from "./components/query_diagram/query_diagram"; //Диаграмма запроса import { QueryDiagram } from "./components/query_diagram/query_diagram"; //Диаграмма запроса
import { QueryOptions } from "./components/query_options/query_options"; //Свойства запроса import { Inspector } from "./components/inspector/inspector"; //Инспектор свойств
import { QueriesManager } from "./components/queries_manager/queries_manager"; //Менеджер запросов import { QueriesManager } from "./components/queries_manager/queries_manager"; //Менеджер запросов
import { useQueryDesc } from "./hooks"; //Пользовательские хуки import { useQuery } from "./hooks"; //Хуки для работы с метаданными запроса на сервере
import { useQueryRelations } from "./components/inspector_query_rls/hooks"; //Хуки для работы со связями запроса на сервере
import { useQueryEntities } from "./components/inspector_query_ents/hooks"; //Хуки для работы с сущностями запроса на сервере
//--------- //---------
//Константы //Константы
@ -49,8 +51,14 @@ const QueryEditor = () => {
//Отображения менеджера запросов //Отображения менеджера запросов
const [openQueriesManager, setOpenQueriesManager] = useState(true); const [openQueriesManager, setOpenQueriesManager] = useState(true);
//Получение данных запроса //Получение метаданных с описанием запроса
const [queryDiagram, addEnt, removeEnt, setEntPosition, addRl, removeRl, doRefresh] = useQueryDesc(query); const [queryDiagram, queryOption, doRefresh] = useQuery(query);
//Работа с сущностями на сервере
const { removeEnt, setEntPosition } = useQueryEntities(query);
//Работа со связями на сервере
const { addRl, removeRl } = useQueryRelations(query);
//Подключение к контексту приложения //Подключение к контексту приложения
const { setAppBarTitle } = useContext(ApplicationСtx); const { setAppBarTitle } = useContext(ApplicationСtx);
@ -78,16 +86,11 @@ const QueryEditor = () => {
//Обработка изменения положения сущности на диаграмме //Обработка изменения положения сущности на диаграмме
const handleEntityPositionChange = (ent, position) => setEntPosition(ent, position.x, position.y); const handleEntityPositionChange = (ent, position) => setEntPosition(ent, position.x, position.y);
//Обработка добавления сущности в запрос
const handleEntityAdd = async (entName, cb) => {
await addEnt(entName, "VIEW");
cb(true);
};
//Обработка удаления сущности из запроса //Обработка удаления сущности из запроса
const handleEntityRemove = async ent => { const handleEntityRemove = async ent => {
await removeEnt(ent); await removeEnt(ent);
if (entity && entity?.id === ent) cleanupEnRlSelection(); if (entity && entity?.id === ent) cleanupEnRlSelection();
doRefresh();
}; };
//Обработка выделения сущности //Обработка выделения сущности
@ -100,15 +103,17 @@ const QueryEditor = () => {
const handleRelationClick = rl => selectRelation(rl); const handleRelationClick = rl => selectRelation(rl);
//Обработка добавления отношения cущностей //Обработка добавления отношения cущностей
const handleRelationAdd = (source, target) => { const handleRelationAdd = async (source, target) => {
cleanupEnRlSelection(); cleanupEnRlSelection();
addRl(source, target); await addRl(source, target);
doRefresh();
}; };
//Обработка удаления отношения cущностей //Обработка удаления отношения cущностей
const handleRelationRemove = async rl => { const handleRelationRemove = async rl => {
await removeRl(rl); await removeRl(rl);
if (relation && relation?.id === rl) cleanupEnRlSelection(); if (relation && relation?.id === rl) cleanupEnRlSelection();
doRefresh();
}; };
//При нажатии на панели (пустом месте) диаграммы запроса //При нажатии на панели (пустом месте) диаграммы запроса
@ -173,15 +178,7 @@ const QueryEditor = () => {
<Grid item xs={5} sx={STYLES.GRID_ITEM_INSPECTOR}> <Grid item xs={5} sx={STYLES.GRID_ITEM_INSPECTOR}>
{toolBar} {toolBar}
{query && ( {query && (
<QueryOptions <Inspector {...queryOption} query={query} entity={entity} relation={relation} onOptionsChanged={handleQueryOptionsChanged} />
query={query}
entity={entity}
relation={relation}
onEntityAdd={handleEntityAdd}
onEntityRemove={handleEntityRemove}
onRelationRemove={handleRelationRemove}
onQueryOptionsChanged={handleQueryOptionsChanged}
/>
)} )}
</Grid> </Grid>
</Grid> </Grid>