ЦИТК-979 - Настройка запроса - аргументы (клиент) + рефакторинг инспектора свойств
This commit is contained in:
parent
38af01c9ef
commit
eef77cbd2d
89
app/panels/query_editor/components/argument/argument.js
Normal file
89
app/panels/query_editor/components/argument/argument.js
Normal 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 };
|
||||
62
app/panels/query_editor/components/inspector/inspector.js
Normal file
62
app/panels/query_editor/components/inspector/inspector.js
Normal 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 };
|
||||
@ -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 };
|
||||
@ -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 };
|
||||
@ -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 };
|
||||
@ -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 };
|
||||
@ -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 };
|
||||
@ -1,24 +1,53 @@
|
||||
/*
|
||||
Парус 8 - Панели мониторинга - Редактор запросов
|
||||
Пользовательские хуки диалога настройки атрибутов сущности
|
||||
Пользовательские хуки для работы с сущностями
|
||||
*/
|
||||
|
||||
//---------------------
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import { useState, useContext, useEffect, useCallback } from "react"; //Классы React
|
||||
import { useContext, useCallback, useEffect, useState } from "react"; //Классы React
|
||||
import { BackEndСtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером
|
||||
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) => {
|
||||
//Собственное состояние - флаг загрузки
|
||||
@ -89,4 +118,4 @@ const useEntityAttrs = (query, entity) => {
|
||||
//Интерфейс модуля
|
||||
//----------------
|
||||
|
||||
export { useEntityAttrs };
|
||||
export { useQueryEntities, useEntityAttrs };
|
||||
@ -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 };
|
||||
@ -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 };
|
||||
@ -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 };
|
||||
116
app/panels/query_editor/components/queries_manager/hooks.js
Normal file
116
app/panels/query_editor/components/queries_manager/hooks.js
Normal 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 };
|
||||
@ -13,7 +13,7 @@ import { Button, Icon } from "@mui/material"; //Интерфейсные ком
|
||||
import { MessagingСtx } from "../../../../context/messaging"; //Контекст сообщений
|
||||
import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы приложения
|
||||
import { P8PConfigDialog } from "../../../../components/editors/p8p_config_dialog"; //Типовой диалог настройки
|
||||
import { useQuery } from "../../hooks"; //Пользовательские хуки
|
||||
import { useQueries } from "./hooks"; //Хуки для работы с запросами
|
||||
import { QueriesList } from "./queries_list"; //Список запросов
|
||||
import { QueryIUDialog } from "./query_iu_dialog"; //Диалог добавления/исправления запроса
|
||||
|
||||
@ -27,7 +27,7 @@ const QueriesManager = ({ current = null, onQuerySelect = null, onCancel = 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);
|
||||
|
||||
@ -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 };
|
||||
@ -1,13 +1,13 @@
|
||||
/*
|
||||
Парус 8 - Панели мониторинга - Редактор запросов
|
||||
Пользовательские хуки
|
||||
Пользовательские хуки для работы с метаданными запроса
|
||||
*/
|
||||
|
||||
//---------------------
|
||||
//Подключение библиотек
|
||||
//---------------------
|
||||
|
||||
import { useState, useContext, useEffect, useCallback } from "react"; //Классы React
|
||||
import { useState, useContext, useEffect } from "react"; //Классы React
|
||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||
import { NODE_TYPE } from "./common"; //Общие ресурсы и константы редактора
|
||||
|
||||
@ -88,8 +88,8 @@ const serverQueryData2QueryDiagram = (entities, relations) => {
|
||||
//Тело модуля
|
||||
//-----------
|
||||
|
||||
//Работа с запросами
|
||||
const useQuery = () => {
|
||||
//Работа с метаданными запроса
|
||||
const useQuery = query => {
|
||||
//Собственное состояние - флаг инициализированности
|
||||
const [isInit, setInit] = useState(false);
|
||||
|
||||
@ -99,8 +99,11 @@ const useQuery = () => {
|
||||
//Собственное состояние - флаг необходимости обновления
|
||||
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);
|
||||
@ -108,51 +111,6 @@ const useQuery = () => {
|
||||
//Обновление данных
|
||||
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(() => {
|
||||
//Загрузка данных с сервера
|
||||
@ -160,107 +118,14 @@ const useQuery = () => {
|
||||
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];
|
||||
};
|
||||
|
||||
//Работа с содержимым запроса
|
||||
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",
|
||||
stored: "PKG_P8PANELS_QE.QUERY",
|
||||
args: { NRN: query },
|
||||
respArg: "COUT",
|
||||
isArray: name => ["XENT", "XATTR", "XRL"].includes(name),
|
||||
isArray: name => ["XENT", "XATTR", "XRL", "XARG"].includes(name),
|
||||
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);
|
||||
} finally {
|
||||
setRefresh(false);
|
||||
@ -273,18 +138,21 @@ const useQueryDesc = query => {
|
||||
//Если есть для чего получать данные
|
||||
loadData();
|
||||
//Нет идентификатора запроса - нет данных
|
||||
else setData(null);
|
||||
else {
|
||||
setQueryDiagram(null);
|
||||
setQueryOption(null);
|
||||
}
|
||||
}, [refresh, query, executeStored]);
|
||||
|
||||
//При изменении входных свойств - поднимаем флаг обновления
|
||||
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 };
|
||||
|
||||
@ -13,9 +13,11 @@ import { ApplicationСtx } from "../../context/application"; //Контекст
|
||||
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Компоненты рабочего стола
|
||||
import { P8PEditorToolBar } from "../../components/editors/p8p_editor_toolbar"; //Панель инструментов редактора
|
||||
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 { 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 [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);
|
||||
@ -78,16 +86,11 @@ const QueryEditor = () => {
|
||||
//Обработка изменения положения сущности на диаграмме
|
||||
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 => {
|
||||
await removeEnt(ent);
|
||||
if (entity && entity?.id === ent) cleanupEnRlSelection();
|
||||
doRefresh();
|
||||
};
|
||||
|
||||
//Обработка выделения сущности
|
||||
@ -100,15 +103,17 @@ const QueryEditor = () => {
|
||||
const handleRelationClick = rl => selectRelation(rl);
|
||||
|
||||
//Обработка добавления отношения cущностей
|
||||
const handleRelationAdd = (source, target) => {
|
||||
const handleRelationAdd = async (source, target) => {
|
||||
cleanupEnRlSelection();
|
||||
addRl(source, target);
|
||||
await addRl(source, target);
|
||||
doRefresh();
|
||||
};
|
||||
|
||||
//Обработка удаления отношения cущностей
|
||||
const handleRelationRemove = async rl => {
|
||||
await removeRl(rl);
|
||||
if (relation && relation?.id === rl) cleanupEnRlSelection();
|
||||
doRefresh();
|
||||
};
|
||||
|
||||
//При нажатии на панели (пустом месте) диаграммы запроса
|
||||
@ -173,15 +178,7 @@ const QueryEditor = () => {
|
||||
<Grid item xs={5} sx={STYLES.GRID_ITEM_INSPECTOR}>
|
||||
{toolBar}
|
||||
{query && (
|
||||
<QueryOptions
|
||||
query={query}
|
||||
entity={entity}
|
||||
relation={relation}
|
||||
onEntityAdd={handleEntityAdd}
|
||||
onEntityRemove={handleEntityRemove}
|
||||
onRelationRemove={handleRelationRemove}
|
||||
onQueryOptionsChanged={handleQueryOptionsChanged}
|
||||
/>
|
||||
<Inspector {...queryOption} query={query} entity={entity} relation={relation} onOptionsChanged={handleQueryOptionsChanged} />
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user