Закладка "Прогнозирование" - фильтры и сортировки в списке технических объектов, коррекция стилей и сообщений об отсуствии данных
This commit is contained in:
parent
fcdd04cd27
commit
ef520e0932
@ -158,6 +158,22 @@ text="Проверка прав доступа при формировании
|
|||||||
PKG_COND_BROKER.ADD_CONDITION_BETWEEN(SCOLUMN_NAME => 'OPER_DATE',
|
PKG_COND_BROKER.ADD_CONDITION_BETWEEN(SCOLUMN_NAME => 'OPER_DATE',
|
||||||
SCONDITION_NAME_FROM => 'DOPER_DATEFrom',
|
SCONDITION_NAME_FROM => 'DOPER_DATEFrom',
|
||||||
SCONDITION_NAME_TO => 'DOPER_DATETo');
|
SCONDITION_NAME_TO => 'DOPER_DATETo');
|
||||||
|
/* Состояние */
|
||||||
|
PKG_COND_BROKER.ADD_CONDITION_CODE(SCOLUMN_NAME => 'CODE',
|
||||||
|
SCONDITION_NAME => 'SUSE_KINDFrom',
|
||||||
|
SJOINS => 'HLSTATETYPES <- RN;HLSTATETYPES');
|
||||||
|
/* Класс */
|
||||||
|
PKG_COND_BROKER.ADD_CONDITION_CODE(SCOLUMN_NAME => 'NAME',
|
||||||
|
SCONDITION_NAME => 'SOBJ_KINDFrom',
|
||||||
|
SJOINS => 'OBJ_KIND <- RN;EQOBJKIND');
|
||||||
|
/* Модели прогнозирования */
|
||||||
|
if (PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'SEQUIPDSCMMLFrom') = 1) then
|
||||||
|
PKG_COND_BROKER.ADD_CLAUSE(SCLAUSE => 'UPPER(' ||
|
||||||
|
PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_LIST_BY_EQCONFIG') ||
|
||||||
|
'(RN)) like REPLACE(REPLACE(UPPER(:SEQUIPDSCMML), ''?'', ''_''), ''*'', ''%'')');
|
||||||
|
PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'SEQUIPDSCMML',
|
||||||
|
SVALUE => PKG_COND_BROKER.GET_CONDITION_STR(SCONDITION_NAME => 'SEQUIPDSCMMLFrom'));
|
||||||
|
end if;
|
||||||
end EQCONFIG_THOBJ_LIST_COND;
|
end EQCONFIG_THOBJ_LIST_COND;
|
||||||
|
|
||||||
/* Формирование списка технических объектов для выбранного узла состава оборудования */
|
/* Формирование списка технических объектов для выбранного узла состава оборудования */
|
||||||
@ -203,19 +219,27 @@ text="Проверка прав доступа при формировании
|
|||||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
SNAME => 'SCODE',
|
SNAME => 'SCODE',
|
||||||
SCAPTION => 'Обозначение',
|
SCAPTION => 'Обозначение',
|
||||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BORDER => true,
|
||||||
|
BFILTER => true);
|
||||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
SNAME => 'SNAME',
|
SNAME => 'SNAME',
|
||||||
SCAPTION => 'Наименование',
|
SCAPTION => 'Наименование',
|
||||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BORDER => true,
|
||||||
|
BFILTER => true);
|
||||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
SNAME => 'DOPER_DATE',
|
SNAME => 'DOPER_DATE',
|
||||||
SCAPTION => 'Дата ввода в эксплуатацию',
|
SCAPTION => 'Дата ввода в эксплуатацию',
|
||||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE);
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE,
|
||||||
|
BORDER => true,
|
||||||
|
BFILTER => true);
|
||||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
SNAME => 'SUSE_KIND',
|
SNAME => 'SUSE_KIND',
|
||||||
SCAPTION => 'Состояние',
|
SCAPTION => 'Состояние',
|
||||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BORDER => true,
|
||||||
|
BFILTER => true);
|
||||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
SNAME => 'NOBJ_KIND',
|
SNAME => 'NOBJ_KIND',
|
||||||
SCAPTION => 'Рег. номер класса технического объекта',
|
SCAPTION => 'Рег. номер класса технического объекта',
|
||||||
@ -224,11 +248,19 @@ text="Проверка прав доступа при формировании
|
|||||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
SNAME => 'SOBJ_KIND',
|
SNAME => 'SOBJ_KIND',
|
||||||
SCAPTION => 'Класс',
|
SCAPTION => 'Класс',
|
||||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
BORDER => true,
|
||||||
|
BFILTER => true);
|
||||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
SNAME => 'SEQUIPDSCMML',
|
SNAME => 'SEQUIPDSCMML',
|
||||||
SCAPTION => 'Модели прогнозирования',
|
SCAPTION => 'Модели прогнозирования',
|
||||||
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR);
|
SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR,
|
||||||
|
SHINT => '<b>Модели прогнозирования</b> - доступные для использования модели прогнозирования и задачи, ими решаемые:<br>' ||
|
||||||
|
'<b>TCF</b> - Оценка технического состояния (<b>T</b>echnical <b>C</b>ondition <b>F</b>orecast)<br>' ||
|
||||||
|
'<b>RUL</b> - Прогнозирование остаточного ресурса (<b>R</b>emaining <b>U</b>seful <b>L</b>ife)<br>' ||
|
||||||
|
'<b>FP</b> - Прогнозирование отказа (<b>F</b>ailure <b>P</b>redict)',
|
||||||
|
BORDER => true,
|
||||||
|
BFILTER => true);
|
||||||
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
PKG_P8PANELS_VISUAL.TDATA_GRID_ADD_COL_DEF(RDATA_GRID => RDG,
|
||||||
SNAME => 'NEQUIPDSCMML_ACTION',
|
SNAME => 'NEQUIPDSCMML_ACTION',
|
||||||
SCAPTION => 'Действия с моделью',
|
SCAPTION => 'Действия с моделью',
|
||||||
@ -248,7 +280,7 @@ text="Проверка прав доступа при формировании
|
|||||||
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.OPER_DATE DOPER_DATE,');
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.OPER_DATE DOPER_DATE,');
|
||||||
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' ST.CODE SUSE_KIND,');
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' ST.CODE SUSE_KIND,');
|
||||||
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.OBJ_KIND NOBJ_KIND,');
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.OBJ_KIND NOBJ_KIND,');
|
||||||
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' OK.CODE SOBJ_KIND,');
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' OK.NAME SOBJ_KIND,');
|
||||||
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_LIST_BY_EQCONFIG') || '(C.RN) SEQUIPDSCMML,');
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_LIST_BY_EQCONFIG') || '(C.RN) SEQUIPDSCMML,');
|
||||||
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_ACT_BY_EQCONFIG') || '(C.RN) NEQUIPDSCMML_ACTION');
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_ACT_BY_EQCONFIG') || '(C.RN) NEQUIPDSCMML_ACTION');
|
||||||
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from EQCONFIG C');
|
PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from EQCONFIG C');
|
||||||
|
@ -7,13 +7,14 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useState } from "react"; //Классы React
|
import React, { useState, useContext } from "react"; //Классы React
|
||||||
import { Box, Grid } from "@mui/material"; //Интерфейсные компоненты
|
import { Box, Grid } from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; //Дерево
|
import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; //Дерево
|
||||||
|
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||||
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных
|
||||||
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
|
||||||
import { useEqConfigTree, useEqConfigTechObjTable, useEqConfigTechObjCard, findTreeItem, needLoadLevel } from "./forecast_tab_hooks"; //Вспомогательные хуки
|
import { useEqConfigTree, useEqConfigTechObjTable, useEqConfigTechObjCard, findTreeItem, needLoadLevel } from "./forecast_tab_hooks"; //Вспомогательные хуки
|
||||||
import { TechObjCard } from "./forecast_tab_layout"; //Вспомогательные компоненты и вёрстка
|
import { TechObjCard, eqConfigTechObjTableValueFormatter } from "./forecast_tab_layout"; //Вспомогательные компоненты и вёрстка
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -28,6 +29,9 @@ const TABS_HEIGHT = "49px";
|
|||||||
//Высота кнопки "Ещё"
|
//Высота кнопки "Ещё"
|
||||||
const TABLE_MORE_HEIGHT = "49px";
|
const TABLE_MORE_HEIGHT = "49px";
|
||||||
|
|
||||||
|
//Высота фильтров таблицы
|
||||||
|
const TABLE_FILTERS_HEIGHT = "48px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
LEFT_SIDE_GRID: {},
|
LEFT_SIDE_GRID: {},
|
||||||
@ -37,13 +41,19 @@ const STYLES = {
|
|||||||
maxHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`,
|
maxHeight: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT})`,
|
||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
overflowY: "scroll",
|
overflowY: "scroll",
|
||||||
scrollbarWidth: "thin"
|
scrollbarWidth: "thin",
|
||||||
|
padding: "3px"
|
||||||
},
|
},
|
||||||
TECH_OBJ_TABLE: morePages => ({ height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${morePages ? TABLE_MORE_HEIGHT : "0px"})` })
|
TECH_OBJ_TABLE: (morePages, filters) => ({
|
||||||
|
height: `calc(100vh - ${APP_BAR_HEIGHT} - ${TABS_HEIGHT} - ${morePages ? TABLE_MORE_HEIGHT : "0px"} - ${
|
||||||
|
filters ? TABLE_FILTERS_HEIGHT : "0px"
|
||||||
|
})`,
|
||||||
|
scrollbarWidth: "thin"
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
//Начальное состояние спецификации техничких объектов
|
//Начальное состояние спецификации техничких объектов
|
||||||
const TECH_OBJ_SPEC_INIT = { parent: null, filters: null, orders: null, pageNumber: 1 };
|
const TECH_OBJ_SPEC_INIT = { parent: null, filters: [], orders: [], pageNumber: 1 };
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -51,6 +61,9 @@ const TECH_OBJ_SPEC_INIT = { parent: null, filters: null, orders: null, pageNumb
|
|||||||
|
|
||||||
//Закладка прогнозирования
|
//Закладка прогнозирования
|
||||||
const ForecastTab = () => {
|
const ForecastTab = () => {
|
||||||
|
//Подключение к контексту сообщений
|
||||||
|
const { InlineMsgInfo } = useContext(MessagingСtx);
|
||||||
|
|
||||||
//Собственное состояние - текущая загружаемая ветка
|
//Собственное состояние - текущая загружаемая ветка
|
||||||
const [loadingTreeItem, setLoadingTreeItem] = useState(0);
|
const [loadingTreeItem, setLoadingTreeItem] = useState(0);
|
||||||
|
|
||||||
@ -97,41 +110,50 @@ const ForecastTab = () => {
|
|||||||
//При изменении количества отображаемых страниц спецификации технических объектов
|
//При изменении количества отображаемых страниц спецификации технических объектов
|
||||||
const handleTechObjSpecPagesCountChanged = () => setTechObjSpec(pv => ({ ...pv, pageNumber: pv.pageNumber + 1 }));
|
const handleTechObjSpecPagesCountChanged = () => setTechObjSpec(pv => ({ ...pv, pageNumber: pv.pageNumber + 1 }));
|
||||||
|
|
||||||
|
//Текст при отсутствии данных в списке технических объектов
|
||||||
|
const noDataFoundText =
|
||||||
|
techObjsDataGridIsLoading || !techObjsDataGrid.init
|
||||||
|
? "Минуточку..."
|
||||||
|
: techObjSpec.filters.length > 0
|
||||||
|
? "Нет данных, соответствующих условиям отбора"
|
||||||
|
: "Выбранный уровень структуры не содержит данных о технических объектах";
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={4} sx={STYLES.LEFT_SIDE_GRID}>
|
<Grid item xs={3} sx={STYLES.LEFT_SIDE_GRID}>
|
||||||
<Box sx={STYLES.TREE_BOX}>
|
<Box sx={STYLES.TREE_BOX}>
|
||||||
<RichTreeView items={tree} onItemExpansionToggle={handleTreeItemExpansionToggle} onItemFocus={handleTreeItemFocus} />
|
<RichTreeView items={tree} onItemExpansionToggle={handleTreeItemExpansionToggle} onItemFocus={handleTreeItemFocus} />
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={8} sx={STYLES.RIGHT_SIDE_GRID}>
|
<Grid item xs={9} sx={STYLES.RIGHT_SIDE_GRID}>
|
||||||
{techObjCardId ? (
|
{techObjCardId ? (
|
||||||
!techObjCardIsLoading ? (
|
!techObjCardIsLoading ? (
|
||||||
<TechObjCard cardData={techObjCard} />
|
<TechObjCard cardData={techObjCard} />
|
||||||
) : null
|
) : null
|
||||||
) : techObjsDataGrid.init ? (
|
) : techObjsDataGrid.init ? (
|
||||||
<P8PDataGrid
|
<P8PDataGrid
|
||||||
{...{
|
{...{ ...P8P_DATA_GRID_CONFIG_PROPS, noDataFoundText }}
|
||||||
...P8P_DATA_GRID_CONFIG_PROPS,
|
containerComponentProps={{
|
||||||
noDataFoundText:
|
sx: STYLES.TECH_OBJ_TABLE(techObjsDataGrid.morePages, techObjSpec.filters.length > 0),
|
||||||
techObjsDataGridIsLoading || !techObjsDataGrid.init
|
elevation: 0
|
||||||
? "Минуточку..."
|
|
||||||
: "Выбранный уровень структуры не содержит данных о технических объектах"
|
|
||||||
}}
|
}}
|
||||||
containerComponentProps={{ sx: STYLES.TECH_OBJ_TABLE(techObjsDataGrid.morePages), elevation: 0 }}
|
filtersInitial={techObjSpec.filters}
|
||||||
columnsDef={techObjsDataGrid.columnsDef}
|
columnsDef={techObjsDataGrid.columnsDef}
|
||||||
rows={techObjsDataGrid.rows}
|
rows={techObjsDataGrid.rows}
|
||||||
size={P8P_DATA_GRID_SIZE.SMALL}
|
size={P8P_DATA_GRID_SIZE.SMALL}
|
||||||
morePages={techObjsDataGrid.morePages}
|
morePages={techObjsDataGrid.morePages}
|
||||||
fixedHeader={true}
|
fixedHeader={true}
|
||||||
reloading={false}
|
reloading={false}
|
||||||
|
valueFormatter={eqConfigTechObjTableValueFormatter}
|
||||||
onFilterChanged={handleTechObjSpecFilterChanged}
|
onFilterChanged={handleTechObjSpecFilterChanged}
|
||||||
onOrderChanged={handleTechObjSpecOrderChanged}
|
onOrderChanged={handleTechObjSpecOrderChanged}
|
||||||
onPagesCountChanged={handleTechObjSpecPagesCountChanged}
|
onPagesCountChanged={handleTechObjSpecPagesCountChanged}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : (
|
||||||
|
<InlineMsgInfo okBtn={false} text={"Укажите элемент структуры состава оборудования для отображения данных"} />
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@ import { deepCopyObject, object2Base64XML } from "../../core/utils"; //Вспо
|
|||||||
//---------
|
//---------
|
||||||
|
|
||||||
//Размер страницы данных
|
//Размер страницы данных
|
||||||
const DATA_GRID_PAGE_SIZE = 5;
|
const DATA_GRID_PAGE_SIZE = 50;
|
||||||
|
|
||||||
//-----------------------
|
//-----------------------
|
||||||
//Вспомогательные функции
|
//Вспомогательные функции
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
import React from "react"; //Классы React
|
||||||
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Box, Card, CardContent, Typography, CardActions, Button } from "@mui/material"; //Интерфейсные компоненты
|
import { Box, Card, CardContent, Typography, CardActions, Button } from "@mui/material"; //Интерфейсные компоненты
|
||||||
|
import { formatDateRF } from "../../core/utils"; //Вспомогательные функции
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -42,8 +44,22 @@ const TechObjCard = ({ cardData }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Контроль свойств - Карточка технического объекта
|
||||||
|
TechObjCard.propTypes = {
|
||||||
|
cardData: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
//Форматирование значений колонок таблицы технических объектов
|
||||||
|
const eqConfigTechObjTableValueFormatter = ({ value, columnDef }) => {
|
||||||
|
switch (columnDef.name) {
|
||||||
|
case "DOPER_DATE":
|
||||||
|
return formatDateRF(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
//----------------
|
//----------------
|
||||||
//Интерфейс модуля
|
//Интерфейс модуля
|
||||||
//----------------
|
//----------------
|
||||||
|
|
||||||
export { TechObjCard };
|
export { TechObjCard, eqConfigTechObjTableValueFormatter };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user