@evergis/react 4.0.129 → 4.0.131
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Dashboard/componentTypes.d.ts +1 -1
- package/dist/components/Dashboard/components/AddButton/styled.d.ts +15 -0
- package/dist/components/Dashboard/components/index.d.ts +1 -0
- package/dist/components/Dashboard/constants.d.ts +12 -0
- package/dist/components/Dashboard/containers/AttachmentContainer/styled.d.ts +0 -1
- package/dist/components/Dashboard/containers/StructuredDataContainer/constants.d.ts +2 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/hooks/useStructuredData.d.ts +4 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/styled.d.ts +3 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/utils/filterValue.d.ts +3 -2
- package/dist/components/Dashboard/elements/ElementTable/components/TableCell.d.ts +1 -1
- package/dist/components/Dashboard/elements/ElementTable/constants.d.ts +5 -0
- package/dist/components/Dashboard/elements/ElementTable/hooks/useCellEditing.d.ts +25 -9
- package/dist/components/Dashboard/elements/ElementTable/hooks/useHeadOverlap.d.ts +15 -0
- package/dist/components/Dashboard/elements/ElementTable/hooks/useTableView.d.ts +10 -1
- package/dist/components/Dashboard/elements/ElementTable/styled.d.ts +51 -4
- package/dist/components/Dashboard/elements/ElementTable/types.d.ts +5 -0
- package/dist/components/Dashboard/elements/ElementTable/utils/tableBox.d.ts +20 -0
- package/dist/components/Dashboard/hooks/index.d.ts +1 -0
- package/dist/components/Dashboard/hooks/useDataSourceLoading.d.ts +2 -0
- package/dist/components/Dashboard/hooks/useGlobalContext.d.ts +2 -0
- package/dist/components/Dashboard/types.d.ts +8 -6
- package/dist/components/Dashboard/utils/applyQueryFilters.d.ts +3 -1
- package/dist/components/Dashboard/utils/formatDataSourceCondition.d.ts +5 -1
- package/dist/components/Dashboard/utils/getMapViewDataSources.d.ts +7 -0
- package/dist/components/Dashboard/utils/index.d.ts +2 -0
- package/dist/components/Dashboard/utils/toConditionsArray.d.ts +2 -0
- package/dist/contexts/GlobalContext/types.d.ts +4 -0
- package/dist/index.js +445 -127
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +439 -129
- package/dist/react.esm.js.map +1 -1
- package/package.json +3 -3
- package/dist/components/Dashboard/containers/StructuredDataContainer/useStructuredData.d.ts +0 -28
- package/dist/components/Dashboard/containers/StructuredDataContainer/useStructuredDataDraft.d.ts +0 -25
- package/dist/components/Dashboard/containers/StructuredDataContainer/useStructuredDataSave.d.ts +0 -17
- package/dist/components/Dashboard/containers/StructuredDataContainer/useStructuredDataSchema.d.ts +0 -11
- package/dist/components/Dashboard/elements/ElementTable/useCellEditing.d.ts +0 -15
- package/dist/components/Dashboard/elements/ElementTable/useTableView.d.ts +0 -16
package/dist/react.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
2
|
-
import { IconButton, Flex, transition, Chip, shadows, Description, Divider, Icon, Popup, Menu, IconToggleButton, LinearProgress, Tooltip as Tooltip$1, IconToggle, Preview, LegendToggler, DropdownField, MultiSelectContainer, IconButtonButton, useDragAndDropEffect, FlatButton, DraggableTreeContainer, DraggableTree, FlexSpan, Dialog, DialogTitle, ActionsGroup, DialogContent, DialogActions, RaisedButton, UploaderItemArea, UploaderTitleWrapper, ThemeProvider, darkTheme, CircularProgress, Switch, AutoComplete, Input, Slider, Dropdown, Checkbox, DatePicker, getLocale, H2, Blank, Popover, NumberInput, Uploader, NumberRangeSlider, useAsyncAutocomplete, RangeNumberInput, TreeDropdown, defaultTheme, dateFormat } from '@evergis/uilib-gl';
|
|
3
|
-
import { isValidElement, Fragment, createContext, memo, useRef, useState, useCallback, useEffect, useContext, useMemo, createElement, forwardRef } from 'react';
|
|
4
1
|
import styled, { createGlobalStyle, css, useTheme } from 'styled-components';
|
|
2
|
+
import { Icon, IconButtonInnerChild, IconButton, Flex, transition, Chip, shadows, Description, Divider, Popup, Menu, IconToggleButton, LinearProgress, Tooltip as Tooltip$1, IconToggle, Preview, LegendToggler, DropdownField, MultiSelectContainer, IconButtonButton, useDragAndDropEffect, FlatButton, DraggableTreeContainer, DraggableTree, FlexSpan, Dialog, DialogTitle, ActionsGroup, DialogContent, DialogActions, RaisedButton, UploaderItemArea, UploaderTitleWrapper, ThemeProvider, darkTheme, CircularProgress, Switch, AutoComplete, Input, Slider, Dropdown, Checkbox, DatePicker, getLocale, H2, Blank, Popover, NumberInput, Uploader, NumberRangeSlider, useAsyncAutocomplete, RangeNumberInput, TreeDropdown, defaultTheme, dateFormat } from '@evergis/uilib-gl';
|
|
3
|
+
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
4
|
+
import { isValidElement, Fragment, createContext, memo, useRef, useState, useCallback, useEffect, useContext, useMemo, createElement, useLayoutEffect, forwardRef } from 'react';
|
|
5
5
|
import { lineChartClassNames, BarChart as BarChart$1, barChartClassNames, LineChart, PieChart } from '@evergis/charts';
|
|
6
6
|
import { AttributeType, AttributeIconType, generateId, STORAGE_TOKEN_KEY, parseJwt, STORAGE_REFRESH_TOKEN_KEY, RemoteTaskStatus, AttributeConfigurationType, LayerServiceType, OgcGeometryType, StringSubType } from '@evergis/api';
|
|
7
7
|
import { isNil, isEmpty, uniqueId, isEqual, unescape } from 'lodash';
|
|
@@ -28,6 +28,45 @@ import { Terminal } from '@xterm/xterm';
|
|
|
28
28
|
import { FitAddon } from '@xterm/addon-fit';
|
|
29
29
|
import '@xterm/xterm/css/xterm.css';
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Кнопка «добавить»: серая скруглённая, со значком и подписью. Общая на весь дашборд — вложения
|
|
33
|
+
* и таблица структурированных данных добавляют одинаковой кнопкой, разница только в значке.
|
|
34
|
+
*
|
|
35
|
+
* Размеры сняты с макета (все — в половину его пикселей, макет снят на удвоенной плотности):
|
|
36
|
+
* высота 24, поля 10, просвет между значком и подписью 6, значок 14, подпись 14.
|
|
37
|
+
*
|
|
38
|
+
* Скругление и ширина по содержимому — от самого `IconButton`: он скруглён по умолчанию, а с
|
|
39
|
+
* подписью в детях перестаёт держать фиксированную ширину. Значок ужат до 0.875rem: свой 1rem
|
|
40
|
+
* он заполняет краями, и на макете кружок мельче подписи, а не вровень с ней.
|
|
41
|
+
*
|
|
42
|
+
* Подпись темнее значка: `IconButton` красит и то и другое цветом иконки, но в макете подпись —
|
|
43
|
+
* обычный текст (`textPrimary`), а приглушён только значок.
|
|
44
|
+
*/
|
|
45
|
+
const AddButtonRow = styled(IconButton).withConfig({ displayName: "AddButtonRow", componentId: "sc-3ytj1o" }) `
|
|
46
|
+
padding: 0 0.625rem;
|
|
47
|
+
height: 1.5rem;
|
|
48
|
+
background-color: ${({ theme }) => theme.palette.elementDark};
|
|
49
|
+
font-size: 0.875rem;
|
|
50
|
+
|
|
51
|
+
&:hover {
|
|
52
|
+
background-color: ${({ theme }) => theme.palette.elementDeep};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
${Icon} {
|
|
56
|
+
width: 0.875rem;
|
|
57
|
+
height: 0.875rem;
|
|
58
|
+
|
|
59
|
+
&:after {
|
|
60
|
+
font-size: 0.875rem;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
${IconButtonInnerChild} {
|
|
65
|
+
margin-left: 0.375rem;
|
|
66
|
+
color: ${({ theme }) => theme.palette.textPrimary};
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
|
|
31
70
|
const AddFeatureButton = ({ title, icon = "feature_add" /* , layerName, geometryType*/ }) => {
|
|
32
71
|
// const [, handleAddFeature] = useFeatureCreator(layerName, geometryType);
|
|
33
72
|
const handleAddFeature = () => { };
|
|
@@ -3500,6 +3539,18 @@ const DEFAULT_CHART_ANGLE = 4;
|
|
|
3500
3539
|
const DEFAULT_CHART_HEIGHT = 90;
|
|
3501
3540
|
const STACK_BAR_TOTAL_HEIGHT = 20;
|
|
3502
3541
|
const FILTER_PREFIX = "%";
|
|
3542
|
+
/** Имя системного геометрического фильтра — выделение, нарисованное пользователем на карте. */
|
|
3543
|
+
const GEOMETRY_FILTER_NAME = "geometry";
|
|
3544
|
+
/** Имя системного фильтра «экстент видимой области карты» (EWKT, `SRID=3857`). */
|
|
3545
|
+
const EXTENT_FILTER_NAME = "extent";
|
|
3546
|
+
/** Имя системного фильтра «уровень зума карты» (целое число). */
|
|
3547
|
+
const ZOOM_FILTER_NAME = "zoom";
|
|
3548
|
+
/**
|
|
3549
|
+
* Системные фильтры текущего вида карты. Их значения приходят не из `SelectedFilters`, а из
|
|
3550
|
+
* `GlobalContext`, поэтому имена зарезервированы: одноимённый пользовательский фильтр будет
|
|
3551
|
+
* перехвачен системной подстановкой — ровно как в случае `geometry`.
|
|
3552
|
+
*/
|
|
3553
|
+
const MAP_VIEW_FILTER_NAMES = [EXTENT_FILTER_NAME, ZOOM_FILTER_NAME];
|
|
3503
3554
|
const PROVIDER_PREFIX = "$";
|
|
3504
3555
|
var ProviderPrefix;
|
|
3505
3556
|
(function (ProviderPrefix) {
|
|
@@ -4180,7 +4231,7 @@ const getSelectedFilterValue = (filterName, selectedFilters, defaultValue) => {
|
|
|
4180
4231
|
: selectedFilters?.[filterName]?.value) ?? defaultValue);
|
|
4181
4232
|
};
|
|
4182
4233
|
|
|
4183
|
-
const applyQueryFilters = ({ parameters: configParameters, filters: configFilters, selectedFilters, geometry, attributes, layerInfo, dataSources, projectDataSources, }) => {
|
|
4234
|
+
const applyQueryFilters = ({ parameters: configParameters, filters: configFilters, selectedFilters, geometry, extent, zoomLevel, attributes, layerInfo, dataSources, projectDataSources, }) => {
|
|
4184
4235
|
if (!configParameters) {
|
|
4185
4236
|
return {};
|
|
4186
4237
|
}
|
|
@@ -4225,12 +4276,27 @@ const applyQueryFilters = ({ parameters: configParameters, filters: configFilter
|
|
|
4225
4276
|
const [filterName, filterProp] = filterFullName.includes(".") ? filterFullName.split(".") : [filterFullName, null];
|
|
4226
4277
|
const configFilter = getConfigFilter(filterName, configFilters);
|
|
4227
4278
|
const { defaultValue, relatedDataSource, attributeAlias } = configFilter || {};
|
|
4228
|
-
if (filterName ===
|
|
4279
|
+
if (filterName === GEOMETRY_FILTER_NAME && geometry && !geometry.includes("()") && geometry.endsWith(")")) {
|
|
4229
4280
|
return {
|
|
4230
4281
|
...result,
|
|
4231
4282
|
[key]: geometry,
|
|
4232
4283
|
};
|
|
4233
4284
|
}
|
|
4285
|
+
// Системные фильтры вида карты: значение приходит из `GlobalContext`, а не из `SelectedFilters`,
|
|
4286
|
+
// поэтому резолвятся до веток `.min` / `.max` / `.property` — как `geometry` выше.
|
|
4287
|
+
if (filterName === EXTENT_FILTER_NAME && extent) {
|
|
4288
|
+
return {
|
|
4289
|
+
...result,
|
|
4290
|
+
[key]: extent,
|
|
4291
|
+
};
|
|
4292
|
+
}
|
|
4293
|
+
// Единственная нестроковая системная подстановка: уровень зума уходит числом.
|
|
4294
|
+
if (filterName === ZOOM_FILTER_NAME && !isNil(zoomLevel)) {
|
|
4295
|
+
return {
|
|
4296
|
+
...result,
|
|
4297
|
+
[key]: zoomLevel,
|
|
4298
|
+
};
|
|
4299
|
+
}
|
|
4234
4300
|
if (configParameters[key].endsWith(".max")) {
|
|
4235
4301
|
return {
|
|
4236
4302
|
...result,
|
|
@@ -4481,7 +4547,7 @@ const applyFiltersToCondition = ({ condition, name, defaultValue, filters, isSin
|
|
|
4481
4547
|
}
|
|
4482
4548
|
return isSingle && isNumeric(result) ? Number(result) : result;
|
|
4483
4549
|
};
|
|
4484
|
-
const applyVarsToCondition = ({ section, configFilters, filters, attributes, layerParams, eqlParameters, geometry, isSetParams, }) => {
|
|
4550
|
+
const applyVarsToCondition = ({ section, configFilters, filters, attributes, layerParams, eqlParameters, geometry, extent, zoomLevel, isSetParams, }) => {
|
|
4485
4551
|
if (!section?.length)
|
|
4486
4552
|
return [];
|
|
4487
4553
|
const isSingle = typeof section === "string";
|
|
@@ -4490,6 +4556,17 @@ const applyVarsToCondition = ({ section, configFilters, filters, attributes, lay
|
|
|
4490
4556
|
if (geometry && !geometry.includes("()") && geometry.endsWith(")")) {
|
|
4491
4557
|
result[index] = result[index].replace(new RegExp("%geometry"), `'${geometry}'`);
|
|
4492
4558
|
}
|
|
4559
|
+
// Системные фильтры вида карты подставляются ДО цикла по `configFilters`: одноимённый
|
|
4560
|
+
// пользовательский фильтр не должен перехватывать `%extent` / `%zoom`. Lookahead `(?![\w.])`
|
|
4561
|
+
// оставляет фильтрам составные формы (`%zoomLevel`, `%extent_id`, `%zoom.min`) — та же
|
|
4562
|
+
// граница, что уже разводит `%name` и `%name2.l1` в `getUpdatingDataSources`.
|
|
4563
|
+
if (extent) {
|
|
4564
|
+
result[index] = result[index].replace(new RegExp(`${FILTER_PREFIX}${EXTENT_FILTER_NAME}(?![\\w.])`, "g"), `'${extent}'`);
|
|
4565
|
+
}
|
|
4566
|
+
// Зум — число, кавычки не ставим.
|
|
4567
|
+
if (!isNil(zoomLevel)) {
|
|
4568
|
+
result[index] = result[index].replace(new RegExp(`${FILTER_PREFIX}${ZOOM_FILTER_NAME}(?![\\w.])`, "g"), String(zoomLevel));
|
|
4569
|
+
}
|
|
4493
4570
|
if (configFilters?.length) {
|
|
4494
4571
|
configFilters.forEach(filter => {
|
|
4495
4572
|
result[index] = applyFiltersToCondition({
|
|
@@ -4518,7 +4595,7 @@ const applyVarsToCondition = ({ section, configFilters, filters, attributes, lay
|
|
|
4518
4595
|
});
|
|
4519
4596
|
return isSingle ? result?.[0] : result;
|
|
4520
4597
|
};
|
|
4521
|
-
const formatSingleCondition = (condition, { configFilters, filters, attributes, eqlParameters, layerParams, geometry }) => {
|
|
4598
|
+
const formatSingleCondition = (condition, { configFilters, filters, attributes, eqlParameters, layerParams, geometry, extent, zoomLevel, }) => {
|
|
4522
4599
|
const setParams = condition.match(new RegExp("\\$\\([^)]+\\)", "g"));
|
|
4523
4600
|
const setParamsSection = applyVarsToCondition({
|
|
4524
4601
|
section: setParams,
|
|
@@ -4528,6 +4605,8 @@ const formatSingleCondition = (condition, { configFilters, filters, attributes,
|
|
|
4528
4605
|
eqlParameters,
|
|
4529
4606
|
layerParams,
|
|
4530
4607
|
geometry,
|
|
4608
|
+
extent,
|
|
4609
|
+
zoomLevel,
|
|
4531
4610
|
isSetParams: true,
|
|
4532
4611
|
});
|
|
4533
4612
|
const splitter = " AND ";
|
|
@@ -4540,6 +4619,8 @@ const formatSingleCondition = (condition, { configFilters, filters, attributes,
|
|
|
4540
4619
|
eqlParameters,
|
|
4541
4620
|
layerParams,
|
|
4542
4621
|
geometry,
|
|
4622
|
+
extent,
|
|
4623
|
+
zoomLevel,
|
|
4543
4624
|
});
|
|
4544
4625
|
return setParamsSection?.length && conditionSection.length
|
|
4545
4626
|
? [setParamsSection.join(""), conditionSection.join(splitter)].join(" ")
|
|
@@ -6317,7 +6398,7 @@ const useAttachmentItems = ({ type, elementConfig, valueOverride, }) => {
|
|
|
6317
6398
|
};
|
|
6318
6399
|
|
|
6319
6400
|
const useGlobalContext = () => {
|
|
6320
|
-
const { t, language, themeName, api, ewktGeometry, notification } = useContext(GlobalContext) || {};
|
|
6401
|
+
const { t, language, themeName, api, ewktGeometry, ewktExtent, zoomLevel, notification } = useContext(GlobalContext) || {};
|
|
6321
6402
|
const translate = useCallback((value, options) => {
|
|
6322
6403
|
if (t)
|
|
6323
6404
|
return t(value, options);
|
|
@@ -6329,8 +6410,10 @@ const useGlobalContext = () => {
|
|
|
6329
6410
|
themeName,
|
|
6330
6411
|
api,
|
|
6331
6412
|
ewktGeometry,
|
|
6413
|
+
ewktExtent,
|
|
6414
|
+
zoomLevel,
|
|
6332
6415
|
notification,
|
|
6333
|
-
}), [language, translate, api, ewktGeometry, themeName, notification]);
|
|
6416
|
+
}), [language, translate, api, ewktGeometry, ewktExtent, zoomLevel, themeName, notification]);
|
|
6334
6417
|
};
|
|
6335
6418
|
|
|
6336
6419
|
const GRID_TILE_SIZE = "4.5rem";
|
|
@@ -7136,10 +7219,17 @@ const useDashboardHeader = () => {
|
|
|
7136
7219
|
};
|
|
7137
7220
|
};
|
|
7138
7221
|
|
|
7222
|
+
// Полноэкранная заглушка допустима только пока не пришёл ни один источник: дальше страницу
|
|
7223
|
+
// и модалку наполняют сами контейнеры — у каждого свой ContainerLoading / ChartLoading.
|
|
7224
|
+
const useDataSourceLoading = (type) => {
|
|
7225
|
+
const { dataSources, isLoading } = useWidgetContext(type);
|
|
7226
|
+
const { currentPage } = useWidgetPage(type);
|
|
7227
|
+
return useMemo(() => !!currentPage?.dataSources?.length && !dataSources?.length && !!isLoading, [currentPage?.dataSources?.length, dataSources?.length, isLoading]);
|
|
7228
|
+
};
|
|
7229
|
+
|
|
7139
7230
|
/* eslint-disable max-lines */
|
|
7140
|
-
const toConditionsArray = (value) => Array.isArray(value) ? value : value ? [value] : [];
|
|
7141
7231
|
const useDataSources = ({ type: widgetType, config, attributes, filters, layerParams, eqlParameters, }) => {
|
|
7142
|
-
const { ewktGeometry, api } = useGlobalContext();
|
|
7232
|
+
const { ewktGeometry, ewktExtent, zoomLevel, api } = useGlobalContext();
|
|
7143
7233
|
const { dataSources, layerInfo } = useWidgetContext(widgetType);
|
|
7144
7234
|
const { dataSources: projectDataSources } = useWidgetContext(WidgetType.Dashboard);
|
|
7145
7235
|
const { filters: configFilters, dataSources: configDataSources } = config || {};
|
|
@@ -7167,6 +7257,8 @@ const useDataSources = ({ type: widgetType, config, attributes, filters, layerPa
|
|
|
7167
7257
|
attributes,
|
|
7168
7258
|
filters: configFilters,
|
|
7169
7259
|
geometry: ewktGeometry,
|
|
7260
|
+
extent: ewktExtent,
|
|
7261
|
+
zoomLevel,
|
|
7170
7262
|
layerInfo,
|
|
7171
7263
|
dataSources,
|
|
7172
7264
|
projectDataSources,
|
|
@@ -7241,6 +7333,8 @@ const useDataSources = ({ type: widgetType, config, attributes, filters, layerPa
|
|
|
7241
7333
|
configFilters,
|
|
7242
7334
|
filters: selectedFilters,
|
|
7243
7335
|
geometry: ewktGeometry,
|
|
7336
|
+
extent: ewktExtent,
|
|
7337
|
+
zoomLevel,
|
|
7244
7338
|
attributes,
|
|
7245
7339
|
layerParams,
|
|
7246
7340
|
eqlParameters,
|
|
@@ -7262,6 +7356,8 @@ const useDataSources = ({ type: widgetType, config, attributes, filters, layerPa
|
|
|
7262
7356
|
dataSources,
|
|
7263
7357
|
configFilters,
|
|
7264
7358
|
ewktGeometry,
|
|
7359
|
+
ewktExtent,
|
|
7360
|
+
zoomLevel,
|
|
7265
7361
|
api,
|
|
7266
7362
|
attributes,
|
|
7267
7363
|
layerParams,
|
|
@@ -8733,19 +8829,10 @@ const ShowMoreButton$1 = styled.div.withConfig({ displayName: "ShowMoreButton",
|
|
|
8733
8829
|
const AddButtonContainer = styled.div.withConfig({ displayName: "AddButtonContainer", componentId: "sc-1yphz1r" }) `
|
|
8734
8830
|
margin-top: 0.75rem;
|
|
8735
8831
|
`;
|
|
8736
|
-
const
|
|
8737
|
-
padding: 0 0.75rem;
|
|
8738
|
-
height: 1.5rem;
|
|
8739
|
-
background-color: ${({ theme }) => theme.palette.elementDark};
|
|
8740
|
-
|
|
8741
|
-
&:hover {
|
|
8742
|
-
background-color: ${({ theme }) => theme.palette.elementDeep};
|
|
8743
|
-
}
|
|
8744
|
-
`;
|
|
8745
|
-
const HiddenFileInput = styled.input.withConfig({ displayName: "HiddenFileInput", componentId: "sc-kgi0m7" }) `
|
|
8832
|
+
const HiddenFileInput = styled.input.withConfig({ displayName: "HiddenFileInput", componentId: "sc-3apzla" }) `
|
|
8746
8833
|
display: none;
|
|
8747
8834
|
`;
|
|
8748
|
-
const LinkDialogContent = styled.div.withConfig({ displayName: "LinkDialogContent", componentId: "sc-
|
|
8835
|
+
const LinkDialogContent = styled.div.withConfig({ displayName: "LinkDialogContent", componentId: "sc-1kihzpg" }) `
|
|
8749
8836
|
display: flex;
|
|
8750
8837
|
flex-direction: column;
|
|
8751
8838
|
width: 100%;
|
|
@@ -10936,6 +11023,9 @@ const StructuredDataActions = styled(Flex).withConfig({ displayName: "Structured
|
|
|
10936
11023
|
/**
|
|
10937
11024
|
* Область представления. Прокручивается внутри себя, чтобы длинная таблица не растягивала
|
|
10938
11025
|
* контейнер за пределы отведённой ему ячейки; `min-height: 0` разрешает flex-ребёнку сжиматься.
|
|
11026
|
+
*
|
|
11027
|
+
* Собственный бокс таблицы (`options.width`/`height` представления) живёт внутри и на эту
|
|
11028
|
+
* прокрутку не влияет: он ограничивает саму таблицу, а не отведённое контейнером место.
|
|
10939
11029
|
*/
|
|
10940
11030
|
const StructuredDataView = styled(Flex).withConfig({ displayName: "StructuredDataView", componentId: "sc-1ws3t0d" }) `
|
|
10941
11031
|
flex-direction: column;
|
|
@@ -10952,6 +11042,33 @@ const StructuredDataView = styled(Flex).withConfig({ displayName: "StructuredDat
|
|
|
10952
11042
|
*/
|
|
10953
11043
|
const StructuredDataContext = createContext(null);
|
|
10954
11044
|
|
|
11045
|
+
/** Слот представления: единственный ребёнок контейнера, рисующий данные (элемент `table`). */
|
|
11046
|
+
const STRUCTURED_DATA_VIEW_SLOT = "data";
|
|
11047
|
+
/**
|
|
11048
|
+
* Типы атрибутов с редактором ячейки. Атрибут любого другого типа показывается только на чтение,
|
|
11049
|
+
* даже если помечен `isEditable: true` — редактора для него нет.
|
|
11050
|
+
*/
|
|
11051
|
+
const EDITABLE_ATTRIBUTE_TYPES = [
|
|
11052
|
+
AttributeType.String,
|
|
11053
|
+
AttributeType.Int32,
|
|
11054
|
+
AttributeType.Int64,
|
|
11055
|
+
AttributeType.Double,
|
|
11056
|
+
AttributeType.Boolean,
|
|
11057
|
+
AttributeType.DateTime,
|
|
11058
|
+
];
|
|
11059
|
+
/** Типы, для которых ячейка редактируется числовым инпутом. */
|
|
11060
|
+
const NUMBER_EDITOR_TYPES = [
|
|
11061
|
+
AttributeType.Int32,
|
|
11062
|
+
AttributeType.Int64,
|
|
11063
|
+
AttributeType.Double,
|
|
11064
|
+
];
|
|
11065
|
+
/** Типы, значение которых хранится целым числом — дробную часть в них не пускаем. */
|
|
11066
|
+
const INTEGER_ATTRIBUTE_TYPES = [AttributeType.Int32, AttributeType.Int64];
|
|
11067
|
+
/** Тип атрибута, когда его не задали ни конфиг, ни источник. */
|
|
11068
|
+
const DEFAULT_ATTRIBUTE_TYPE = AttributeType.String;
|
|
11069
|
+
/** Сколько миллисекунд висит нотификация об ошибке записи. */
|
|
11070
|
+
const SAVE_ERROR_DURATION = 5000;
|
|
11071
|
+
|
|
10955
11072
|
/**
|
|
10956
11073
|
* Оставляет от произвольного набора свойств только атрибуты схемы. Отсутствующие добавляет
|
|
10957
11074
|
* как `null`: строка всегда имеет одинаковый набор ключей, иначе представление и
|
|
@@ -10989,8 +11106,9 @@ const getEditableProperties = (row, schema) => schema
|
|
|
10989
11106
|
/**
|
|
10990
11107
|
* Строки черновика → значение фильтра `valueType: "features"`.
|
|
10991
11108
|
*
|
|
10992
|
-
* В `properties`
|
|
10993
|
-
*
|
|
11109
|
+
* В `properties` попадает ровно схема: значения по её атрибутам, включая незаполненные. Лишние
|
|
11110
|
+
* ключи черновика (пришли из источника, остались от прежней схемы) наружу не уходят, а объявленный
|
|
11111
|
+
* атрибут уходит всегда. Геометрия не поддерживается — `geometry: null`.
|
|
10994
11112
|
*/
|
|
10995
11113
|
const toFeaturesFilterValue = (rows, schema) => ({
|
|
10996
11114
|
type: "FeatureCollection",
|
|
@@ -11039,14 +11157,17 @@ const useStructuredDataDraft = ({ schema, dataSource, hasDataSource, filterValue
|
|
|
11039
11157
|
}, [applyBaseline, features, hasDataSource, schema]);
|
|
11040
11158
|
// Ручная структура гидратируется из фильтра один раз: дальше значение фильтра пишем мы сами,
|
|
11041
11159
|
// и повторная гидратация только пересоздавала бы ключи строк.
|
|
11160
|
+
//
|
|
11161
|
+
// Флаг взводится по факту гидратации, а не авансом: значение может приехать позже схемы
|
|
11162
|
+
// (восстановленный выбор пользователя — асинхронно, в отличие от `defaultValue` из конфига),
|
|
11163
|
+
// и окно не должно сгорать на пустом первом рендере. Грязный черновик значение не затирает.
|
|
11042
11164
|
useEffect(() => {
|
|
11043
|
-
|
|
11165
|
+
const canHydrate = !hasDataSource && !hydrated.current && !dirtyRef.current && !!schema.length;
|
|
11166
|
+
if (!canHydrate || !isFeaturesFilterValue(filterValue)) {
|
|
11044
11167
|
return;
|
|
11045
11168
|
}
|
|
11046
11169
|
hydrated.current = true;
|
|
11047
|
-
|
|
11048
|
-
applyBaseline(fromFeaturesFilterValue(filterValue, schema));
|
|
11049
|
-
}
|
|
11170
|
+
applyBaseline(fromFeaturesFilterValue(filterValue, schema));
|
|
11050
11171
|
}, [applyBaseline, filterValue, hasDataSource, schema]);
|
|
11051
11172
|
const changeCell = useCallback((key, attributeName, value) => {
|
|
11052
11173
|
setRows(current => current.map(row => row.key === key
|
|
@@ -11069,36 +11190,16 @@ const useStructuredDataDraft = ({ schema, dataSource, hasDataSource, filterValue
|
|
|
11069
11190
|
}, []));
|
|
11070
11191
|
}, []);
|
|
11071
11192
|
const reset = useCallback(() => setRows(baseline.current), []);
|
|
11072
|
-
const commitSaved = useCallback((next) =>
|
|
11193
|
+
const commitSaved = useCallback((next) => {
|
|
11194
|
+
// Сохранённое состояние — наше: значение фильтра теперь пишем мы, и вернувшееся из него
|
|
11195
|
+
// обновление не должно пересоздавать ключи уже показанных строк.
|
|
11196
|
+
hydrated.current = true;
|
|
11197
|
+
applyBaseline(next);
|
|
11198
|
+
}, [applyBaseline]);
|
|
11073
11199
|
const visibleRows = useMemo(() => rows.filter(({ state }) => state !== "deleted"), [rows]);
|
|
11074
11200
|
return { rows, visibleRows, dirty, changeCell, addRow, deleteRow, reset, commitSaved };
|
|
11075
11201
|
};
|
|
11076
11202
|
|
|
11077
|
-
/**
|
|
11078
|
-
* Типы атрибутов с редактором ячейки. Атрибут любого другого типа показывается только на чтение,
|
|
11079
|
-
* даже если помечен `isEditable: true` — редактора для него нет.
|
|
11080
|
-
*/
|
|
11081
|
-
const EDITABLE_ATTRIBUTE_TYPES = [
|
|
11082
|
-
AttributeType.String,
|
|
11083
|
-
AttributeType.Int32,
|
|
11084
|
-
AttributeType.Int64,
|
|
11085
|
-
AttributeType.Double,
|
|
11086
|
-
AttributeType.Boolean,
|
|
11087
|
-
AttributeType.DateTime,
|
|
11088
|
-
];
|
|
11089
|
-
/** Типы, для которых ячейка редактируется числовым инпутом. */
|
|
11090
|
-
const NUMBER_EDITOR_TYPES = [
|
|
11091
|
-
AttributeType.Int32,
|
|
11092
|
-
AttributeType.Int64,
|
|
11093
|
-
AttributeType.Double,
|
|
11094
|
-
];
|
|
11095
|
-
/** Типы, значение которых хранится целым числом — дробную часть в них не пускаем. */
|
|
11096
|
-
const INTEGER_ATTRIBUTE_TYPES = [AttributeType.Int32, AttributeType.Int64];
|
|
11097
|
-
/** Тип атрибута, когда его не задали ни конфиг, ни источник. */
|
|
11098
|
-
const DEFAULT_ATTRIBUTE_TYPE = AttributeType.String;
|
|
11099
|
-
/** Сколько миллисекунд висит нотификация об ошибке записи. */
|
|
11100
|
-
const SAVE_ERROR_DURATION = 5000;
|
|
11101
|
-
|
|
11102
11203
|
/**
|
|
11103
11204
|
* Применяет черновик к слою источника: удаление → обновление → создание.
|
|
11104
11205
|
*
|
|
@@ -11265,13 +11366,19 @@ const useStructuredDataSchema = (type, elementConfig) => {
|
|
|
11265
11366
|
* Вид источника на права правки не влияет — от него зависит только адресат «Сохранить». Слой
|
|
11266
11367
|
* принимает запись через features-API, источник без `layerName` (EQL, python-скрипт, внешний
|
|
11267
11368
|
* url) не принимает ничего, и правка такой таблицы уходит только в фильтр.
|
|
11369
|
+
*
|
|
11370
|
+
* Значение фильтра читается так же, как его читают остальные потребители дашборда: выбор
|
|
11371
|
+
* пользователя, а пока его нет — `defaultValue` из конфига фильтра. Общего стейта, залитого
|
|
11372
|
+
* дефолтами, в дашборде нет, поэтому фолбэк делает каждый потребитель сам.
|
|
11268
11373
|
*/
|
|
11269
11374
|
const useStructuredData = (type, elementConfig) => {
|
|
11270
11375
|
const { filters } = useWidgetContext(type);
|
|
11376
|
+
const { currentPage } = useWidgetPage(type);
|
|
11271
11377
|
const { relatedDataSource, filterName, editMode } = elementConfig?.options || {};
|
|
11272
11378
|
const { schema, dataSource, layerName } = useStructuredDataSchema(type, elementConfig);
|
|
11273
11379
|
const hasDataSource = !!relatedDataSource;
|
|
11274
|
-
const
|
|
11380
|
+
const configFilter = useMemo(() => getConfigFilter(filterName, currentPage?.filters), [currentPage?.filters, filterName]);
|
|
11381
|
+
const filterValue = useMemo(() => (filterName ? filters?.[filterName]?.value ?? configFilter?.defaultValue : undefined), [configFilter?.defaultValue, filterName, filters]);
|
|
11275
11382
|
const { rows, visibleRows, dirty, changeCell, addRow, deleteRow, reset, commitSaved } = useStructuredDataDraft({
|
|
11276
11383
|
schema,
|
|
11277
11384
|
dataSource,
|
|
@@ -11344,7 +11451,7 @@ const StructuredDataContainer = memo(({ type, elementConfig, isVisible, renderEl
|
|
|
11344
11451
|
if (hasError) {
|
|
11345
11452
|
return jsx(DataSourceError, { name: elementConfig?.templateName });
|
|
11346
11453
|
}
|
|
11347
|
-
return (jsxs(ContainerRoot, { ...root, children: [jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxs(Container, { ...body, isColumn: true, children: [jsx(StructuredDataView, { children: jsx(StructuredDataContext.Provider, { value: contextValue, children: renderElement({ id:
|
|
11454
|
+
return (jsxs(ContainerRoot, { ...root, children: [jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxs(Container, { ...body, isColumn: true, children: [jsx(StructuredDataView, { children: jsx(StructuredDataContext.Provider, { value: contextValue, children: renderElement({ id: STRUCTURED_DATA_VIEW_SLOT }) }) }), canEdit && (jsxs(StructuredDataToolbar, { children: [jsx(StructuredDataActions, { children: jsx(AddButtonRow, { kind: "feature_add", tabIndex: 0, disabled: saving, onClick: onAddRow, children: t("actions.add", { ns: "common", defaultValue: "Добавить" }) }) }), dirty && (jsxs(StructuredDataActions, { children: [jsx(IconButton, { error: true, kind: "close", tabIndex: 0, disabled: saving, title: t("actions.cancel", { ns: "common", defaultValue: "Отменить" }), onClick: onCancel }), jsx(IconButton, { primary: true, kind: "success", tabIndex: 0, disabled: saving, title: t("actions.save", { ns: "common", defaultValue: "Сохранить" }), onClick: onSave })] }))] }))] })), jsx(DeleteRowDialog, { isOpen: isDeleteConfirmOpen, isSourceRow: isDeletingSourceRow, onConfirm: onDeleteConfirm, onCancel: onDeleteCancel })] }));
|
|
11348
11455
|
});
|
|
11349
11456
|
|
|
11350
11457
|
const TabAnchor = styled.div.withConfig({ displayName: "TabAnchor", componentId: "sc-emqf31" }) `
|
|
@@ -14295,28 +14402,86 @@ const ElementSvg = memo(({ type, elementConfig, ...rest }) => {
|
|
|
14295
14402
|
return (jsx(SvgImage, { url: getSvgUrl({ elementConfig, layerInfo, attributes }), width: width, height: height, fontColor: fontColor }));
|
|
14296
14403
|
});
|
|
14297
14404
|
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14405
|
+
/**
|
|
14406
|
+
* Насколько тело таблицы заехало под липкую шапку. Пишется на таблицу при прокрутке, читается
|
|
14407
|
+
* стилем тела: ровно на эту величину тело и отсекается.
|
|
14408
|
+
*/
|
|
14409
|
+
const HEAD_OVERLAP_VARIABLE = "--table-head-overlap";
|
|
14410
|
+
/**
|
|
14411
|
+
* Признак времени в шаблоне `stringFormat.format`.
|
|
14412
|
+
*
|
|
14413
|
+
* Варианты времени в конфигурации атрибута — `hh:mm`, `hh:mm tt`, `hh:mm:ss`, `hh:mm:ss tt`
|
|
14414
|
+
* (см. `timeOptions` в `utils/format`), поэтому достаточно найти часы с минутами.
|
|
14415
|
+
*/
|
|
14416
|
+
const TIME_FORMAT = /hh:mm/;
|
|
14417
|
+
/**
|
|
14418
|
+
* Контейнер порталов `@evergis/uilib-gl` — в него попадают выпадающие слои контролов,
|
|
14419
|
+
* в том числе календарь `DatePicker`. Клик по ним DOM-деревом лежит вне ячейки, поэтому
|
|
14420
|
+
* закрытие редактора по клику снаружи обязано этот контейнер пропускать.
|
|
14421
|
+
*/
|
|
14422
|
+
const PORTAL_ROOT_SELECTOR = "#portal-root";
|
|
14423
|
+
|
|
14424
|
+
/**
|
|
14425
|
+
* Собственный бокс таблицы. Без размеров в `options` представления узел ничего не меняет:
|
|
14426
|
+
* таблица растёт под содержимое, а прокручивает лишнее область представления контейнера.
|
|
14427
|
+
*
|
|
14428
|
+
* С размерами бокс становится её скролл-контейнером — и липкая шапка липнет уже к нему.
|
|
14429
|
+
*/
|
|
14430
|
+
const TableBox = styled.div.withConfig({ displayName: "TableBox", componentId: "sc-19vtvuq" }) `
|
|
14431
|
+
min-width: 0;
|
|
14432
|
+
|
|
14433
|
+
${sizeCssMixin};
|
|
14434
|
+
`;
|
|
14435
|
+
/**
|
|
14436
|
+
* Таблица. По умолчанию втискивается в ширину, которую ей дали: колонкам достаётся то, что есть,
|
|
14437
|
+
* а длинные значения режутся многоточием внутри ячейки.
|
|
14438
|
+
*
|
|
14439
|
+
* `$contentWidth` (ширина бокса задана в `options`) переводит её на ширину по содержимому:
|
|
14440
|
+
* колонки встают по своим значениям, предел ячейки снимается, и всё, что не влезло, уходит
|
|
14441
|
+
* в горизонтальную прокрутку бокса. Иначе вышла бы бессмыслица — бокс с прокруткой, а значения
|
|
14442
|
+
* всё равно с многоточием. `min-width` оставляет таблицу растянутой на весь бокс, когда
|
|
14443
|
+
* содержимого на его ширину не набирается.
|
|
14444
|
+
*
|
|
14445
|
+
* Снятый предел ширины ячейки едет вниз css-переменной, а не правилом по `TableCellWrapper`:
|
|
14446
|
+
* ячейка объявлена ниже по файлу, и селектор по ней отсюда попал бы в TDZ.
|
|
14447
|
+
*/
|
|
14448
|
+
const TableWrapper = styled.table.withConfig({ displayName: "TableWrapper", componentId: "sc-ih9qqq" }) `
|
|
14449
|
+
width: ${({ $contentWidth }) => ($contentWidth ? "max-content" : "100%")};
|
|
14450
|
+
min-width: 100%;
|
|
14451
|
+
/*
|
|
14452
|
+
* Рамки раздельные (со схлопнутым интервалом, поэтому выглядят как схлопнутые). Схлопнутые
|
|
14453
|
+
* рисует сама таблица, а не ячейки, и отсечка тела их не режет: линия строки, уехавшей под
|
|
14454
|
+
* шапку, продолжала бы рисоваться поверх заголовков.
|
|
14455
|
+
*/
|
|
14456
|
+
border-collapse: separate;
|
|
14457
|
+
border-spacing: 0;
|
|
14301
14458
|
font-size: 0.875rem;
|
|
14459
|
+
|
|
14460
|
+
${({ $contentWidth }) => !!$contentWidth &&
|
|
14461
|
+
css `
|
|
14462
|
+
--table-cell-max-width: none;
|
|
14463
|
+
`};
|
|
14302
14464
|
`;
|
|
14303
14465
|
/**
|
|
14304
14466
|
* Шапка липнет к верху области прокрутки — при длинной таблице заголовки остаются видны.
|
|
14305
14467
|
*
|
|
14306
|
-
*
|
|
14307
|
-
*
|
|
14468
|
+
* Своего фона у неё нет и не должно быть: контейнер дашборда красится цветом из конфига, и любой
|
|
14469
|
+
* назначенный шапке цвет остался бы прямоугольником чужого цвета, как только фон контейнера
|
|
14470
|
+
* поменяли. Под шапкой виден фон контейнера, а строки под неё не заезжают — тело отсечено
|
|
14471
|
+
* (см. TableBody и useHeadOverlap).
|
|
14308
14472
|
*/
|
|
14309
|
-
const TableHead = styled.thead.withConfig({ displayName: "TableHead", componentId: "sc-
|
|
14473
|
+
const TableHead = styled.thead.withConfig({ displayName: "TableHead", componentId: "sc-m8fpi" }) `
|
|
14310
14474
|
position: sticky;
|
|
14311
14475
|
top: 0;
|
|
14312
14476
|
z-index: 1;
|
|
14313
14477
|
`;
|
|
14314
|
-
const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", componentId: "sc-
|
|
14478
|
+
const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", componentId: "sc-1m6xil2" }) `
|
|
14315
14479
|
padding: 0.375rem 0.5rem;
|
|
14316
14480
|
text-align: left;
|
|
14317
14481
|
font-weight: 600;
|
|
14318
14482
|
white-space: nowrap;
|
|
14319
14483
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
14484
|
+
/* Рамка принадлежит ячейке (рамки раздельные), поэтому едет вместе с липкой шапкой. */
|
|
14320
14485
|
border-bottom: 1px solid ${({ theme }) => theme.palette.elementDeep};
|
|
14321
14486
|
|
|
14322
14487
|
${({ $sortable }) => $sortable &&
|
|
@@ -14325,25 +14490,50 @@ const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", compo
|
|
|
14325
14490
|
user-select: none;
|
|
14326
14491
|
`}
|
|
14327
14492
|
`;
|
|
14328
|
-
const TableHeadContent = styled.span.withConfig({ displayName: "TableHeadContent", componentId: "sc-
|
|
14493
|
+
const TableHeadContent = styled.span.withConfig({ displayName: "TableHeadContent", componentId: "sc-8hzcop" }) `
|
|
14329
14494
|
display: inline-flex;
|
|
14330
14495
|
align-items: center;
|
|
14331
14496
|
gap: 0.25rem;
|
|
14332
14497
|
`;
|
|
14333
|
-
|
|
14334
|
-
|
|
14498
|
+
/**
|
|
14499
|
+
* Место под значок сортировки. Занято всегда, пока сортировка включена, а сам значок только
|
|
14500
|
+
* прячется: появляясь и исчезая, он менял бы ширину колонки — и таблицу дёргало бы на каждый
|
|
14501
|
+
* клик по заголовку, вместе с телом. Оба направления рисуются значком в 1rem, поэтому
|
|
14502
|
+
* переключение asc/des ширину тоже не трогает.
|
|
14503
|
+
*/
|
|
14504
|
+
const TableSortSlot = styled.span.withConfig({ displayName: "TableSortSlot", componentId: "sc-z378vf" }) `
|
|
14505
|
+
display: inline-flex;
|
|
14506
|
+
visibility: ${({ $active }) => ($active ? "visible" : "hidden")};
|
|
14335
14507
|
`;
|
|
14336
|
-
|
|
14508
|
+
/**
|
|
14509
|
+
* Тело таблицы. Отсекается ровно на то, на сколько его накрыла липкая шапка: строки уходят под
|
|
14510
|
+
* её нижнюю кромку и сквозь прозрачную шапку не проступают. Величину пишет {@link useHeadOverlap},
|
|
14511
|
+
* без неё отсечка нулевая и разметка не меняется.
|
|
14512
|
+
*/
|
|
14513
|
+
const TableBody = styled.tbody.withConfig({ displayName: "TableBody", componentId: "sc-1pxpl5v" }) `
|
|
14514
|
+
clip-path: inset(var(${HEAD_OVERLAP_VARIABLE}, 0px) 0 0 0);
|
|
14515
|
+
`;
|
|
14516
|
+
/**
|
|
14517
|
+
* Строка. Разделитель рисуют её ячейки: собственная рамка строки при раздельных рамках не
|
|
14518
|
+
* рисуется вовсе, а при схлопнутых её рисовала бы таблица — и отсечка тела её бы не резала.
|
|
14519
|
+
*/
|
|
14520
|
+
const TableRow = styled.tr.withConfig({ displayName: "TableRow", componentId: "sc-j62zvd" }) `
|
|
14521
|
+
td {
|
|
14522
|
+
border-bottom: 1px solid ${({ theme }) => theme.palette.elementDeep};
|
|
14523
|
+
}
|
|
14524
|
+
`;
|
|
14525
|
+
const TableCellWrapper = styled.td.withConfig({ displayName: "TableCellWrapper", componentId: "sc-ziu5rk" }) `
|
|
14337
14526
|
padding: 0.125rem 0.25rem;
|
|
14338
14527
|
vertical-align: middle;
|
|
14339
|
-
|
|
14528
|
+
/* Предел снимает заданная ширина: с колонками по содержимому обрезать значение незачем. */
|
|
14529
|
+
max-width: var(--table-cell-max-width, 20rem);
|
|
14340
14530
|
`;
|
|
14341
14531
|
/** Колонка действий: узкая, не растягивается содержимым. */
|
|
14342
|
-
const TableActionsCell = styled(TableCellWrapper).withConfig({ displayName: "TableActionsCell", componentId: "sc-
|
|
14532
|
+
const TableActionsCell = styled(TableCellWrapper).withConfig({ displayName: "TableActionsCell", componentId: "sc-18w13t3" }) `
|
|
14343
14533
|
width: 2rem;
|
|
14344
14534
|
text-align: right;
|
|
14345
14535
|
`;
|
|
14346
|
-
const CellText = styled.div.withConfig({ displayName: "CellText", componentId: "sc-
|
|
14536
|
+
const CellText = styled.div.withConfig({ displayName: "CellText", componentId: "sc-ok630s" }) `
|
|
14347
14537
|
padding: 0.375rem 0.25rem;
|
|
14348
14538
|
/* Та же высота строки, что у редактора — иначе строка подпрыгивала бы по вертикали. */
|
|
14349
14539
|
line-height: 1.25rem;
|
|
@@ -14353,9 +14543,12 @@ const CellText = styled.div.withConfig({ displayName: "CellText", componentId: "
|
|
|
14353
14543
|
`;
|
|
14354
14544
|
/**
|
|
14355
14545
|
* Редактируемая ячейка вне фокуса. Показывает значение по `stringFormat`, а редактор
|
|
14356
|
-
* подставляется
|
|
14546
|
+
* подставляется на фокус — иначе форматирование пришлось бы дублировать внутри инпута.
|
|
14547
|
+
*
|
|
14548
|
+
* Кнопка, а не просто текст, именно ради фокуса: она — таб-стоп ячейки, и Tab по таблице
|
|
14549
|
+
* открывает редактор с курсором внутри.
|
|
14357
14550
|
*/
|
|
14358
|
-
const CellButton = styled.button.withConfig({ displayName: "CellButton", componentId: "sc-
|
|
14551
|
+
const CellButton = styled.button.withConfig({ displayName: "CellButton", componentId: "sc-98k9cz" }) `
|
|
14359
14552
|
width: 100%;
|
|
14360
14553
|
padding: 0.375rem 0.25rem;
|
|
14361
14554
|
line-height: 1.25rem;
|
|
@@ -14374,7 +14567,7 @@ const CellButton = styled.button.withConfig({ displayName: "CellButton", compone
|
|
|
14374
14567
|
border-color: ${({ theme }) => theme.palette.elementDeep};
|
|
14375
14568
|
}
|
|
14376
14569
|
`;
|
|
14377
|
-
const CellPlaceholder = styled.span.withConfig({ displayName: "CellPlaceholder", componentId: "sc-
|
|
14570
|
+
const CellPlaceholder = styled.span.withConfig({ displayName: "CellPlaceholder", componentId: "sc-7tff41" }) `
|
|
14378
14571
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
14379
14572
|
`;
|
|
14380
14573
|
/**
|
|
@@ -14383,11 +14576,11 @@ const CellPlaceholder = styled.span.withConfig({ displayName: "CellPlaceholder",
|
|
|
14383
14576
|
* Копия остаётся в потоке и держит ширину колонки ровно такой, какой она была до клика, —
|
|
14384
14577
|
* иначе таблица дёргалась бы на каждый вход в правку и выход из неё.
|
|
14385
14578
|
*/
|
|
14386
|
-
const CellEditor = styled.div.withConfig({ displayName: "CellEditor", componentId: "sc-
|
|
14579
|
+
const CellEditor = styled.div.withConfig({ displayName: "CellEditor", componentId: "sc-qa22du" }) `
|
|
14387
14580
|
position: relative;
|
|
14388
14581
|
min-height: 2rem;
|
|
14389
14582
|
`;
|
|
14390
|
-
const CellGhost = styled.span.withConfig({ displayName: "CellGhost", componentId: "sc-
|
|
14583
|
+
const CellGhost = styled.span.withConfig({ displayName: "CellGhost", componentId: "sc-1i1yvb2" }) `
|
|
14391
14584
|
display: block;
|
|
14392
14585
|
padding: 0.375rem 0.25rem;
|
|
14393
14586
|
/* Рамка повторяет CellButton — с ней высота ячейки в правке совпадает с высотой на чтении. */
|
|
@@ -14396,7 +14589,7 @@ const CellGhost = styled.span.withConfig({ displayName: "CellGhost", componentId
|
|
|
14396
14589
|
white-space: nowrap;
|
|
14397
14590
|
visibility: hidden;
|
|
14398
14591
|
`;
|
|
14399
|
-
const CellField = styled.div.withConfig({ displayName: "CellField", componentId: "sc-
|
|
14592
|
+
const CellField = styled.div.withConfig({ displayName: "CellField", componentId: "sc-1ww3875" }) `
|
|
14400
14593
|
position: absolute;
|
|
14401
14594
|
inset: 0;
|
|
14402
14595
|
display: flex;
|
|
@@ -14411,7 +14604,7 @@ const CellField = styled.div.withConfig({ displayName: "CellField", componentId:
|
|
|
14411
14604
|
min-width: 0;
|
|
14412
14605
|
}
|
|
14413
14606
|
`;
|
|
14414
|
-
const TableEmpty = styled.div.withConfig({ displayName: "TableEmpty", componentId: "sc-
|
|
14607
|
+
const TableEmpty = styled.div.withConfig({ displayName: "TableEmpty", componentId: "sc-1vamijg" }) `
|
|
14415
14608
|
padding: 0.75rem 0.25rem;
|
|
14416
14609
|
color: ${({ theme }) => theme.palette.textSecondary};
|
|
14417
14610
|
`;
|
|
@@ -14431,38 +14624,60 @@ const isSameCellValue = (next, current, type) => {
|
|
|
14431
14624
|
};
|
|
14432
14625
|
|
|
14433
14626
|
/**
|
|
14434
|
-
*
|
|
14627
|
+
* Правка одной ячейки.
|
|
14435
14628
|
*
|
|
14436
|
-
*
|
|
14437
|
-
*
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
*
|
|
14442
|
-
* в том числе календарь `DatePicker`. Клик по ним DOM-деревом лежит вне ячейки, поэтому
|
|
14443
|
-
* закрытие редактора по клику снаружи обязано этот контейнер пропускать.
|
|
14444
|
-
*/
|
|
14445
|
-
const PORTAL_ROOT_SELECTOR = "#portal-root";
|
|
14446
|
-
|
|
14447
|
-
/**
|
|
14448
|
-
* Режим правки одной ячейки: открывается кликом по значению, закрывается кликом снаружи.
|
|
14629
|
+
* Открывает её фокус, а не клик: по таблице ходят Tab-ом, и на каждой ячейке сразу нужно поле
|
|
14630
|
+
* с курсором — кнопка, требующая ещё и Enter, ломала бы весь проход.
|
|
14631
|
+
*
|
|
14632
|
+
* Поэтому состояний три. `focused` — ячейка под фокусом с закрытым редактором, состояние после
|
|
14633
|
+
* Enter/Escape: фокус возвращается на кнопку, но правку заново не открывает (иначе выйти из неё
|
|
14634
|
+
* было бы нечем), а Tab с неё идёт дальше по таблице.
|
|
14449
14635
|
*
|
|
14450
|
-
* Закрывать по
|
|
14451
|
-
* календаря — редактор исчезал бы раньше, чем календарь успевал открыться.
|
|
14452
|
-
* `
|
|
14453
|
-
*
|
|
14636
|
+
* Закрывать правку по любому уходу фокуса нельзя: DatePicker уводит его из поля уже на клике по
|
|
14637
|
+
* иконке календаря — редактор исчезал бы раньше, чем календарь успевал открыться. Клавиатурный
|
|
14638
|
+
* уход видно по `relatedTarget` (фокус ушёл на соседнюю ячейку), мышиный ловит `mousedown`
|
|
14639
|
+
* снаружи. Клики внутри портала (`#portal-root`) считаем «своими»: выпадающие слои контролов
|
|
14640
|
+
* uilib живут именно там, вне DOM-поддерева ячейки.
|
|
14454
14641
|
*/
|
|
14455
14642
|
const useCellEditing = () => {
|
|
14456
|
-
const [
|
|
14643
|
+
const [mode, setMode] = useState("idle");
|
|
14644
|
+
const buttonRef = useRef(null);
|
|
14457
14645
|
const editorRef = useRef(null);
|
|
14458
|
-
const
|
|
14459
|
-
//
|
|
14460
|
-
// из
|
|
14461
|
-
const
|
|
14462
|
-
|
|
14463
|
-
|
|
14646
|
+
const editing = mode === "editing";
|
|
14647
|
+
// Фокус на закрытой ячейке — это уже правка. Из `focused` не открываем: фокус туда только что
|
|
14648
|
+
// вернули из редактора, и Escape перестал бы работать.
|
|
14649
|
+
const onFocus = useCallback(() => setMode(current => (current === "idle" ? "editing" : current)), []);
|
|
14650
|
+
// Переход в правку убирает саму кнопку — её прощальный blur эту правку закрывать не должен.
|
|
14651
|
+
const onBlur = useCallback(() => setMode(current => (current === "editing" ? current : "idle")), []);
|
|
14652
|
+
// Клик открывает правку и тогда, когда фокус на ячейке уже стоит — то есть после Enter/Escape.
|
|
14653
|
+
const onClick = useCallback(() => setMode("editing"), []);
|
|
14654
|
+
// Enter и Escape закрывают редактор, оставляя фокус на ячейке: значение записано в черновик
|
|
14655
|
+
// на каждый ввод, отдельного «применить» нет.
|
|
14656
|
+
const onEditorKeyDown = useCallback((event) => {
|
|
14657
|
+
if (event.key !== "Enter" && event.key !== "Escape") {
|
|
14658
|
+
return;
|
|
14659
|
+
}
|
|
14660
|
+
// Гасим действие по умолчанию: у Enter это «нажать то, что в фокусе», а фокус браузер смотрит
|
|
14661
|
+
// уже после обработчиков — к тому моменту он вернулся на кнопку ячейки, и правка открылась бы
|
|
14662
|
+
// заново тем же нажатием.
|
|
14663
|
+
event.preventDefault();
|
|
14664
|
+
setMode("focused");
|
|
14665
|
+
}, []);
|
|
14666
|
+
const onEditorBlur = useCallback(({ relatedTarget }) => {
|
|
14667
|
+
const inside = editorRef.current?.contains(relatedTarget) || !!relatedTarget?.closest(PORTAL_ROOT_SELECTOR);
|
|
14668
|
+
// Фокус «в никуда» уходом не считаем: так ведут себя внутренности DatePicker.
|
|
14669
|
+
if (!relatedTarget || inside) {
|
|
14670
|
+
return;
|
|
14464
14671
|
}
|
|
14672
|
+
setMode("idle");
|
|
14465
14673
|
}, []);
|
|
14674
|
+
// Выход из редактора возвращает фокус ячейке: иначе он падал бы в body, и следующий Tab пошёл
|
|
14675
|
+
// бы с начала страницы.
|
|
14676
|
+
useEffect(() => {
|
|
14677
|
+
if (mode === "focused") {
|
|
14678
|
+
buttonRef.current?.focus();
|
|
14679
|
+
}
|
|
14680
|
+
}, [mode]);
|
|
14466
14681
|
useEffect(() => {
|
|
14467
14682
|
if (!editing) {
|
|
14468
14683
|
return undefined;
|
|
@@ -14472,24 +14687,26 @@ const useCellEditing = () => {
|
|
|
14472
14687
|
if (editorRef.current?.contains(node) || node?.closest?.(PORTAL_ROOT_SELECTOR)) {
|
|
14473
14688
|
return;
|
|
14474
14689
|
}
|
|
14475
|
-
|
|
14690
|
+
setMode("idle");
|
|
14476
14691
|
};
|
|
14477
14692
|
document.addEventListener("mousedown", onDocumentMouseDown);
|
|
14478
14693
|
return () => document.removeEventListener("mousedown", onDocumentMouseDown);
|
|
14479
14694
|
}, [editing]);
|
|
14480
|
-
|
|
14695
|
+
const buttonProps = useMemo(() => ({ ref: buttonRef, onFocus, onBlur, onClick }), [onBlur, onClick, onFocus]);
|
|
14696
|
+
const editorProps = useMemo(() => ({ ref: editorRef, onBlur: onEditorBlur, onKeyDown: onEditorKeyDown }), [onEditorBlur, onEditorKeyDown]);
|
|
14697
|
+
return { editing, buttonProps, editorProps };
|
|
14481
14698
|
};
|
|
14482
14699
|
|
|
14483
14700
|
/**
|
|
14484
14701
|
* Ячейка таблицы.
|
|
14485
14702
|
*
|
|
14486
|
-
* Вне фокуса значение всегда показано через `stringFormat
|
|
14703
|
+
* Вне фокуса значение всегда показано через `stringFormat`, редактор подставляется на фокус.
|
|
14487
14704
|
* Иначе форматирование (округление, разряды, единицы) пришлось бы дублировать внутри инпута,
|
|
14488
14705
|
* а вводить в отформатированное поле нельзя.
|
|
14489
14706
|
*/
|
|
14490
14707
|
const TableCell = memo(({ attribute, row, canEdit, onChange }) => {
|
|
14491
14708
|
const { t, language } = useGlobalContext();
|
|
14492
|
-
const { editing,
|
|
14709
|
+
const { editing, buttonProps, editorProps } = useCellEditing();
|
|
14493
14710
|
const { attributeName, type, isEditable, stringFormat } = attribute;
|
|
14494
14711
|
const value = row.properties[attributeName];
|
|
14495
14712
|
const handleChange = useCallback((next) => {
|
|
@@ -14518,22 +14735,53 @@ const TableCell = memo(({ attribute, row, canEdit, onChange }) => {
|
|
|
14518
14735
|
return jsx(CellText, { title: formatted, children: formatted || jsx(CellPlaceholder, { children: "\u2014" }) });
|
|
14519
14736
|
}
|
|
14520
14737
|
if (!editing) {
|
|
14521
|
-
return (jsx(CellButton, { type: "button",
|
|
14738
|
+
return (jsx(CellButton, { type: "button", ...buttonProps, children: formatted || jsx(CellPlaceholder, { children: "\u2014" }) }));
|
|
14522
14739
|
}
|
|
14523
14740
|
const renderEditor = () => {
|
|
14524
14741
|
if (type === AttributeType.DateTime) {
|
|
14525
|
-
return (jsx(DatePicker, { value: dateValue, locale: getLocale(language), withTime: withTime, withHeader: true, width: "100%", onChange: date => handleChange(date.toISOString()) }));
|
|
14742
|
+
return (jsx(DatePicker, { focus: true, value: dateValue, locale: getLocale(language), withTime: withTime, withHeader: true, width: "100%", onChange: date => handleChange(date.toISOString()) }));
|
|
14526
14743
|
}
|
|
14527
14744
|
if (NUMBER_EDITOR_TYPES.includes(type)) {
|
|
14528
14745
|
return (jsx(NumberInput, { autoFocus: true, value: value === null || value === undefined ? null : Number(value), width: "100%", numeralDecimalScale: INTEGER_ATTRIBUTE_TYPES.includes(type) ? 0 : undefined, onChange: next => handleChange(next) }));
|
|
14529
14746
|
}
|
|
14530
14747
|
return (jsx(Input, { autoFocus: true, value: value === null || value === undefined ? "" : String(value), width: "100%", onChange: ({ target }) => handleChange(target.value) }));
|
|
14531
14748
|
};
|
|
14532
|
-
return (jsxs(CellEditor, {
|
|
14749
|
+
return (jsxs(CellEditor, { ...editorProps, children: [jsx(CellGhost, { children: formatted || "—" }), jsx(CellField, { children: renderEditor() })] }));
|
|
14533
14750
|
});
|
|
14534
14751
|
|
|
14535
14752
|
const ContainerLoading = () => (jsx(Flex, { alignContent: "center", justifyContent: "center", width: "100%", children: jsx(CircularProgress, { diameter: 1.5, mono: true }) }));
|
|
14536
14753
|
|
|
14754
|
+
/**
|
|
14755
|
+
* Отсечка тела таблицы по нижней кромке липкой шапки.
|
|
14756
|
+
*
|
|
14757
|
+
* Шапка прозрачная — фон контейнера виден сквозь неё, и красить её нечем: цвет контейнера задаётся
|
|
14758
|
+
* конфигом и меняется. Значит, строки не должны под неё заезжать в принципе. Тело для этого
|
|
14759
|
+
* отсекается (`clip-path`) ровно на то, на сколько шапка его накрыла: низ шапки минус верх тела.
|
|
14760
|
+
*
|
|
14761
|
+
* Разница считается по факту, а не по величине прокрутки: она одинаково верна и когда прокручивает
|
|
14762
|
+
* собственный бокс таблицы, и когда её прокручивает область представления контейнера. Пока
|
|
14763
|
+
* не прокручено, низ шапки совпадает с верхом тела — отсекать нечего.
|
|
14764
|
+
*
|
|
14765
|
+
* Прокрутка не всплывает, но проходит фазу перехвата, поэтому слушаем документ: какой именно
|
|
14766
|
+
* предок прокручивается, знать не нужно.
|
|
14767
|
+
*/
|
|
14768
|
+
const useHeadOverlap = (table) => {
|
|
14769
|
+
useLayoutEffect(() => {
|
|
14770
|
+
if (!table) {
|
|
14771
|
+
return undefined;
|
|
14772
|
+
}
|
|
14773
|
+
const update = () => {
|
|
14774
|
+
const head = table.tHead?.getBoundingClientRect();
|
|
14775
|
+
const body = table.tBodies[0]?.getBoundingClientRect();
|
|
14776
|
+
const overlap = head && body ? Math.max(0, head.bottom - body.top) : 0;
|
|
14777
|
+
table.style.setProperty(HEAD_OVERLAP_VARIABLE, `${overlap}px`);
|
|
14778
|
+
};
|
|
14779
|
+
update();
|
|
14780
|
+
document.addEventListener("scroll", update, { capture: true, passive: true });
|
|
14781
|
+
return () => document.removeEventListener("scroll", update, { capture: true });
|
|
14782
|
+
}, [table]);
|
|
14783
|
+
};
|
|
14784
|
+
|
|
14537
14785
|
const compareValues = (left, right, type) => {
|
|
14538
14786
|
if (NUMERIC_ATTRIBUTE_TYPES.includes(type)) {
|
|
14539
14787
|
return Number(left) - Number(right);
|
|
@@ -14578,28 +14826,66 @@ const getNextSort = (current, attributeName) => {
|
|
|
14578
14826
|
};
|
|
14579
14827
|
|
|
14580
14828
|
/**
|
|
14581
|
-
*
|
|
14829
|
+
* Css собственного бокса таблицы: размер из `options` представления плюс прокрутка того,
|
|
14830
|
+
* что в этот размер не влез.
|
|
14831
|
+
*
|
|
14832
|
+
* Размеров нет — нет и бокса: таблица занимает столько, сколько просит содержимое, а лишнее,
|
|
14833
|
+
* как и раньше, уходит в прокрутку области представления контейнера.
|
|
14834
|
+
*
|
|
14835
|
+
* Проценты работают только по ширине. Между областью представления и таблицей стоит блочная
|
|
14836
|
+
* обёртка элемента (`ElementValueWrapper`) с высотой `auto`, и `height: "100%"` в ней не
|
|
14837
|
+
* разрешается — вертикальный предел задают конкретные единицы (`240`, `"20rem"`, `"50vh"`),
|
|
14838
|
+
* а «занять всю выданную высоту» остаётся за `options.height` контейнера.
|
|
14839
|
+
*
|
|
14840
|
+
* `contain: inline-size` идёт в пару к fill-ширине: сама по себе она предком не ограничена
|
|
14841
|
+
* (процент от раскладки, которая меряет себя содержимым, вырождается в `auto`), и таблица
|
|
14842
|
+
* распирала бы ряд плиток или трек `auto` изнутри. С containment вклад бокса в ширину предка
|
|
14843
|
+
* обнуляется: ширину он берёт снаружи, а внутрь по ней не смотрят.
|
|
14844
|
+
*/
|
|
14845
|
+
const getTableBoxStyle = (width, height) => {
|
|
14846
|
+
if (width == null && height == null) {
|
|
14847
|
+
return undefined;
|
|
14848
|
+
}
|
|
14849
|
+
return {
|
|
14850
|
+
...getWrapperSizeStyle({ width, height, overflow: "auto" }),
|
|
14851
|
+
...(isFillSize(width) && { contain: "inline-size" }),
|
|
14852
|
+
};
|
|
14853
|
+
};
|
|
14854
|
+
|
|
14855
|
+
/**
|
|
14856
|
+
* Вид таблицы: колонки плюс локальная сортировка.
|
|
14857
|
+
*
|
|
14858
|
+
* Набор и порядок колонок — это схема контейнера (`attributesDescription`) как есть: показываем
|
|
14859
|
+
* ровно то, что описано, и в том же порядке. Своего отбора у представления нет — иначе описанный
|
|
14860
|
+
* атрибут и видимая колонка расходились бы, а в фильтр всё равно уходят все атрибуты схемы.
|
|
14582
14861
|
*
|
|
14583
14862
|
* Сортировка живёт здесь, а не в контейнере: она ничего не меняет в данных и не должна
|
|
14584
14863
|
* влиять на порядок строк, уходящих в фильтр.
|
|
14864
|
+
*
|
|
14865
|
+
* `width`/`height` — размер собственного бокса таблицы: он ограничивает её саму и прокручивает
|
|
14866
|
+
* то, что не влезло. Место, отведённое контейнеру, задаётся его же опциями и живёт отдельно.
|
|
14585
14867
|
*/
|
|
14586
14868
|
const useTableView = (elementConfig) => {
|
|
14587
14869
|
const context = useContext(StructuredDataContext);
|
|
14588
|
-
const {
|
|
14870
|
+
const { sort: sortEnabled, width, height } = elementConfig?.options || {};
|
|
14589
14871
|
const [sort, setSort] = useState(null);
|
|
14590
14872
|
const schema = context?.schema;
|
|
14591
14873
|
const rows = context?.rows;
|
|
14592
|
-
const columns = useMemo(() =>
|
|
14593
|
-
if (!columnNames?.length) {
|
|
14594
|
-
return schema ?? [];
|
|
14595
|
-
}
|
|
14596
|
-
return columnNames
|
|
14597
|
-
.map(columnName => schema?.find(({ attributeName }) => attributeName === columnName))
|
|
14598
|
-
.filter(Boolean);
|
|
14599
|
-
}, [columnNames, schema]);
|
|
14874
|
+
const columns = useMemo(() => schema ?? [], [schema]);
|
|
14600
14875
|
const sortedRows = useMemo(() => sortRows(rows ?? [], sort, schema ?? []), [rows, schema, sort]);
|
|
14876
|
+
const sizeCss = useMemo(() => getTableBoxStyle(width, height), [height, width]);
|
|
14601
14877
|
const onSortToggle = useCallback((attributeName) => setSort(current => getNextSort(current, attributeName)), []);
|
|
14602
|
-
return {
|
|
14878
|
+
return {
|
|
14879
|
+
context,
|
|
14880
|
+
columns,
|
|
14881
|
+
rows: sortedRows,
|
|
14882
|
+
sort,
|
|
14883
|
+
sortEnabled: !!sortEnabled,
|
|
14884
|
+
sizeCss,
|
|
14885
|
+
// Ширина задана — колонки по содержимому: лишнее уходит в прокрутку бокса, а не в многоточие.
|
|
14886
|
+
contentWidth: width != null,
|
|
14887
|
+
onSortToggle,
|
|
14888
|
+
};
|
|
14603
14889
|
};
|
|
14604
14890
|
|
|
14605
14891
|
/**
|
|
@@ -14610,7 +14896,10 @@ const useTableView = (elementConfig) => {
|
|
|
14610
14896
|
*/
|
|
14611
14897
|
const ElementTable = memo(({ elementConfig }) => {
|
|
14612
14898
|
const { t } = useGlobalContext();
|
|
14613
|
-
const { context, columns, rows, sort, sortEnabled, onSortToggle } = useTableView(elementConfig);
|
|
14899
|
+
const { context, columns, rows, sort, sortEnabled, sizeCss, contentWidth, onSortToggle } = useTableView(elementConfig);
|
|
14900
|
+
// Узел таблицы держим состоянием, а не ref: отсечка должна встать сразу, как он появится.
|
|
14901
|
+
const [table, setTable] = useState(null);
|
|
14902
|
+
useHeadOverlap(table);
|
|
14614
14903
|
if (!context) {
|
|
14615
14904
|
return null;
|
|
14616
14905
|
}
|
|
@@ -14623,7 +14912,10 @@ const ElementTable = memo(({ elementConfig }) => {
|
|
|
14623
14912
|
defaultValue: "Схема данных не задана",
|
|
14624
14913
|
}) }));
|
|
14625
14914
|
}
|
|
14626
|
-
return (
|
|
14915
|
+
return (jsx(TableBox, { "$sizeCss": sizeCss, children: jsxs(TableWrapper, { ref: setTable, "$contentWidth": contentWidth, children: [jsx(TableHead, { children: jsxs("tr", { children: [columns.map(({ attributeName, alias, description }) => {
|
|
14916
|
+
const sorted = sort?.attributeName === attributeName;
|
|
14917
|
+
return (jsx(TableHeadCell, { title: description || alias, "$sortable": sortEnabled, onClick: sortEnabled ? () => onSortToggle(attributeName) : undefined, children: jsxs(TableHeadContent, { children: [alias, sortEnabled && (jsx(TableSortSlot, { "$active": sorted, children: jsx(Icon, { kind: sorted && sort?.direction === "desc" ? "sorting_des" : "sorting_asc" }) }))] }) }, attributeName));
|
|
14918
|
+
}), context.canEdit && jsx(TableHeadCell, {})] }) }), jsx(TableBody, { children: rows.map(row => (jsxs(TableRow, { children: [columns.map(attribute => (jsx(TableCellWrapper, { children: jsx(TableCell, { attribute: attribute, row: row, canEdit: context.canEdit, onChange: context.onCellChange }) }, attribute.attributeName))), context.canEdit && (jsx(TableActionsCell, { children: jsx(IconButton, { kind: "delete", title: t("actions.delete", { ns: "common", defaultValue: "Удалить" }), onClick: () => context.onRowDelete(row.key) }) }))] }, row.key))) })] }) }));
|
|
14627
14919
|
});
|
|
14628
14920
|
|
|
14629
14921
|
const TooltipIcon = styled(Icon).withConfig({ displayName: "TooltipIcon", componentId: "sc-1lkxudm" }) `
|
|
@@ -15235,7 +15527,8 @@ const getRenderElement = ({ t, config, elementConfig, attributes = [], layerInfo
|
|
|
15235
15527
|
|
|
15236
15528
|
const ElementModal = memo(({ type = WidgetType.Dashboard, elementConfig }) => {
|
|
15237
15529
|
const { config } = useWidgetConfig(type);
|
|
15238
|
-
const { expandedContainers, attributes
|
|
15530
|
+
const { expandedContainers, attributes } = useWidgetContext(type);
|
|
15531
|
+
const isDataSourceLoading = useDataSourceLoading(type);
|
|
15239
15532
|
const [isOpen, setIsOpen] = useState(false);
|
|
15240
15533
|
const { options } = elementConfig || {};
|
|
15241
15534
|
const { modalId, icon } = options || {};
|
|
@@ -15255,7 +15548,7 @@ const ElementModal = memo(({ type = WidgetType.Dashboard, elementConfig }) => {
|
|
|
15255
15548
|
return null;
|
|
15256
15549
|
const { options: modalOptions } = modalConfig;
|
|
15257
15550
|
const { title, maxWidth, minWidth, minHeight } = modalOptions || {};
|
|
15258
|
-
return (jsxs(Fragment$1, { children: [jsx(ModalIcon, { kind: icon || "new_window", onClick: handleOpen, children: title }), jsxs(Dialog, { maxWidth: maxWidth, minWidth: minWidth, minHeight: minHeight, isOpen: isOpen, modal: true, onCloseRequest: handleClose, style: { paddingBottom: "2rem" }, children: [jsx(DialogTitle, { children: jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [!!title && jsx("span", { children: title }), jsx(IconButton, { kind: "close", onClick: handleClose })] }) }), jsx(DialogContent, { children:
|
|
15551
|
+
return (jsxs(Fragment$1, { children: [jsx(ModalIcon, { kind: icon || "new_window", onClick: handleOpen, children: title }), jsxs(Dialog, { maxWidth: maxWidth, minWidth: minWidth, minHeight: minHeight, isOpen: isOpen, modal: true, onCloseRequest: handleClose, style: { paddingBottom: "2rem" }, children: [jsx(DialogTitle, { children: jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [!!title && jsx("span", { children: title }), jsx(IconButton, { kind: "close", onClick: handleClose })] }) }), jsx(DialogContent, { children: isDataSourceLoading ? (jsx(DashboardLoading, {})) : (jsx(Container, { isColumn: true, noBorders: true, children: jsx(ContainerChildren, { type: type, items: modalContent, isMain: true, renderElement: renderElement }) })) })] })] }));
|
|
15259
15552
|
});
|
|
15260
15553
|
|
|
15261
15554
|
const elementComponents = {
|
|
@@ -16607,6 +16900,25 @@ const getFilterValue = ({ selectedFilters, configFilters, filterName, newValue,
|
|
|
16607
16900
|
return valueType === "single" ? newValue : valueType === "range" ? [newValue, newValue] : [newValue];
|
|
16608
16901
|
};
|
|
16609
16902
|
|
|
16903
|
+
/** Условие источника задаётся строкой или массивом строк — приводим к массиву для единообразного обхода. */
|
|
16904
|
+
const toConditionsArray = (value) => Array.isArray(value) ? value : value ? [value] : [];
|
|
16905
|
+
|
|
16906
|
+
const MAP_VIEW_PLACEHOLDERS = MAP_VIEW_FILTER_NAMES.map(name => `${FILTER_PREFIX}${name}`);
|
|
16907
|
+
// Та же граница, что и при подстановке в `formatDataSourceCondition`: составные формы
|
|
16908
|
+
// (`%zoomLevel`, `%extent_id`, `%zoom.min`) принадлежат пользовательским фильтрам, не карте.
|
|
16909
|
+
const hasMapViewPlaceholder = (value) => MAP_VIEW_PLACEHOLDERS.some(placeholder => new RegExp(`${placeholder}(?![\\w.])`).test(value));
|
|
16910
|
+
/**
|
|
16911
|
+
* Источники, чей запрос зависит от текущего вида карты — в `parameters` или `condition` у них
|
|
16912
|
+
* есть `%extent` / `%zoom`. Перезапрашивают при движении карты только их: иначе каждый пан
|
|
16913
|
+
* дёргал бы все запросы страницы.
|
|
16914
|
+
*/
|
|
16915
|
+
const getMapViewDataSources = (dataSources) => dataSources?.filter(({ parameters, condition }) => {
|
|
16916
|
+
const hasInParameters = Object.values(parameters ?? {}).some(value => typeof value === "string" && MAP_VIEW_PLACEHOLDERS.includes(value));
|
|
16917
|
+
if (hasInParameters)
|
|
16918
|
+
return true;
|
|
16919
|
+
return toConditionsArray(condition).some(hasMapViewPlaceholder);
|
|
16920
|
+
}) ?? [];
|
|
16921
|
+
|
|
16610
16922
|
const getFormattedAttributes = (t, data, attributes, config) => {
|
|
16611
16923
|
const showOtherItems = config?.options?.otherItems < data?.length;
|
|
16612
16924
|
const otherIndex = config?.options?.otherItems + 1;
|
|
@@ -17183,11 +17495,9 @@ const DashboardLoading = memo(() => {
|
|
|
17183
17495
|
});
|
|
17184
17496
|
|
|
17185
17497
|
const Dashboard = memo(({ type = WidgetType.Dashboard, noBorders }) => {
|
|
17186
|
-
const
|
|
17187
|
-
const { currentPage } = useWidgetPage(type);
|
|
17498
|
+
const isDataSourceLoading = useDataSourceLoading(type);
|
|
17188
17499
|
const isDiffPage = useDiffPage(type);
|
|
17189
|
-
|
|
17190
|
-
if (dataSourceLoading || isDiffPage) {
|
|
17500
|
+
if (isDataSourceLoading || isDiffPage) {
|
|
17191
17501
|
return (jsx(DashboardLoading, {}));
|
|
17192
17502
|
}
|
|
17193
17503
|
return (jsx(PagesContainer, { type: type, noBorders: noBorders }));
|
|
@@ -17814,5 +18124,5 @@ const DEFAULT_HEATMAP_STYLE = {
|
|
|
17814
18124
|
],
|
|
17815
18125
|
};
|
|
17816
18126
|
|
|
17817
|
-
export { ALIGNMENTS, ALIGN_ITEMS, ATTRIBUTE_ICON_ELEMENT_TYPES, AddFeatureButton, AddFeatureContainer, AlertIconContainer, AttachmentContainer, AttributeGalleryContainer, AttributeLabel, BASE_CONTAINER_STYLE, BaseMapTheme, CHART_TYPES, COMPACT_FRACTION_DIGITS, CONFIG_PAGES_ID, CONFIG_PAGE_ID, CONTAINERS_GROUP_DEFAULTS, CONTAINER_BODY_ATTRIBUTE, CONTAINER_BODY_FILL_STYLE, CameraContainer, Chart, ChartContainer, ChartLegend, ChartLoading, Container, ContainerChildren, ContainerLoading, ContainerRoot, ContainerTemplate, ContainerWrapper, ContainersGroupContainer, DEFAULT_ATTRIBUTE_NAME, DEFAULT_BARCHART_RADIUS, DEFAULT_BASE_MAP, DEFAULT_BLUR, DEFAULT_CHART_ANGLE, DEFAULT_CHART_HEIGHT, DEFAULT_CHART_WIDTH, DEFAULT_CIRCLE_RADIUS, DEFAULT_CIRCLE_STROKE_WIDTH, DEFAULT_CIRCLE_STYLE, DEFAULT_COLOR, DEFAULT_DASHBOARD_CONFIG, DEFAULT_DATA_SOURCE_LIMIT, DEFAULT_DROPDOWN_WIDTH, DEFAULT_FILL_EXTRUSION_BASE, DEFAULT_FILL_EXTRUSION_HEIGHT, DEFAULT_FILL_EXTRUSION_STYLE, DEFAULT_FILL_EXTRUSION_VERTICAL_GRADIENT, DEFAULT_FILL_STYLE, DEFAULT_FILTER_PADDING, DEFAULT_GRID_GAP, DEFAULT_HEATMAP_COLOR, DEFAULT_HEATMAP_INTENSITY, DEFAULT_HEATMAP_RADIUS, DEFAULT_HEATMAP_STYLE, DEFAULT_HEATMAP_WEIGHT, DEFAULT_ICON_ANCHOR, DEFAULT_ICON_OVERLAP, DEFAULT_ICON_PADDING, DEFAULT_ICON_ROTATE, DEFAULT_ICON_SIZE, DEFAULT_ID_ATTRIBUTE_NAME, DEFAULT_LAT, DEFAULT_LINE_CAP, DEFAULT_LINE_JOIN, DEFAULT_LINE_STYLE, DEFAULT_LINE_WIDTH, DEFAULT_LNG, DEFAULT_OPACITY, DEFAULT_PAGES_CONFIG, DEFAULT_PIECHART_RADIUS, DEFAULT_SYMBOL_COLOR, DEFAULT_SYMBOL_HALO_COLOR, DEFAULT_SYMBOL_PLACEMENT, DEFAULT_SYMBOL_SPACING, DEFAULT_SYMBOL_STYLE, DEFAULT_TEXT_ANCHOR, DEFAULT_TEXT_JUSTIFY, DEFAULT_TEXT_SIZE, DEFAULT_TEXT_TRANSFORM, DEFAULT_TRACK_FR, DEFAULT_TRANSLATE, DEFAULT_ZOOM, DRAG_THRESHOLD_PX, Dashboard, DashboardCheckbox, DashboardChip, DashboardContent, DashboardContext, DashboardDefaultHeader, DashboardHeader, DashboardLoading, DashboardPlaceholder, DashboardPlaceholderWrap, DashboardProvider, DashboardWrapper, DataSourceContainer, DataSourceError, DataSourceErrorContainer, DataSourceInnerContainer, DataSourceProgressContainer, DateFormat, DefaultAttributesContainer, DefaultHeaderContainer, DefaultHeaderWrapper, DividerContainer, EMPTY_DATA_SOURCE_LAYER_INFO, EditGeometryType, ElementButton, ElementCamera, ElementChart, ElementChips, ElementControl, ElementIcon, ElementImage, ElementLegend, ElementLink, ElementMarkdown, ElementSlideshow, ElementSvg, ElementTable, ElementTooltip, ElementValueWrapper, ExpandableTitle, FEATURE_CARD_DEFAULT_COLORS, FEATURE_CARD_OTHER_COLOR, FILL_SIZE, FILTERED_VALUE_OPACITY, FILTER_PREFIX, FR_PRECISION, FeatureCardBackgroundHeader, FeatureCardButtons, FeatureCardContext, FeatureCardDefaultHeader, FeatureCardHeader, FeatureCardProvider, FeatureCardSlideshowHeader, FeatureCardTitle, FeatureControls, FeatureTitleContainer, FiltersContainer, GEOMETRY_ATTRIBUTE, GRID_AUTO_FILL_DEFAULTS, GRID_CELL_ATTR, GRID_CELL_ID_PREFIX, GRID_DRAGGING_ATTR, GRID_DRAG_SOURCE_ATTR, GRID_DROP_TARGET_ATTR, GRID_FILL_DEFAULTS, GRID_HANDLE_ATTR, GRID_HANDLE_PROPS, GRID_ROW_ID_PREFIX, GlobalContext, GlobalProvider, GridRowContainer, HANDLE_BLEED_PX, Header, HeaderContainer, HeaderFontColorMixin, HeaderFrontView, HeaderTemplate, HeaderTitleContainer, HiddenTitleItems, IconContainer, ImageContainer, LEFT_PANEL_HEADER_HEIGHT, Layer, LayerDescription, LayerGroupList, LayerIcon, LayerIconContainer, LayerListContainer, LayerTree, LayersContainer, LayersListWrapper, LinearProgressContainer, LogTerminal, LogoContainer, MAX_CHART_WIDTH, MAX_TRACKS, MIN_TRACK_PX, MIN_TRACK_RATIO, Map$1 as Map, MapContext, MapProvider, NO_CELL_DRAG_SELECTOR, NO_CONTENT_VALUE, NUMERIC_ATTRIBUTE_TYPES, NoLiveSnapshotContainer, OBJECT_FITS, OVERFLOWS, OneColumnContainer, POLL_SUBTASK_INTERVAL_MS, POLL_SUBTASK_TIMEOUT_MS, PROVIDER_PREFIX, PageNavigator, PageTitle, PageTitleContainer, PagesContainer, Pagination, PresentationHeader, PresentationHeaderButtons, PresentationHeaderTools, PresentationPanelContainer, PresentationPanelWrapper, PresentationWrapper, ProgressContainer, ProviderPrefix, QUERY_DESCRIPTION_CACHE_TTL, RoundedBackgroundContainer, SAVE_HOOK_RESULT_DURATION, SERVER_NOTIFICATION_EVENT, STACK_BAR_TOTAL_HEIGHT, ScalingFactor, ServerNotificationsContext, ServerNotificationsProvider, SlideshowContainer, SmallPreviewContainer$1 as SmallPreviewContainer, SmallPreviewControl, SmallPreviewCounter, SmallPreviewImages, SmallPreviewLeft, SmallPreviewRight, StackBar, StructuredDataContainer, SvgImage, TILE_ALIGNMENTS, TIME_ZONE_FORMAT, TITLE_SLOT_IDS, TabsContainer, TextTrim, ThemeName, TitleContainer, TopContainer, TopContainerButtons, TwoColumnContainer, UploadContainer, VIEW_MODES, WidgetType, addDataSource, addDataSources, adjustColor, applyFiltersToCondition, applyQueryFilters, applyTreeFilterToCondition, applyVarsToCondition, asAttributeName, asChartId, asContainerId, asDataSourceName, asFilterName, asLayerName, asModalId, asResourceId, asTabId, buildGridTemplate, buildTrackTemplate, checkEqualOrIncludes, checkIsLoading, collectConfigIds, containsNodeId, createConfigLayer, createConfigPage, createGridCell, createGridIdFactory, createGridRow, createNewPageId, createSaveNotificationId, dateOptions, debounce, decimalOpacityToHex, enrichStyleItemsWithIds, enrichStyleModelsWithIds, eqlParametersToPayload, fetchQueryDescription, findAttributeInExpression, findCellContext, formatArea, formatAttributeValue, formatChartRelatedValue, formatConditionValue, formatDataSourceCondition, formatDate$1 as formatDate, formatElementValue, formatLength, formatNumber, formatPolygonMeasure, geometryToEwkt, getActualExtrusionHeight, getAttributeByName, getAttributeConfigurationByName, getAttributeIconElement, getAttributeIconUrl, getAttributeValue, getAttributesConfiguration, getAverageTrackSize, getChartAxes, getChartFilterName, getChartMarkers, getConfigFilter, getContainerComponent, getDashboardHeader, getDataFromAttributes, getDataFromRelatedFeatures, getDataSource, getDataSourceFilterValue, getDataSourceLayerInfo, getDate, getDefaultConfig, getDisplayTemplateNameFromAttribute, getElementValue, getFeatureAttributes, getFeatureCardHeader, getFilterComponent, getFilterSelectedItems, getFilterValue, getFormattedAttributes, getGradientColors, getImageUrl, getLayerClientStyle, getLayerInfo, getLayerInfoAttribute, getLayerInfoFromDataSources, getLayoutChildren, getPagesFromConfig, getPagesFromProjectInfo, getProxyService, getRelatedAttribute, getRenderElement, getResourceUrl, getRootElementId, getSelectedFilterValue, getSlideshowImages, getStyleAttributes, getSvgUrl, getTemplateNameFromAttribute, getThemeByName, getTotalFromAttributes, getTotalFromRelatedFeatures, getTrackSize, getTrackSizeKey, getTrackSizes, getWrapperSizeStyle, hexToRgba, isEmptyElementValue, isEmptyValue, isFeaturesFilterValue, isFillSize, isFrSize, isGridNode, isHiddenEmptyValue, isHookActive, isLayerService, isNotValidSelectedTab, isNumeric, isObject, isProxyService, isRootOwningContainer, isTreeFilterValue, isVisibleContainer, mapNodeById, mergeAttributeConfigurations, metersPerPixel, noMarginMixin, numberOptions, parseFrValue, parseIconNames, parseIconNamesFromClientStyle, pieChartTooltipFromAttributes, pieChartTooltipFromRelatedFeatures, pointOptions, removeDataSource, removeTracks, replaceNodesByIds, rgbToHex, roundFr, roundTotalSum, setLayoutChildren, sizeCssMixin, sliceShownOtherItems, stretchPalette, timeOptions, toCssSize, toFrSize, toPxNumber, toRenderableValue, tooltipNameFromAttributes, tooltipValueFromAttributes, tooltipValueFromRelatedFeatures, transparentizeColor, updateDataSource, useAfterSave, useAppHeight, useAttachmentItems, useAttachmentPreviewImages, useAutoCompleteControl, useBeforeSave, useChartChange, useChartData, useContainerAttributes, useContainerRoot, useCurrentPageLayers, useCustomFeatureSelect, useDashboardHeader, useDataSources, useDebouncedCallback, useDiffPage, useEditGroupAttributes, useEqualTileWidth, useExpandableContainers, useExportPdf, useFeatureSaveHooks, useFetchImageWithAuth, useFetchWithAuth, useGetConfigLayer, useGlobalContext, useHeaderRender, useHideIfEmptyDataSource, useIconsFromLayers, useLayerHiddenAttributes, useLayerParams, useMapContext, useMapDraw, useMapImages, useMaxZoomTo, useProjectDashboardInit, usePythonSandbox, usePythonTask, useRedrawLayer, useRelatedDataSourceAttributes, useRemoteTask, useRenderElement, useResizeBox, useSavePrototypeBuilder, useServerNotificationsContext, useShownOtherItems, useToggle, useUpdateDataSource, useVisibleProjectItems, useWidgetConfig, useWidgetContext, useWidgetFilters, useWidgetPage, useWindowResize, useWrapperSize, useZoomToFeatures, useZoomToPoint, withTrackSize };
|
|
18127
|
+
export { ALIGNMENTS, ALIGN_ITEMS, ATTRIBUTE_ICON_ELEMENT_TYPES, AddButtonRow, AddFeatureButton, AddFeatureContainer, AlertIconContainer, AttachmentContainer, AttributeGalleryContainer, AttributeLabel, BASE_CONTAINER_STYLE, BaseMapTheme, CHART_TYPES, COMPACT_FRACTION_DIGITS, CONFIG_PAGES_ID, CONFIG_PAGE_ID, CONTAINERS_GROUP_DEFAULTS, CONTAINER_BODY_ATTRIBUTE, CONTAINER_BODY_FILL_STYLE, CameraContainer, Chart, ChartContainer, ChartLegend, ChartLoading, Container, ContainerChildren, ContainerLoading, ContainerRoot, ContainerTemplate, ContainerWrapper, ContainersGroupContainer, DEFAULT_ATTRIBUTE_NAME, DEFAULT_BARCHART_RADIUS, DEFAULT_BASE_MAP, DEFAULT_BLUR, DEFAULT_CHART_ANGLE, DEFAULT_CHART_HEIGHT, DEFAULT_CHART_WIDTH, DEFAULT_CIRCLE_RADIUS, DEFAULT_CIRCLE_STROKE_WIDTH, DEFAULT_CIRCLE_STYLE, DEFAULT_COLOR, DEFAULT_DASHBOARD_CONFIG, DEFAULT_DATA_SOURCE_LIMIT, DEFAULT_DROPDOWN_WIDTH, DEFAULT_FILL_EXTRUSION_BASE, DEFAULT_FILL_EXTRUSION_HEIGHT, DEFAULT_FILL_EXTRUSION_STYLE, DEFAULT_FILL_EXTRUSION_VERTICAL_GRADIENT, DEFAULT_FILL_STYLE, DEFAULT_FILTER_PADDING, DEFAULT_GRID_GAP, DEFAULT_HEATMAP_COLOR, DEFAULT_HEATMAP_INTENSITY, DEFAULT_HEATMAP_RADIUS, DEFAULT_HEATMAP_STYLE, DEFAULT_HEATMAP_WEIGHT, DEFAULT_ICON_ANCHOR, DEFAULT_ICON_OVERLAP, DEFAULT_ICON_PADDING, DEFAULT_ICON_ROTATE, DEFAULT_ICON_SIZE, DEFAULT_ID_ATTRIBUTE_NAME, DEFAULT_LAT, DEFAULT_LINE_CAP, DEFAULT_LINE_JOIN, DEFAULT_LINE_STYLE, DEFAULT_LINE_WIDTH, DEFAULT_LNG, DEFAULT_OPACITY, DEFAULT_PAGES_CONFIG, DEFAULT_PIECHART_RADIUS, DEFAULT_SYMBOL_COLOR, DEFAULT_SYMBOL_HALO_COLOR, DEFAULT_SYMBOL_PLACEMENT, DEFAULT_SYMBOL_SPACING, DEFAULT_SYMBOL_STYLE, DEFAULT_TEXT_ANCHOR, DEFAULT_TEXT_JUSTIFY, DEFAULT_TEXT_SIZE, DEFAULT_TEXT_TRANSFORM, DEFAULT_TRACK_FR, DEFAULT_TRANSLATE, DEFAULT_ZOOM, DRAG_THRESHOLD_PX, Dashboard, DashboardCheckbox, DashboardChip, DashboardContent, DashboardContext, DashboardDefaultHeader, DashboardHeader, DashboardLoading, DashboardPlaceholder, DashboardPlaceholderWrap, DashboardProvider, DashboardWrapper, DataSourceContainer, DataSourceError, DataSourceErrorContainer, DataSourceInnerContainer, DataSourceProgressContainer, DateFormat, DefaultAttributesContainer, DefaultHeaderContainer, DefaultHeaderWrapper, DividerContainer, EMPTY_DATA_SOURCE_LAYER_INFO, EXTENT_FILTER_NAME, EditGeometryType, ElementButton, ElementCamera, ElementChart, ElementChips, ElementControl, ElementIcon, ElementImage, ElementLegend, ElementLink, ElementMarkdown, ElementSlideshow, ElementSvg, ElementTable, ElementTooltip, ElementValueWrapper, ExpandableTitle, FEATURE_CARD_DEFAULT_COLORS, FEATURE_CARD_OTHER_COLOR, FILL_SIZE, FILTERED_VALUE_OPACITY, FILTER_PREFIX, FR_PRECISION, FeatureCardBackgroundHeader, FeatureCardButtons, FeatureCardContext, FeatureCardDefaultHeader, FeatureCardHeader, FeatureCardProvider, FeatureCardSlideshowHeader, FeatureCardTitle, FeatureControls, FeatureTitleContainer, FiltersContainer, GEOMETRY_ATTRIBUTE, GEOMETRY_FILTER_NAME, GRID_AUTO_FILL_DEFAULTS, GRID_CELL_ATTR, GRID_CELL_ID_PREFIX, GRID_DRAGGING_ATTR, GRID_DRAG_SOURCE_ATTR, GRID_DROP_TARGET_ATTR, GRID_FILL_DEFAULTS, GRID_HANDLE_ATTR, GRID_HANDLE_PROPS, GRID_ROW_ID_PREFIX, GlobalContext, GlobalProvider, GridRowContainer, HANDLE_BLEED_PX, Header, HeaderContainer, HeaderFontColorMixin, HeaderFrontView, HeaderTemplate, HeaderTitleContainer, HiddenTitleItems, IconContainer, ImageContainer, LEFT_PANEL_HEADER_HEIGHT, Layer, LayerDescription, LayerGroupList, LayerIcon, LayerIconContainer, LayerListContainer, LayerTree, LayersContainer, LayersListWrapper, LinearProgressContainer, LogTerminal, LogoContainer, MAP_VIEW_FILTER_NAMES, MAX_CHART_WIDTH, MAX_TRACKS, MIN_TRACK_PX, MIN_TRACK_RATIO, Map$1 as Map, MapContext, MapProvider, NO_CELL_DRAG_SELECTOR, NO_CONTENT_VALUE, NUMERIC_ATTRIBUTE_TYPES, NoLiveSnapshotContainer, OBJECT_FITS, OVERFLOWS, OneColumnContainer, POLL_SUBTASK_INTERVAL_MS, POLL_SUBTASK_TIMEOUT_MS, PROVIDER_PREFIX, PageNavigator, PageTitle, PageTitleContainer, PagesContainer, Pagination, PresentationHeader, PresentationHeaderButtons, PresentationHeaderTools, PresentationPanelContainer, PresentationPanelWrapper, PresentationWrapper, ProgressContainer, ProviderPrefix, QUERY_DESCRIPTION_CACHE_TTL, RoundedBackgroundContainer, SAVE_HOOK_RESULT_DURATION, SERVER_NOTIFICATION_EVENT, STACK_BAR_TOTAL_HEIGHT, ScalingFactor, ServerNotificationsContext, ServerNotificationsProvider, SlideshowContainer, SmallPreviewContainer$1 as SmallPreviewContainer, SmallPreviewControl, SmallPreviewCounter, SmallPreviewImages, SmallPreviewLeft, SmallPreviewRight, StackBar, StructuredDataContainer, SvgImage, TILE_ALIGNMENTS, TIME_ZONE_FORMAT, TITLE_SLOT_IDS, TabsContainer, TextTrim, ThemeName, TitleContainer, TopContainer, TopContainerButtons, TwoColumnContainer, UploadContainer, VIEW_MODES, WidgetType, ZOOM_FILTER_NAME, addDataSource, addDataSources, adjustColor, applyFiltersToCondition, applyQueryFilters, applyTreeFilterToCondition, applyVarsToCondition, asAttributeName, asChartId, asContainerId, asDataSourceName, asFilterName, asLayerName, asModalId, asResourceId, asTabId, buildGridTemplate, buildTrackTemplate, checkEqualOrIncludes, checkIsLoading, collectConfigIds, containsNodeId, createConfigLayer, createConfigPage, createGridCell, createGridIdFactory, createGridRow, createNewPageId, createSaveNotificationId, dateOptions, debounce, decimalOpacityToHex, enrichStyleItemsWithIds, enrichStyleModelsWithIds, eqlParametersToPayload, fetchQueryDescription, findAttributeInExpression, findCellContext, formatArea, formatAttributeValue, formatChartRelatedValue, formatConditionValue, formatDataSourceCondition, formatDate$1 as formatDate, formatElementValue, formatLength, formatNumber, formatPolygonMeasure, geometryToEwkt, getActualExtrusionHeight, getAttributeByName, getAttributeConfigurationByName, getAttributeIconElement, getAttributeIconUrl, getAttributeValue, getAttributesConfiguration, getAverageTrackSize, getChartAxes, getChartFilterName, getChartMarkers, getConfigFilter, getContainerComponent, getDashboardHeader, getDataFromAttributes, getDataFromRelatedFeatures, getDataSource, getDataSourceFilterValue, getDataSourceLayerInfo, getDate, getDefaultConfig, getDisplayTemplateNameFromAttribute, getElementValue, getFeatureAttributes, getFeatureCardHeader, getFilterComponent, getFilterSelectedItems, getFilterValue, getFormattedAttributes, getGradientColors, getImageUrl, getLayerClientStyle, getLayerInfo, getLayerInfoAttribute, getLayerInfoFromDataSources, getLayoutChildren, getMapViewDataSources, getPagesFromConfig, getPagesFromProjectInfo, getProxyService, getRelatedAttribute, getRenderElement, getResourceUrl, getRootElementId, getSelectedFilterValue, getSlideshowImages, getStyleAttributes, getSvgUrl, getTemplateNameFromAttribute, getThemeByName, getTotalFromAttributes, getTotalFromRelatedFeatures, getTrackSize, getTrackSizeKey, getTrackSizes, getWrapperSizeStyle, hexToRgba, isEmptyElementValue, isEmptyValue, isFeaturesFilterValue, isFillSize, isFrSize, isGridNode, isHiddenEmptyValue, isHookActive, isLayerService, isNotValidSelectedTab, isNumeric, isObject, isProxyService, isRootOwningContainer, isTreeFilterValue, isVisibleContainer, mapNodeById, mergeAttributeConfigurations, metersPerPixel, noMarginMixin, numberOptions, parseFrValue, parseIconNames, parseIconNamesFromClientStyle, pieChartTooltipFromAttributes, pieChartTooltipFromRelatedFeatures, pointOptions, removeDataSource, removeTracks, replaceNodesByIds, rgbToHex, roundFr, roundTotalSum, setLayoutChildren, sizeCssMixin, sliceShownOtherItems, stretchPalette, timeOptions, toConditionsArray, toCssSize, toFrSize, toPxNumber, toRenderableValue, tooltipNameFromAttributes, tooltipValueFromAttributes, tooltipValueFromRelatedFeatures, transparentizeColor, updateDataSource, useAfterSave, useAppHeight, useAttachmentItems, useAttachmentPreviewImages, useAutoCompleteControl, useBeforeSave, useChartChange, useChartData, useContainerAttributes, useContainerRoot, useCurrentPageLayers, useCustomFeatureSelect, useDashboardHeader, useDataSourceLoading, useDataSources, useDebouncedCallback, useDiffPage, useEditGroupAttributes, useEqualTileWidth, useExpandableContainers, useExportPdf, useFeatureSaveHooks, useFetchImageWithAuth, useFetchWithAuth, useGetConfigLayer, useGlobalContext, useHeaderRender, useHideIfEmptyDataSource, useIconsFromLayers, useLayerHiddenAttributes, useLayerParams, useMapContext, useMapDraw, useMapImages, useMaxZoomTo, useProjectDashboardInit, usePythonSandbox, usePythonTask, useRedrawLayer, useRelatedDataSourceAttributes, useRemoteTask, useRenderElement, useResizeBox, useSavePrototypeBuilder, useServerNotificationsContext, useShownOtherItems, useToggle, useUpdateDataSource, useVisibleProjectItems, useWidgetConfig, useWidgetContext, useWidgetFilters, useWidgetPage, useWindowResize, useWrapperSize, useZoomToFeatures, useZoomToPoint, withTrackSize };
|
|
17818
18128
|
//# sourceMappingURL=react.esm.js.map
|