@evergis/react 4.0.130 → 4.0.132

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.
Files changed (26) hide show
  1. package/dist/components/Dashboard/components/Chart/styled.d.ts +7 -0
  2. package/dist/components/Dashboard/constants.d.ts +27 -0
  3. package/dist/components/Dashboard/hooks/index.d.ts +1 -0
  4. package/dist/components/Dashboard/hooks/useDataSourceLoading.d.ts +2 -0
  5. package/dist/components/Dashboard/hooks/useGlobalContext.d.ts +2 -0
  6. package/dist/components/Dashboard/types.d.ts +13 -0
  7. package/dist/components/Dashboard/utils/applyQueryFilters.d.ts +3 -1
  8. package/dist/components/Dashboard/utils/formatDataSourceCondition.d.ts +5 -1
  9. package/dist/components/Dashboard/utils/getMapViewDataSources.d.ts +7 -0
  10. package/dist/components/Dashboard/utils/index.d.ts +2 -0
  11. package/dist/components/Dashboard/utils/toConditionsArray.d.ts +2 -0
  12. package/dist/contexts/GlobalContext/types.d.ts +4 -0
  13. package/dist/index.js +376 -241
  14. package/dist/index.js.map +1 -1
  15. package/dist/react.esm.js +369 -243
  16. package/dist/react.esm.js.map +1 -1
  17. package/package.json +2 -2
  18. package/dist/components/Dashboard/containers/StructuredDataContainer/useStructuredData.d.ts +0 -28
  19. package/dist/components/Dashboard/containers/StructuredDataContainer/useStructuredDataDraft.d.ts +0 -25
  20. package/dist/components/Dashboard/containers/StructuredDataContainer/useStructuredDataSave.d.ts +0 -17
  21. package/dist/components/Dashboard/containers/StructuredDataContainer/useStructuredDataSchema.d.ts +0 -11
  22. package/dist/components/Dashboard/containers/StructuredDataContainer/utils/viewScroll.d.ts +0 -17
  23. package/dist/components/Dashboard/elements/ElementTable/hooks/useSurfaceColor.d.ts +0 -16
  24. package/dist/components/Dashboard/elements/ElementTable/useCellEditing.d.ts +0 -15
  25. package/dist/components/Dashboard/elements/ElementTable/useTableView.d.ts +0 -16
  26. package/dist/components/Dashboard/elements/ElementTable/utils/surfaceColor.d.ts +0 -13
package/dist/index.js CHANGED
@@ -75,205 +75,6 @@ const AddFeatureButton = ({ title, icon = "feature_add" /* , layerName, geometry
75
75
  return (jsxRuntime.jsx(uilibGl.IconButton, { kind: icon, primary: true, onClick: handleAddFeature, children: title }));
76
76
  };
77
77
 
78
- const ChartTooltipTable = styled.table.withConfig({ displayName: "ChartTooltipTable", componentId: "sc-1fk3ts5" }) `
79
- td {
80
- padding: 0;
81
- }
82
-
83
- tr:not(:last-child) td {
84
- padding-bottom: 0.375rem;
85
- }
86
- `;
87
- const ChartTooltip = styled(uilibGl.Flex).withConfig({ displayName: "ChartTooltip", componentId: "sc-1iyyyv7" }) `
88
- flex-wrap: nowrap;
89
- background: rgb(48, 69, 79);
90
- border-radius: 0.25rem;
91
- color: white;
92
-
93
- :not(:last-child) {
94
- margin-bottom: 0.25rem;
95
- }
96
- `;
97
- const ChartTooltipLabel = styled.div.withConfig({ displayName: "ChartTooltipLabel", componentId: "sc-gl0qxz" }) `
98
- margin-right: 0.25rem;
99
- `;
100
- const ChartTooltipColor = styled.div.withConfig({ displayName: "ChartTooltipColor", componentId: "sc-tmvvbh" }) `
101
- width: 0.625rem;
102
- height: 0.625rem;
103
- background-color: ${({ $color }) => $color};
104
- border-radius: ${({ theme: { borderRadius } }) => borderRadius.smallest};
105
- margin-right: 0.25rem;
106
- `;
107
- const ChartLegendColor$1 = styled.div.withConfig({ displayName: "ChartLegendColor", componentId: "sc-l66k4q" }) `
108
- width: 0.5rem;
109
- height: 0.5rem;
110
- background-color: ${({ $color }) => $color};
111
- border-radius: 0.125rem;
112
- `;
113
- const ChartLegendValue = styled.div.withConfig({ displayName: "ChartLegendValue", componentId: "sc-1d7z775" }) `
114
- opacity: 0.65;
115
- `;
116
- const ChartTooltipRow = styled(uilibGl.Flex).withConfig({ displayName: "ChartTooltipRow", componentId: "sc-ih1uc5" }) `
117
- display: flex;
118
- flex-direction: row;
119
- flex-wrap: nowrap;
120
- align-items: center;
121
- margin-top: 0.5rem;
122
- line-height: 0;
123
-
124
- ${ChartLegendColor$1} {
125
- margin-right: 0.25rem;
126
- }
127
- `;
128
- const ChartTooltipName = styled.div.withConfig({ displayName: "ChartTooltipName", componentId: "sc-sm4g0t" }) `
129
- margin-right: 1rem;
130
- opacity: 0.65;
131
- `;
132
- const PieChartCenter = styled.div.withConfig({ displayName: "PieChartCenter", componentId: "sc-1le93jy" }) `
133
- position: absolute;
134
- top: 50%;
135
- left: 50%;
136
- transform: translate(-50%, -50%);
137
- text-align: center;
138
- font-weight: bold;
139
- font-size: 1.5rem;
140
- `;
141
- const ChartWrapperContainer = styled.div.withConfig({ displayName: "ChartWrapperContainer", componentId: "sc-1f4x9zv" }) `
142
- position: relative;
143
- width: 100%;
144
- `;
145
- /*
146
- * fill-режим: обёртка забирает всю доступную ячейку (её высоту задаёт флекс-цепочка, а не контент графика),
147
- * на неё вешается ref для ResizeObserver — меряем обе оси без цикла. Плоский div (не Flex uilib), как соседний
148
- * ChartWrapperContainer, чтобы ref гарантированно дошёл до DOM-узла. Тело графика центрируется внутри.
149
- */
150
- const ChartFillMeasure = styled.div.withConfig({ displayName: "ChartFillMeasure", componentId: "sc-1r4oerb" }) `
151
- position: relative;
152
- display: flex;
153
- align-items: center;
154
- justify-content: center;
155
- width: 100%;
156
- height: 100%;
157
- min-width: 0;
158
- min-height: 0;
159
- overflow: hidden;
160
-
161
- /* SVG по умолчанию inline, поэтому под ним остаётся зазор базовой линии (~4px при line-height
162
- 18.4px): вне fill его скрывал запас высоты, а тело, точно заполнившее ячейку, из-за него
163
- вылезает за нижнюю границу. Блочный SVG зазора не даёт. */
164
- svg {
165
- display: block;
166
- }
167
- `;
168
- const Tooltip = styled.div.withConfig({ displayName: "Tooltip", componentId: "sc-1va8cy3" }) `
169
- position: relative;
170
- border-radius: 0.25rem;
171
- background-color: rgba(28, 33, 48);
172
- padding: 0.5rem;
173
- box-shadow: 0 0.125rem 0.25rem 0 rgba(0, 0, 0, 0.15);
174
- font-size: 0.75rem;
175
- transform: ${({ transform }) => transform};
176
- color: white;
177
-
178
- :before {
179
- position: absolute;
180
- display: block;
181
- content: "";
182
- width: 0;
183
- height: 0;
184
- }
185
- `;
186
- const LineChartStyles = styled.createGlobalStyle `
187
- .dashboardLineChartTooltip.${charts.lineChartClassNames.lineChartMouseLabel} {
188
- .${charts.lineChartClassNames.lineChartLabelFlex} {
189
- justify-content: center;
190
- align-items: flex-end;
191
-
192
- ${Tooltip} {
193
- margin: 0 0 12px 0;
194
-
195
- :before {
196
- top: auto;
197
- bottom: 0;
198
- left: 50%;
199
- transform: translate(-50%, 100%);
200
- border-left: 4px solid transparent;
201
- border-right: 4px solid transparent;
202
- border-top: 4px solid rgba(28, 33, 48, 0.9);
203
- }
204
- }
205
- }
206
- }
207
-
208
- .${charts.lineChartClassNames.lineChartYScaleGlobal}, .${charts.lineChartClassNames.lineChartXScaleGlobal} {
209
- .domain {
210
- visibility: hidden;
211
- }
212
-
213
- .tick {
214
- text {
215
- fill: ${({ theme: { palette } }) => palette.textDisabled};
216
- }
217
-
218
- line {
219
- visibility: hidden;
220
- }
221
- }
222
- }
223
-
224
- .${charts.lineChartClassNames.lineChartXScaleGlobal} {
225
- .tick {
226
- :first-of-type {
227
- text {
228
- text-anchor: start;
229
- }
230
- }
231
-
232
- :last-of-type {
233
- text {
234
- text-anchor: end;
235
- }
236
- }
237
- }
238
- }
239
-
240
- .${charts.lineChartClassNames.lineChartLine} {
241
- stroke-width: 2px;
242
- }
243
-
244
- .${charts.lineChartClassNames.lineChartLabel} {
245
- color: ${({ theme: { palette } }) => palette.textPrimary};
246
- }
247
-
248
- .${charts.lineChartClassNames.lineChartMouseCircle} {
249
- stroke: #ffffff;
250
- stroke-width: 2px;
251
- }
252
-
253
- .${charts.lineChartClassNames.lineChartGridLineX} {
254
- stroke: ${({ theme: { palette } }) => palette.element};
255
- }
256
-
257
- text {
258
- fill: ${({ theme: { palette } }) => palette.textDisabled};
259
- }
260
- `;
261
- const StyledBarChart = styled(charts.BarChart).withConfig({ displayName: "StyledBarChart", componentId: "sc-1l1kx80" }) `
262
- .domain {
263
- display: none;
264
- }
265
-
266
- .tick {
267
- text {
268
- fill: ${({ theme: { palette } }) => palette.textDisabled};
269
- }
270
-
271
- line {
272
- visibility: hidden;
273
- }
274
- }
275
- `;
276
-
277
78
  function range(start, stop, step) {
278
79
  start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
279
80
 
@@ -3541,6 +3342,18 @@ const DEFAULT_CHART_ANGLE = 4;
3541
3342
  const DEFAULT_CHART_HEIGHT = 90;
3542
3343
  const STACK_BAR_TOTAL_HEIGHT = 20;
3543
3344
  const FILTER_PREFIX = "%";
3345
+ /** Имя системного геометрического фильтра — выделение, нарисованное пользователем на карте. */
3346
+ const GEOMETRY_FILTER_NAME = "geometry";
3347
+ /** Имя системного фильтра «экстент видимой области карты» (EWKT, `SRID=3857`). */
3348
+ const EXTENT_FILTER_NAME = "extent";
3349
+ /** Имя системного фильтра «уровень зума карты» (целое число). */
3350
+ const ZOOM_FILTER_NAME = "zoom";
3351
+ /**
3352
+ * Системные фильтры текущего вида карты. Их значения приходят не из `SelectedFilters`, а из
3353
+ * `GlobalContext`, поэтому имена зарезервированы: одноимённый пользовательский фильтр будет
3354
+ * перехвачен системной подстановкой — ровно как в случае `geometry`.
3355
+ */
3356
+ const MAP_VIEW_FILTER_NAMES = [EXTENT_FILTER_NAME, ZOOM_FILTER_NAME];
3544
3357
  const PROVIDER_PREFIX = "$";
3545
3358
  exports.ProviderPrefix = void 0;
3546
3359
  (function (ProviderPrefix) {
@@ -3576,6 +3389,22 @@ const ATTRIBUTE_ICON_ELEMENT_TYPES = {
3576
3389
  const EMPTY_DATA_SOURCE_LAYER_INFO = {
3577
3390
  configuration: { attributesConfiguration: { attributes: [] } },
3578
3391
  };
3392
+ /**
3393
+ * z-index плавающих слоёв дашборда: тултипы графиков и выпадающие списки фильтров.
3394
+ *
3395
+ * Тултипы графиков (`@evergis/charts`) и поповеры дропдаунов рендерятся порталом в `body`, где
3396
+ * их собственные z-index (100 у Bar/Line, 103 у Pie) ниже модального окна `Dialog` из
3397
+ * `@evergis/uilib-gl` (110) — внутри модалки дашборда они уходили под окно.
3398
+ */
3399
+ const DASHBOARD_OVERLAY_Z_INDEX = 1000;
3400
+ /**
3401
+ * Стиль контейнера тултипа `PieChart`: там z-index проставляется инлайном (103), поэтому поднять
3402
+ * его CSS-классом нельзя — только через `tooltipStyle`. Ключ пишем в CSS-нотации: значение уходит
3403
+ * в `d3.selection.style()` → `setProperty`, а camelCase он не понимает.
3404
+ */
3405
+ const PIE_CHART_TOOLTIP_STYLE = {
3406
+ "z-index": `${DASHBOARD_OVERLAY_Z_INDEX}`,
3407
+ };
3579
3408
  const DEFAULT_DROPDOWN_WIDTH = 312;
3580
3409
  const DEFAULT_FILTER_PADDING = 12;
3581
3410
  /** Базовый отступ обёртки контейнера. Снимается, когда контейнер занимает ячейку целиком. */
@@ -3609,6 +3438,217 @@ const CONTAINER_BODY_FILL_STYLE = {
3609
3438
  */
3610
3439
  const CONTAINERS_GROUP_DEFAULTS = { boxSizing: "border-box" };
3611
3440
 
3441
+ const ChartTooltipTable = styled.table.withConfig({ displayName: "ChartTooltipTable", componentId: "sc-1fk3ts5" }) `
3442
+ td {
3443
+ padding: 0;
3444
+ }
3445
+
3446
+ tr:not(:last-child) td {
3447
+ padding-bottom: 0.375rem;
3448
+ }
3449
+ `;
3450
+ const ChartTooltip = styled(uilibGl.Flex).withConfig({ displayName: "ChartTooltip", componentId: "sc-1iyyyv7" }) `
3451
+ flex-wrap: nowrap;
3452
+ background: rgb(48, 69, 79);
3453
+ border-radius: 0.25rem;
3454
+ color: white;
3455
+
3456
+ :not(:last-child) {
3457
+ margin-bottom: 0.25rem;
3458
+ }
3459
+ `;
3460
+ const ChartTooltipLabel = styled.div.withConfig({ displayName: "ChartTooltipLabel", componentId: "sc-gl0qxz" }) `
3461
+ margin-right: 0.25rem;
3462
+ `;
3463
+ const ChartTooltipColor = styled.div.withConfig({ displayName: "ChartTooltipColor", componentId: "sc-tmvvbh" }) `
3464
+ width: 0.625rem;
3465
+ height: 0.625rem;
3466
+ background-color: ${({ $color }) => $color};
3467
+ border-radius: ${({ theme: { borderRadius } }) => borderRadius.smallest};
3468
+ margin-right: 0.25rem;
3469
+ `;
3470
+ const ChartLegendColor$1 = styled.div.withConfig({ displayName: "ChartLegendColor", componentId: "sc-l66k4q" }) `
3471
+ width: 0.5rem;
3472
+ height: 0.5rem;
3473
+ background-color: ${({ $color }) => $color};
3474
+ border-radius: 0.125rem;
3475
+ `;
3476
+ const ChartLegendValue = styled.div.withConfig({ displayName: "ChartLegendValue", componentId: "sc-1d7z775" }) `
3477
+ opacity: 0.65;
3478
+ `;
3479
+ const ChartTooltipRow = styled(uilibGl.Flex).withConfig({ displayName: "ChartTooltipRow", componentId: "sc-ih1uc5" }) `
3480
+ display: flex;
3481
+ flex-direction: row;
3482
+ flex-wrap: nowrap;
3483
+ align-items: center;
3484
+ margin-top: 0.5rem;
3485
+ line-height: 0;
3486
+
3487
+ ${ChartLegendColor$1} {
3488
+ margin-right: 0.25rem;
3489
+ }
3490
+ `;
3491
+ const ChartTooltipName = styled.div.withConfig({ displayName: "ChartTooltipName", componentId: "sc-sm4g0t" }) `
3492
+ margin-right: 1rem;
3493
+ opacity: 0.65;
3494
+ `;
3495
+ const PieChartCenter = styled.div.withConfig({ displayName: "PieChartCenter", componentId: "sc-1le93jy" }) `
3496
+ position: absolute;
3497
+ top: 50%;
3498
+ left: 50%;
3499
+ transform: translate(-50%, -50%);
3500
+ text-align: center;
3501
+ font-weight: bold;
3502
+ font-size: 1.5rem;
3503
+ `;
3504
+ const ChartWrapperContainer = styled.div.withConfig({ displayName: "ChartWrapperContainer", componentId: "sc-1f4x9zv" }) `
3505
+ position: relative;
3506
+ width: 100%;
3507
+ `;
3508
+ /*
3509
+ * fill-режим: обёртка забирает всю доступную ячейку (её высоту задаёт флекс-цепочка, а не контент графика),
3510
+ * на неё вешается ref для ResizeObserver — меряем обе оси без цикла. Плоский div (не Flex uilib), как соседний
3511
+ * ChartWrapperContainer, чтобы ref гарантированно дошёл до DOM-узла. Тело графика центрируется внутри.
3512
+ */
3513
+ const ChartFillMeasure = styled.div.withConfig({ displayName: "ChartFillMeasure", componentId: "sc-1r4oerb" }) `
3514
+ position: relative;
3515
+ display: flex;
3516
+ align-items: center;
3517
+ justify-content: center;
3518
+ width: 100%;
3519
+ height: 100%;
3520
+ min-width: 0;
3521
+ min-height: 0;
3522
+ overflow: hidden;
3523
+
3524
+ /* SVG по умолчанию inline, поэтому под ним остаётся зазор базовой линии (~4px при line-height
3525
+ 18.4px): вне fill его скрывал запас высоты, а тело, точно заполнившее ячейку, из-за него
3526
+ вылезает за нижнюю границу. Блочный SVG зазора не даёт. */
3527
+ svg {
3528
+ display: block;
3529
+ }
3530
+ `;
3531
+ const Tooltip = styled.div.withConfig({ displayName: "Tooltip", componentId: "sc-1va8cy3" }) `
3532
+ position: relative;
3533
+ border-radius: 0.25rem;
3534
+ background-color: rgba(28, 33, 48);
3535
+ padding: 0.5rem;
3536
+ box-shadow: 0 0.125rem 0.25rem 0 rgba(0, 0, 0, 0.15);
3537
+ font-size: 0.75rem;
3538
+ transform: ${({ transform }) => transform};
3539
+ color: white;
3540
+
3541
+ :before {
3542
+ position: absolute;
3543
+ display: block;
3544
+ content: "";
3545
+ width: 0;
3546
+ height: 0;
3547
+ }
3548
+ `;
3549
+ /**
3550
+ * Тултипы графиков рендерятся в `body` со своим z-index (100 у Bar и Line) — ниже модального окна
3551
+ * `Dialog` из `@evergis/uilib-gl` (110), поэтому в модалке дашборда они уходили под окно. Класс
3552
+ * дублируем, чтобы правило перебило стили `@evergis/charts` по специфичности, а не по порядку
3553
+ * подключения.
3554
+ */
3555
+ const ChartTooltipStyles = styled.createGlobalStyle `
3556
+ .${charts.barChartClassNames.barChartMouseTooltip}.${charts.barChartClassNames.barChartMouseTooltip},
3557
+ .${charts.lineChartClassNames.lineChartMouseLabel}.${charts.lineChartClassNames.lineChartMouseLabel} {
3558
+ z-index: ${DASHBOARD_OVERLAY_Z_INDEX};
3559
+ }
3560
+ `;
3561
+ const LineChartStyles = styled.createGlobalStyle `
3562
+ .dashboardLineChartTooltip.${charts.lineChartClassNames.lineChartMouseLabel} {
3563
+ .${charts.lineChartClassNames.lineChartLabelFlex} {
3564
+ justify-content: center;
3565
+ align-items: flex-end;
3566
+
3567
+ ${Tooltip} {
3568
+ margin: 0 0 12px 0;
3569
+
3570
+ :before {
3571
+ top: auto;
3572
+ bottom: 0;
3573
+ left: 50%;
3574
+ transform: translate(-50%, 100%);
3575
+ border-left: 4px solid transparent;
3576
+ border-right: 4px solid transparent;
3577
+ border-top: 4px solid rgba(28, 33, 48, 0.9);
3578
+ }
3579
+ }
3580
+ }
3581
+ }
3582
+
3583
+ .${charts.lineChartClassNames.lineChartYScaleGlobal}, .${charts.lineChartClassNames.lineChartXScaleGlobal} {
3584
+ .domain {
3585
+ visibility: hidden;
3586
+ }
3587
+
3588
+ .tick {
3589
+ text {
3590
+ fill: ${({ theme: { palette } }) => palette.textDisabled};
3591
+ }
3592
+
3593
+ line {
3594
+ visibility: hidden;
3595
+ }
3596
+ }
3597
+ }
3598
+
3599
+ .${charts.lineChartClassNames.lineChartXScaleGlobal} {
3600
+ .tick {
3601
+ :first-of-type {
3602
+ text {
3603
+ text-anchor: start;
3604
+ }
3605
+ }
3606
+
3607
+ :last-of-type {
3608
+ text {
3609
+ text-anchor: end;
3610
+ }
3611
+ }
3612
+ }
3613
+ }
3614
+
3615
+ .${charts.lineChartClassNames.lineChartLine} {
3616
+ stroke-width: 2px;
3617
+ }
3618
+
3619
+ .${charts.lineChartClassNames.lineChartLabel} {
3620
+ color: ${({ theme: { palette } }) => palette.textPrimary};
3621
+ }
3622
+
3623
+ .${charts.lineChartClassNames.lineChartMouseCircle} {
3624
+ stroke: #ffffff;
3625
+ stroke-width: 2px;
3626
+ }
3627
+
3628
+ .${charts.lineChartClassNames.lineChartGridLineX} {
3629
+ stroke: ${({ theme: { palette } }) => palette.element};
3630
+ }
3631
+
3632
+ text {
3633
+ fill: ${({ theme: { palette } }) => palette.textDisabled};
3634
+ }
3635
+ `;
3636
+ const StyledBarChart = styled(charts.BarChart).withConfig({ displayName: "StyledBarChart", componentId: "sc-1l1kx80" }) `
3637
+ .domain {
3638
+ display: none;
3639
+ }
3640
+
3641
+ .tick {
3642
+ text {
3643
+ fill: ${({ theme: { palette } }) => palette.textDisabled};
3644
+ }
3645
+
3646
+ line {
3647
+ visibility: hidden;
3648
+ }
3649
+ }
3650
+ `;
3651
+
3612
3652
  const StackBarContainer = styled(uilibGl.Flex).withConfig({ displayName: "StackBarContainer", componentId: "sc-stc97k" }) `
3613
3653
  flex-wrap: nowrap;
3614
3654
  width: 100%;
@@ -4221,7 +4261,7 @@ const getSelectedFilterValue = (filterName, selectedFilters, defaultValue) => {
4221
4261
  : selectedFilters?.[filterName]?.value) ?? defaultValue);
4222
4262
  };
4223
4263
 
4224
- const applyQueryFilters = ({ parameters: configParameters, filters: configFilters, selectedFilters, geometry, attributes, layerInfo, dataSources, projectDataSources, }) => {
4264
+ const applyQueryFilters = ({ parameters: configParameters, filters: configFilters, selectedFilters, geometry, extent, zoomLevel, attributes, layerInfo, dataSources, projectDataSources, }) => {
4225
4265
  if (!configParameters) {
4226
4266
  return {};
4227
4267
  }
@@ -4266,12 +4306,27 @@ const applyQueryFilters = ({ parameters: configParameters, filters: configFilter
4266
4306
  const [filterName, filterProp] = filterFullName.includes(".") ? filterFullName.split(".") : [filterFullName, null];
4267
4307
  const configFilter = getConfigFilter(filterName, configFilters);
4268
4308
  const { defaultValue, relatedDataSource, attributeAlias } = configFilter || {};
4269
- if (filterName === "geometry" && geometry && !geometry.includes("()") && geometry.endsWith(")")) {
4309
+ if (filterName === GEOMETRY_FILTER_NAME && geometry && !geometry.includes("()") && geometry.endsWith(")")) {
4270
4310
  return {
4271
4311
  ...result,
4272
4312
  [key]: geometry,
4273
4313
  };
4274
4314
  }
4315
+ // Системные фильтры вида карты: значение приходит из `GlobalContext`, а не из `SelectedFilters`,
4316
+ // поэтому резолвятся до веток `.min` / `.max` / `.property` — как `geometry` выше.
4317
+ if (filterName === EXTENT_FILTER_NAME && extent) {
4318
+ return {
4319
+ ...result,
4320
+ [key]: extent,
4321
+ };
4322
+ }
4323
+ // Единственная нестроковая системная подстановка: уровень зума уходит числом.
4324
+ if (filterName === ZOOM_FILTER_NAME && !lodash.isNil(zoomLevel)) {
4325
+ return {
4326
+ ...result,
4327
+ [key]: zoomLevel,
4328
+ };
4329
+ }
4275
4330
  if (configParameters[key].endsWith(".max")) {
4276
4331
  return {
4277
4332
  ...result,
@@ -4489,13 +4544,22 @@ const applyFiltersToCondition = ({ condition, name, defaultValue, filters, isSin
4489
4544
  return applyTreeFilterToCondition(condition, name, rawValue, isSingle);
4490
4545
  }
4491
4546
  const hasFilter = filters[name] !== undefined && !!filters[name].value?.toString().length;
4547
+ const filterName = `${FILTER_PREFIX}${name}`;
4548
+ // Пока фильтр не применён, границы `%name.min` / `%name.max` берём из range-дефолта конфига
4549
+ // (`defaultValue: [from, to]`) — иначе в условие ушёл бы весь массив вместо своей границы.
4550
+ // Проверка плейсхолдеров обязательна: у array-фильтра массивный дефолт подставляется целиком.
4551
+ const rangeDefault = !hasFilter &&
4552
+ Array.isArray(defaultValue) &&
4553
+ (condition.includes(`${filterName}.min`) || condition.includes(`${filterName}.max`))
4554
+ ? defaultValue
4555
+ : null;
4492
4556
  const min = formatConditionValue({
4493
- value: hasFilter ? filters[name].min : null,
4557
+ value: hasFilter ? filters[name].min : rangeDefault?.[0] ?? null,
4494
4558
  checkQuotes: !isSingle,
4495
4559
  isSetParams,
4496
4560
  });
4497
4561
  const max = formatConditionValue({
4498
- value: hasFilter ? filters[name].max : null,
4562
+ value: hasFilter ? filters[name].max : rangeDefault?.[1] ?? null,
4499
4563
  checkQuotes: !isSingle,
4500
4564
  isSetParams,
4501
4565
  });
@@ -4505,7 +4569,6 @@ const applyFiltersToCondition = ({ condition, name, defaultValue, filters, isSin
4505
4569
  checkQuotes: !isSingle,
4506
4570
  isSetParams,
4507
4571
  });
4508
- const filterName = `${FILTER_PREFIX}${name}`;
4509
4572
  const hasMin = min !== "" && min !== null && min !== undefined;
4510
4573
  const hasMax = max !== "" && max !== null && max !== undefined;
4511
4574
  let result = condition;
@@ -4522,7 +4585,7 @@ const applyFiltersToCondition = ({ condition, name, defaultValue, filters, isSin
4522
4585
  }
4523
4586
  return isSingle && isNumeric(result) ? Number(result) : result;
4524
4587
  };
4525
- const applyVarsToCondition = ({ section, configFilters, filters, attributes, layerParams, eqlParameters, geometry, isSetParams, }) => {
4588
+ const applyVarsToCondition = ({ section, configFilters, filters, attributes, layerParams, eqlParameters, geometry, extent, zoomLevel, isSetParams, }) => {
4526
4589
  if (!section?.length)
4527
4590
  return [];
4528
4591
  const isSingle = typeof section === "string";
@@ -4531,6 +4594,17 @@ const applyVarsToCondition = ({ section, configFilters, filters, attributes, lay
4531
4594
  if (geometry && !geometry.includes("()") && geometry.endsWith(")")) {
4532
4595
  result[index] = result[index].replace(new RegExp("%geometry"), `'${geometry}'`);
4533
4596
  }
4597
+ // Системные фильтры вида карты подставляются ДО цикла по `configFilters`: одноимённый
4598
+ // пользовательский фильтр не должен перехватывать `%extent` / `%zoom`. Lookahead `(?![\w.])`
4599
+ // оставляет фильтрам составные формы (`%zoomLevel`, `%extent_id`, `%zoom.min`) — та же
4600
+ // граница, что уже разводит `%name` и `%name2.l1` в `getUpdatingDataSources`.
4601
+ if (extent) {
4602
+ result[index] = result[index].replace(new RegExp(`${FILTER_PREFIX}${EXTENT_FILTER_NAME}(?![\\w.])`, "g"), `'${extent}'`);
4603
+ }
4604
+ // Зум — число, кавычки не ставим.
4605
+ if (!lodash.isNil(zoomLevel)) {
4606
+ result[index] = result[index].replace(new RegExp(`${FILTER_PREFIX}${ZOOM_FILTER_NAME}(?![\\w.])`, "g"), String(zoomLevel));
4607
+ }
4534
4608
  if (configFilters?.length) {
4535
4609
  configFilters.forEach(filter => {
4536
4610
  result[index] = applyFiltersToCondition({
@@ -4559,7 +4633,7 @@ const applyVarsToCondition = ({ section, configFilters, filters, attributes, lay
4559
4633
  });
4560
4634
  return isSingle ? result?.[0] : result;
4561
4635
  };
4562
- const formatSingleCondition = (condition, { configFilters, filters, attributes, eqlParameters, layerParams, geometry }) => {
4636
+ const formatSingleCondition = (condition, { configFilters, filters, attributes, eqlParameters, layerParams, geometry, extent, zoomLevel, }) => {
4563
4637
  const setParams = condition.match(new RegExp("\\$\\([^)]+\\)", "g"));
4564
4638
  const setParamsSection = applyVarsToCondition({
4565
4639
  section: setParams,
@@ -4569,6 +4643,8 @@ const formatSingleCondition = (condition, { configFilters, filters, attributes,
4569
4643
  eqlParameters,
4570
4644
  layerParams,
4571
4645
  geometry,
4646
+ extent,
4647
+ zoomLevel,
4572
4648
  isSetParams: true,
4573
4649
  });
4574
4650
  const splitter = " AND ";
@@ -4581,6 +4657,8 @@ const formatSingleCondition = (condition, { configFilters, filters, attributes,
4581
4657
  eqlParameters,
4582
4658
  layerParams,
4583
4659
  geometry,
4660
+ extent,
4661
+ zoomLevel,
4584
4662
  });
4585
4663
  return setParamsSection?.length && conditionSection.length
4586
4664
  ? [setParamsSection.join(""), conditionSection.join(splitter)].join(" ")
@@ -6358,7 +6436,7 @@ const useAttachmentItems = ({ type, elementConfig, valueOverride, }) => {
6358
6436
  };
6359
6437
 
6360
6438
  const useGlobalContext = () => {
6361
- const { t, language, themeName, api, ewktGeometry, notification } = React.useContext(GlobalContext) || {};
6439
+ const { t, language, themeName, api, ewktGeometry, ewktExtent, zoomLevel, notification } = React.useContext(GlobalContext) || {};
6362
6440
  const translate = React.useCallback((value, options) => {
6363
6441
  if (t)
6364
6442
  return t(value, options);
@@ -6370,8 +6448,10 @@ const useGlobalContext = () => {
6370
6448
  themeName,
6371
6449
  api,
6372
6450
  ewktGeometry,
6451
+ ewktExtent,
6452
+ zoomLevel,
6373
6453
  notification,
6374
- }), [language, translate, api, ewktGeometry, themeName, notification]);
6454
+ }), [language, translate, api, ewktGeometry, ewktExtent, zoomLevel, themeName, notification]);
6375
6455
  };
6376
6456
 
6377
6457
  const GRID_TILE_SIZE = "4.5rem";
@@ -7177,10 +7257,17 @@ const useDashboardHeader = () => {
7177
7257
  };
7178
7258
  };
7179
7259
 
7260
+ // Полноэкранная заглушка допустима только пока не пришёл ни один источник: дальше страницу
7261
+ // и модалку наполняют сами контейнеры — у каждого свой ContainerLoading / ChartLoading.
7262
+ const useDataSourceLoading = (type) => {
7263
+ const { dataSources, isLoading } = useWidgetContext(type);
7264
+ const { currentPage } = useWidgetPage(type);
7265
+ return React.useMemo(() => !!currentPage?.dataSources?.length && !dataSources?.length && !!isLoading, [currentPage?.dataSources?.length, dataSources?.length, isLoading]);
7266
+ };
7267
+
7180
7268
  /* eslint-disable max-lines */
7181
- const toConditionsArray = (value) => Array.isArray(value) ? value : value ? [value] : [];
7182
7269
  const useDataSources = ({ type: widgetType, config, attributes, filters, layerParams, eqlParameters, }) => {
7183
- const { ewktGeometry, api } = useGlobalContext();
7270
+ const { ewktGeometry, ewktExtent, zoomLevel, api } = useGlobalContext();
7184
7271
  const { dataSources, layerInfo } = useWidgetContext(widgetType);
7185
7272
  const { dataSources: projectDataSources } = useWidgetContext(exports.WidgetType.Dashboard);
7186
7273
  const { filters: configFilters, dataSources: configDataSources } = config || {};
@@ -7208,6 +7295,8 @@ const useDataSources = ({ type: widgetType, config, attributes, filters, layerPa
7208
7295
  attributes,
7209
7296
  filters: configFilters,
7210
7297
  geometry: ewktGeometry,
7298
+ extent: ewktExtent,
7299
+ zoomLevel,
7211
7300
  layerInfo,
7212
7301
  dataSources,
7213
7302
  projectDataSources,
@@ -7282,6 +7371,8 @@ const useDataSources = ({ type: widgetType, config, attributes, filters, layerPa
7282
7371
  configFilters,
7283
7372
  filters: selectedFilters,
7284
7373
  geometry: ewktGeometry,
7374
+ extent: ewktExtent,
7375
+ zoomLevel,
7285
7376
  attributes,
7286
7377
  layerParams,
7287
7378
  eqlParameters,
@@ -7303,6 +7394,8 @@ const useDataSources = ({ type: widgetType, config, attributes, filters, layerPa
7303
7394
  dataSources,
7304
7395
  configFilters,
7305
7396
  ewktGeometry,
7397
+ ewktExtent,
7398
+ zoomLevel,
7306
7399
  api,
7307
7400
  attributes,
7308
7401
  layerParams,
@@ -12687,7 +12780,7 @@ const EditStringContainer = ({ type, elementConfig, renderElement, }) => {
12687
12780
  onControlChange(String(lastSelected?.value ?? ""));
12688
12781
  setValue(lastSelected?.text ?? "");
12689
12782
  }, [onControlChange, setValue]);
12690
- return (jsxRuntime.jsxs(Container, { id: id, isColumn: true, style: { ...BASE_CONTAINER_STYLE, ...style }, children: [jsxRuntime.jsxs(ContainerAlias, { hasBottomMargin: true, children: [renderElement({ id: "alias" }), renderElement({ id: "tooltip" })] }), jsxRuntime.jsx(ContainerValue, { column: true, children: control?.relatedDataSource ? (jsxRuntime.jsx(uilibGl.AutoComplete, { value: value, options: options, width: "100%", onChange: onChange, onSelect: onSelect })) : (jsxRuntime.jsx(uilibGl.Input, { value: controlValue, width: "100%", onChange: (e) => onControlChange(e.target.value) })) })] }));
12783
+ return (jsxRuntime.jsxs(Container, { id: id, isColumn: true, style: { ...BASE_CONTAINER_STYLE, ...style }, children: [jsxRuntime.jsxs(ContainerAlias, { hasBottomMargin: true, children: [renderElement({ id: "alias" }), renderElement({ id: "tooltip" })] }), jsxRuntime.jsx(ContainerValue, { column: true, children: control?.relatedDataSource ? (jsxRuntime.jsx(uilibGl.AutoComplete, { zIndex: DASHBOARD_OVERLAY_Z_INDEX, value: value, options: options, width: "100%", onChange: onChange, onSelect: onSelect })) : (jsxRuntime.jsx(uilibGl.Input, { value: controlValue, width: "100%", onChange: (e) => onControlChange(e.target.value) })) })] }));
12691
12784
  };
12692
12785
 
12693
12786
  const EditNumberContainer = ({ type, elementConfig, renderElement, }) => {
@@ -12700,7 +12793,7 @@ const EditDropdownContainer = ({ type, elementConfig, renderElement, }) => {
12700
12793
  const { value, control, items, onChange } = useEditControl(type, elementConfig);
12701
12794
  const { id, style } = elementConfig || {};
12702
12795
  const optionsList = React.useMemo(() => items.map(item => ({ text: item, value: item })), [items]);
12703
- return (jsxRuntime.jsxs(Container, { id: id, isColumn: true, style: { ...BASE_CONTAINER_STYLE, ...style }, children: [jsxRuntime.jsxs(ContainerAlias, { hasBottomMargin: true, children: [renderElement({ id: "alias" }), renderElement({ id: "tooltip" })] }), jsxRuntime.jsx(ContainerValue, { column: true, children: jsxRuntime.jsx(uilibGl.Dropdown, { zIndex: 1000, label: control?.label, placeholder: control?.placeholder, options: optionsList, value: value, width: `${control?.width ?? DEFAULT_DROPDOWN_WIDTH}px`, onChange: ([option]) => onChange(option.value) }) })] }));
12796
+ return (jsxRuntime.jsxs(Container, { id: id, isColumn: true, style: { ...BASE_CONTAINER_STYLE, ...style }, children: [jsxRuntime.jsxs(ContainerAlias, { hasBottomMargin: true, children: [renderElement({ id: "alias" }), renderElement({ id: "tooltip" })] }), jsxRuntime.jsx(ContainerValue, { column: true, children: jsxRuntime.jsx(uilibGl.Dropdown, { zIndex: DASHBOARD_OVERLAY_Z_INDEX, label: control?.label, placeholder: control?.placeholder, options: optionsList, value: value, width: `${control?.width ?? DEFAULT_DROPDOWN_WIDTH}px`, onChange: ([option]) => onChange(option.value) }) })] }));
12704
12797
  };
12705
12798
 
12706
12799
  const CheckboxWrapper = styled(ContainerValue).withConfig({ displayName: "CheckboxWrapper", componentId: "sc-169umb6" }) `
@@ -12741,7 +12834,7 @@ const EditDateContainer = ({ type, elementConfig, renderElement, }) => {
12741
12834
  const { withTime } = options || {};
12742
12835
  const dateValue = React.useMemo(() => (value ? new Date(value) : undefined), [value]);
12743
12836
  const handleChange = React.useCallback((date) => onChange(date.toISOString()), [onChange]);
12744
- return (jsxRuntime.jsxs(Container, { id: id, isColumn: true, style: { ...BASE_CONTAINER_STYLE, ...style }, children: [jsxRuntime.jsxs(ContainerAlias, { hasBottomMargin: true, children: [renderElement({ id: "alias" }), renderElement({ id: "tooltip" })] }), jsxRuntime.jsx(ContainerValue, { column: true, children: jsxRuntime.jsx(uilibGl.DatePicker, { value: dateValue, locale: uilibGl.getLocale(language), withTime: withTime ?? false, withHeader: true, width: "100%", onChange: handleChange }) })] }));
12837
+ return (jsxRuntime.jsxs(Container, { id: id, isColumn: true, style: { ...BASE_CONTAINER_STYLE, ...style }, children: [jsxRuntime.jsxs(ContainerAlias, { hasBottomMargin: true, children: [renderElement({ id: "alias" }), renderElement({ id: "tooltip" })] }), jsxRuntime.jsx(ContainerValue, { column: true, children: jsxRuntime.jsx(uilibGl.DatePicker, { zIndex: DASHBOARD_OVERLAY_Z_INDEX, value: dateValue, locale: uilibGl.getLocale(language), withTime: withTime ?? false, withHeader: true, width: "100%", onChange: handleChange }) })] }));
12745
12838
  };
12746
12839
 
12747
12840
  const AddButton = ({ multiple = true, accept, onSelectFiles, onSelectFromCatalog, onSelectFromLink, }) => {
@@ -13889,7 +13982,7 @@ const ElementControl = ({ elementConfig }) => {
13889
13982
  });
13890
13983
  }
13891
13984
  }, [changeControls, control?.targetAttributeName]);
13892
- return (jsxRuntime.jsx(uilibGl.Dropdown, { zIndex: 1000, width: toCssSize(width) ?? "100%", label: label, options: items, value: currentValue, placeholder: placeholder, disabled: isDisabled, onChange: handleChange }));
13985
+ return (jsxRuntime.jsx(uilibGl.Dropdown, { zIndex: DASHBOARD_OVERLAY_Z_INDEX, width: toCssSize(width) ?? "100%", label: label, options: items, value: currentValue, placeholder: placeholder, disabled: isDisabled, onChange: handleChange }));
13893
13986
  };
13894
13987
 
13895
13988
  const StyledIconFontSizeMixin = styled.css `
@@ -14063,7 +14156,7 @@ const LocalLink = React.memo(({ link, style }) => {
14063
14156
  navigator.clipboard.writeText(link);
14064
14157
  toggleOpen();
14065
14158
  }, [link, toggleOpen]);
14066
- return (jsxRuntime.jsx(uilibGl.Popover, { open: isOpen, zIndex: 10, onRequestClose: toggleOpen, anchorOrigin: "bottom-right", targetOrigin: "top-right", anchor: jsxRuntime.jsx(LocalLinkButton, { onClick: toggleOpen }), children: jsxRuntime.jsxs(LocalLinkBlank, { children: [jsxRuntime.jsx(Link, { href: link, target: "_blank", rel: "noreferrer", style: style, children: link }), jsxRuntime.jsx(LocalLinkCopy, { children: jsxRuntime.jsx(uilibGl.IconButton, { kind: "copy", onClick: onCopy, children: t("copy", { ns: "dashboard", defaultValue: "Копировать" }) }) })] }) }));
14159
+ return (jsxRuntime.jsx(uilibGl.Popover, { open: isOpen, zIndex: DASHBOARD_OVERLAY_Z_INDEX, onRequestClose: toggleOpen, anchorOrigin: "bottom-right", targetOrigin: "top-right", anchor: jsxRuntime.jsx(LocalLinkButton, { onClick: toggleOpen }), children: jsxRuntime.jsxs(LocalLinkBlank, { children: [jsxRuntime.jsx(Link, { href: link, target: "_blank", rel: "noreferrer", style: style, children: link }), jsxRuntime.jsx(LocalLinkCopy, { children: jsxRuntime.jsx(uilibGl.IconButton, { kind: "copy", onClick: onCopy, children: t("copy", { ns: "dashboard", defaultValue: "Копировать" }) }) })] }) }));
14067
14160
  });
14068
14161
 
14069
14162
  const ElementLink = React.memo(({ type, elementConfig }) => {
@@ -14684,7 +14777,7 @@ const TableCell = React.memo(({ attribute, row, canEdit, onChange }) => {
14684
14777
  }
14685
14778
  const renderEditor = () => {
14686
14779
  if (type === api.AttributeType.DateTime) {
14687
- return (jsxRuntime.jsx(uilibGl.DatePicker, { focus: true, value: dateValue, locale: uilibGl.getLocale(language), withTime: withTime, withHeader: true, width: "100%", onChange: date => handleChange(date.toISOString()) }));
14780
+ return (jsxRuntime.jsx(uilibGl.DatePicker, { zIndex: DASHBOARD_OVERLAY_Z_INDEX, focus: true, value: dateValue, locale: uilibGl.getLocale(language), withTime: withTime, withHeader: true, width: "100%", onChange: date => handleChange(date.toISOString()) }));
14688
14781
  }
14689
14782
  if (NUMBER_EDITOR_TYPES.includes(type)) {
14690
14783
  return (jsxRuntime.jsx(uilibGl.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) }));
@@ -15472,7 +15565,8 @@ const getRenderElement = ({ t, config, elementConfig, attributes = [], layerInfo
15472
15565
 
15473
15566
  const ElementModal = React.memo(({ type = exports.WidgetType.Dashboard, elementConfig }) => {
15474
15567
  const { config } = useWidgetConfig(type);
15475
- const { expandedContainers, attributes, isLoading } = useWidgetContext(type);
15568
+ const { expandedContainers, attributes } = useWidgetContext(type);
15569
+ const isDataSourceLoading = useDataSourceLoading(type);
15476
15570
  const [isOpen, setIsOpen] = React.useState(false);
15477
15571
  const { options } = elementConfig || {};
15478
15572
  const { modalId, icon } = options || {};
@@ -15492,7 +15586,7 @@ const ElementModal = React.memo(({ type = exports.WidgetType.Dashboard, elementC
15492
15586
  return null;
15493
15587
  const { options: modalOptions } = modalConfig;
15494
15588
  const { title, maxWidth, minWidth, minHeight } = modalOptions || {};
15495
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ModalIcon, { kind: icon || "new_window", onClick: handleOpen, children: title }), jsxRuntime.jsxs(uilibGl.Dialog, { maxWidth: maxWidth, minWidth: minWidth, minHeight: minHeight, isOpen: isOpen, modal: true, onCloseRequest: handleClose, style: { paddingBottom: "2rem" }, children: [jsxRuntime.jsx(uilibGl.DialogTitle, { children: jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: "space-between", alignItems: "center", children: [!!title && jsxRuntime.jsx("span", { children: title }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "close", onClick: handleClose })] }) }), jsxRuntime.jsx(uilibGl.DialogContent, { children: isLoading ? (jsxRuntime.jsx(DashboardLoading, {})) : (jsxRuntime.jsx(Container, { isColumn: true, noBorders: true, children: jsxRuntime.jsx(ContainerChildren, { type: type, items: modalContent, isMain: true, renderElement: renderElement }) })) })] })] }));
15589
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ModalIcon, { kind: icon || "new_window", onClick: handleOpen, children: title }), jsxRuntime.jsxs(uilibGl.Dialog, { maxWidth: maxWidth, minWidth: minWidth, minHeight: minHeight, isOpen: isOpen, modal: true, onCloseRequest: handleClose, style: { paddingBottom: "2rem" }, children: [jsxRuntime.jsx(uilibGl.DialogTitle, { children: jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: "space-between", alignItems: "center", children: [!!title && jsxRuntime.jsx("span", { children: title }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "close", onClick: handleClose })] }) }), jsxRuntime.jsx(uilibGl.DialogContent, { children: isDataSourceLoading ? (jsxRuntime.jsx(DashboardLoading, {})) : (jsxRuntime.jsx(Container, { isColumn: true, noBorders: true, children: jsxRuntime.jsx(ContainerChildren, { type: type, items: modalContent, isMain: true, renderElement: renderElement }) })) })] })] }));
15496
15590
  });
15497
15591
 
15498
15592
  const elementComponents = {
@@ -15761,7 +15855,7 @@ const TextFilter = ({ type, filter }) => {
15761
15855
  }, [filterName, filters]);
15762
15856
  if (!configFilter)
15763
15857
  return null;
15764
- return (jsxRuntime.jsx(TextFilterContainer, { children: jsxRuntime.jsx(uilibGl.AutoComplete, { value: value, placeholder: placeholder, options: variants || options, zIndex: 100, width: getFilterWidth(width), menuHeight: height ? `${height}px` : "10rem", withInfiniteScroll: !variants, infiniteScrollProps: variants ? undefined : infiniteScrollProps, multiSelect: multiSelect, selected: selected, setOptions: variants ? undefined : setOptions, onChange: onChange, onSelect: onSelect, onGetInnerRef: ref => (suggestRef.current = ref), asyncCallback: variants ? undefined : search, onBlur: onBlur, onKeyUp: isFreeTextInput || (variants && !variants.length) ? onKeyUp : undefined }) }));
15858
+ return (jsxRuntime.jsx(TextFilterContainer, { children: jsxRuntime.jsx(uilibGl.AutoComplete, { value: value, placeholder: placeholder, options: variants || options, zIndex: DASHBOARD_OVERLAY_Z_INDEX, width: getFilterWidth(width), menuHeight: height ? `${height}px` : "10rem", withInfiniteScroll: !variants, infiniteScrollProps: variants ? undefined : infiniteScrollProps, multiSelect: multiSelect, selected: selected, setOptions: variants ? undefined : setOptions, onChange: onChange, onSelect: onSelect, onGetInnerRef: ref => (suggestRef.current = ref), asyncCallback: variants ? undefined : search, onBlur: onBlur, onKeyUp: isFreeTextInput || (variants && !variants.length) ? onKeyUp : undefined }) }));
15765
15859
  };
15766
15860
 
15767
15861
  const getListOptions = (items, filterName, configFilters) => {
@@ -15807,7 +15901,7 @@ const DropdownFilter = ({ type, filter, elementConfig }) => {
15807
15901
  }, [changeFilters, filterName]);
15808
15902
  if (!configFilter && !variants)
15809
15903
  return null;
15810
- return (jsxRuntime.jsx(uilibGl.Dropdown, { zIndex: 100, width: getFilterWidth(width), value: value, placeholder: placeholder, options: filterOptions, onChange: onChange }));
15904
+ return (jsxRuntime.jsx(uilibGl.Dropdown, { zIndex: DASHBOARD_OVERLAY_Z_INDEX, width: getFilterWidth(width), value: value, placeholder: placeholder, options: filterOptions, onChange: onChange }));
15811
15905
  };
15812
15906
 
15813
15907
  const CheckboxFilter = ({ type, filter, elementConfig }) => {
@@ -16077,7 +16171,7 @@ const BarChartFilter = ({ type, config, elementConfig, filter }) => {
16077
16171
  return (jsxRuntime.jsx(uilibGl.ThemeProvider, { children: jsxRuntime.jsx(TooltipContainer, { children: group.groupName === group.value.toString() ? group.value : [group.groupName, group.value].join(": ") }) }));
16078
16172
  }, []);
16079
16173
  const totalHeight = height + BAR_CHART_HEADER_HEIGHT + BAR_CHART_FOOTER_MARGIN;
16080
- return (jsxRuntime.jsx(ChartWrapper, { height: totalHeight, loading: loading, style: style, children: jsxRuntime.jsxs(BarChartWrapper, { height: totalHeight, children: [jsxRuntime.jsxs(BarChartFilterHeader, { height: BAR_CHART_HEADER_HEIGHT, children: [jsxRuntime.jsxs(BarChartFilterArrows, { children: [jsxRuntime.jsx(uilibGl.IconButton, { kind: "prev", disabled: prevDisabled, onClick: onPrev }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "next", disabled: nextDisabled, onClick: onNext })] }), renderSelectedRange] }), jsxRuntime.jsx(BarChartContainer, { barHeight: barHeight, marginBottom: DEFAULT_BAR_CHART_MARGINS.bottom, children: jsxRuntime.jsx(BarChart, { data: data, margin: DEFAULT_BAR_CHART_MARGINS, height: height, barWidth: barWidth, barPadding: padding, xAxisPadding: 0, yAxisPadding: 0, selectable: !loading, dynamicTooltipEnable: true, isBarTooltip: true, renderTooltip: renderTooltip, ...rest }) })] }) }));
16174
+ return (jsxRuntime.jsxs(ChartWrapper, { height: totalHeight, loading: loading, style: style, children: [jsxRuntime.jsx(ChartTooltipStyles, {}), jsxRuntime.jsxs(BarChartWrapper, { height: totalHeight, children: [jsxRuntime.jsxs(BarChartFilterHeader, { height: BAR_CHART_HEADER_HEIGHT, children: [jsxRuntime.jsxs(BarChartFilterArrows, { children: [jsxRuntime.jsx(uilibGl.IconButton, { kind: "prev", disabled: prevDisabled, onClick: onPrev }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "next", disabled: nextDisabled, onClick: onNext })] }), renderSelectedRange] }), jsxRuntime.jsx(BarChartContainer, { barHeight: barHeight, marginBottom: DEFAULT_BAR_CHART_MARGINS.bottom, children: jsxRuntime.jsx(BarChart, { data: data, margin: DEFAULT_BAR_CHART_MARGINS, height: height, barWidth: barWidth, barPadding: padding, xAxisPadding: 0, yAxisPadding: 0, selectable: !loading, dynamicTooltipEnable: true, isBarTooltip: true, renderTooltip: renderTooltip, ...rest }) })] })] }));
16081
16175
  };
16082
16176
 
16083
16177
  const DEFAULT_FROM_DATA = { minFromData: null, maxFromData: null };
@@ -16087,6 +16181,7 @@ const RangeDateFilter = ({ type, filter }) => {
16087
16181
  const { currentPage } = useWidgetPage(type);
16088
16182
  const [value, setValue] = React.useState([undefined, undefined]);
16089
16183
  const isInit = React.useRef(false);
16184
+ const isDefaultApplied = React.useRef(false);
16090
16185
  const updateDebounce = useDebouncedCallback(FILTER_UPDATE_DEBOUNCE);
16091
16186
  const { filters: configFilters } = currentPage;
16092
16187
  const { filterName, label, minValue, maxValue, withTime } = filter.options;
@@ -16099,28 +16194,42 @@ const RangeDateFilter = ({ type, filter }) => {
16099
16194
  maxFromData: !prev.maxFromData ? date : date > prev.maxFromData ? date : prev.maxFromData
16100
16195
  };
16101
16196
  }, DEFAULT_FROM_DATA) || DEFAULT_FROM_DATA, [configFilter?.attributeValue, dataSource?.features]);
16102
- const minDate = React.useMemo(() => minValue || minFromData.toISOString(), [minFromData, minValue]);
16103
- const maxDate = React.useMemo(() => maxValue || maxFromData.toISOString(), [maxFromData, maxValue]);
16197
+ const minDate = React.useMemo(() => minValue || minFromData?.toISOString(), [minFromData, minValue]);
16198
+ const maxDate = React.useMemo(() => maxValue || maxFromData?.toISOString(), [maxFromData, maxValue]);
16199
+ // Диапазон по умолчанию: `defaultValue: [from, to]` из конфига фильтра — начальное значение
16200
+ // и точка сброса. Границы календаря (min/max) при этом не меняются; незаданная граница
16201
+ // дефолта падает на них же — как было до появления `defaultValue`.
16202
+ const defaultRange = React.useMemo(() => {
16203
+ const [from, to] = (Array.isArray(configFilter?.defaultValue) ? configFilter.defaultValue : []);
16204
+ return [getDate(from)?.toISOString() ?? minDate, getDate(to)?.toISOString() ?? maxDate];
16205
+ }, [configFilter?.defaultValue, maxDate, minDate]);
16104
16206
  const isEmpty = React.useMemo(() => lodash.isNil(value?.[0]) && lodash.isNil(value?.[1]), [value]);
16105
- const isDefault = React.useMemo(() => value?.[0] === minDate && value?.[1] === maxDate, [maxDate, minDate, value]);
16207
+ const isDefault = React.useMemo(() => value?.[0] === defaultRange[0] && value?.[1] === defaultRange[1], [defaultRange, value]);
16106
16208
  const reset = React.useCallback(() => {
16107
- setValue([minDate, maxDate]);
16209
+ const [from, to] = defaultRange;
16210
+ setValue([from, to]);
16108
16211
  changeFilters({
16109
16212
  [filterName]: {
16110
- value: [minDate, maxDate],
16111
- min: minDate,
16112
- max: maxDate
16213
+ value: [from, to],
16214
+ min: from,
16215
+ max: to
16113
16216
  }
16114
16217
  }, configFilter?.resetFilters);
16115
- }, [changeFilters, configFilter?.resetFilters, filterName, maxDate, minDate]);
16218
+ }, [changeFilters, configFilter?.resetFilters, defaultRange, filterName]);
16116
16219
  const onChange = React.useCallback((newValue) => {
16117
16220
  setValue([newValue[0].toISOString(), newValue[1].toISOString()]);
16118
16221
  }, []);
16222
+ // Дефолт применяем однократно — как только обе границы диапазона известны. С `defaultValue`
16223
+ // это происходит сразу, без него — после подгрузки фич связанного источника данных.
16119
16224
  React.useEffect(() => {
16120
- if (!lodash.isNil(minDate) && !lodash.isNil(maxDate)) {
16121
- reset();
16122
- }
16123
- }, []); // eslint-disable-line
16225
+ if (isDefaultApplied.current)
16226
+ return;
16227
+ const [from, to] = defaultRange;
16228
+ if (lodash.isNil(from) || lodash.isNil(to))
16229
+ return;
16230
+ isDefaultApplied.current = true;
16231
+ reset();
16232
+ }, [defaultRange, reset]);
16124
16233
  React.useEffect(() => {
16125
16234
  if (!isInit.current) {
16126
16235
  isInit.current = true;
@@ -16138,7 +16247,7 @@ const RangeDateFilter = ({ type, filter }) => {
16138
16247
  }, [value]); // eslint-disable-line
16139
16248
  if (!configFilter)
16140
16249
  return null;
16141
- return (jsxRuntime.jsx(uilibGl.RangeNumberInput, { label: label || t("interval", { ns: "dashboard", defaultValue: "Интервал" }), selectedOption: { range: true }, minDate: getDate(minDate), maxDate: getDate(maxDate), value: [getDate(value[0]), getDate(value[1])], zIndex: 100, prefix: jsxRuntime.jsx(uilibGl.Icon, { kind: "date", disabled: true }), suffix: !isEmpty && !isDefault && jsxRuntime.jsx(StyledIconButton, { kind: "error", onClick: reset }), withTime: withTime, isDate: true, onChange: onChange }));
16250
+ return (jsxRuntime.jsx(uilibGl.RangeNumberInput, { label: label || t("interval", { ns: "dashboard", defaultValue: "Интервал" }), selectedOption: { range: true }, minDate: getDate(minDate), maxDate: getDate(maxDate), value: [getDate(value[0]), getDate(value[1])], zIndex: DASHBOARD_OVERLAY_Z_INDEX, prefix: jsxRuntime.jsx(uilibGl.Icon, { kind: "date", disabled: true }), suffix: !isEmpty && !isDefault && jsxRuntime.jsx(StyledIconButton, { kind: "error", onClick: reset }), withTime: withTime, isDate: true, onChange: onChange }));
16142
16251
  };
16143
16252
 
16144
16253
  const getJustifyContent = (align) => {
@@ -16782,7 +16891,7 @@ const useTreeFilter = (type, filter) => {
16782
16891
 
16783
16892
  const TreeFilter = ({ type, filter }) => {
16784
16893
  const { width, placeholder, multiSelect, loading, data, setData, expanded, setExpanded, onLoadChildren, selectedIds, selectedCount, selectedLabel, searchValue, onSearchChange, onOpen, onClose, onToggleSelect, onReset, onSave, dirty, } = useTreeFilter(type, filter);
16785
- return (jsxRuntime.jsx(TreeFilterContainer, { children: jsxRuntime.jsx(uilibGl.TreeDropdown, { zIndex: 100, width: getFilterWidth(width), placeholder: placeholder, multiSelect: multiSelect, loading: loading, data: data, setData: setData, expanded: expanded, setExpanded: setExpanded, onLoadChildren: onLoadChildren, selectedIds: selectedIds, selectedCount: selectedCount, selectedLabel: selectedLabel, searchValue: searchValue, onSearchChange: onSearchChange, onOpen: onOpen, onClose: onClose, onToggleSelect: onToggleSelect, onReset: onReset, onSave: onSave, dirty: dirty }) }));
16894
+ return (jsxRuntime.jsx(TreeFilterContainer, { children: jsxRuntime.jsx(uilibGl.TreeDropdown, { zIndex: DASHBOARD_OVERLAY_Z_INDEX, width: getFilterWidth(width), placeholder: placeholder, multiSelect: multiSelect, loading: loading, data: data, setData: setData, expanded: expanded, setExpanded: setExpanded, onLoadChildren: onLoadChildren, selectedIds: selectedIds, selectedCount: selectedCount, selectedLabel: selectedLabel, searchValue: searchValue, onSearchChange: onSearchChange, onOpen: onOpen, onClose: onClose, onToggleSelect: onToggleSelect, onReset: onReset, onSave: onSave, dirty: dirty }) }));
16786
16895
  };
16787
16896
 
16788
16897
  const getFilterComponent = (filterType) => {
@@ -16844,6 +16953,25 @@ const getFilterValue = ({ selectedFilters, configFilters, filterName, newValue,
16844
16953
  return valueType === "single" ? newValue : valueType === "range" ? [newValue, newValue] : [newValue];
16845
16954
  };
16846
16955
 
16956
+ /** Условие источника задаётся строкой или массивом строк — приводим к массиву для единообразного обхода. */
16957
+ const toConditionsArray = (value) => Array.isArray(value) ? value : value ? [value] : [];
16958
+
16959
+ const MAP_VIEW_PLACEHOLDERS = MAP_VIEW_FILTER_NAMES.map(name => `${FILTER_PREFIX}${name}`);
16960
+ // Та же граница, что и при подстановке в `formatDataSourceCondition`: составные формы
16961
+ // (`%zoomLevel`, `%extent_id`, `%zoom.min`) принадлежат пользовательским фильтрам, не карте.
16962
+ const hasMapViewPlaceholder = (value) => MAP_VIEW_PLACEHOLDERS.some(placeholder => new RegExp(`${placeholder}(?![\\w.])`).test(value));
16963
+ /**
16964
+ * Источники, чей запрос зависит от текущего вида карты — в `parameters` или `condition` у них
16965
+ * есть `%extent` / `%zoom`. Перезапрашивают при движении карты только их: иначе каждый пан
16966
+ * дёргал бы все запросы страницы.
16967
+ */
16968
+ const getMapViewDataSources = (dataSources) => dataSources?.filter(({ parameters, condition }) => {
16969
+ const hasInParameters = Object.values(parameters ?? {}).some(value => typeof value === "string" && MAP_VIEW_PLACEHOLDERS.includes(value));
16970
+ if (hasInParameters)
16971
+ return true;
16972
+ return toConditionsArray(condition).some(hasMapViewPlaceholder);
16973
+ }) ?? [];
16974
+
16847
16975
  const getFormattedAttributes = (t, data, attributes, config) => {
16848
16976
  const showOtherItems = config?.options?.otherItems < data?.length;
16849
16977
  const otherIndex = config?.options?.otherItems + 1;
@@ -17320,7 +17448,7 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
17320
17448
  ?.map(item => ({
17321
17449
  ...item,
17322
17450
  color: formatFilterColor(item.name, item.color, defaultColor),
17323
- })) || []), width: pieSide, height: pieSide, padAngle: angle, outerRadius: radius, cornerRadius: cornerRadius, renderTooltip: renderPieChartTooltip, withTooltip: true, onClick: filterName ? item => onFilter(item.name) : undefined, children: showTotal && (jsxRuntime.jsx(PieChartCenter, { children: totalWord || roundTotalSum(+totalSum) })) }) }));
17451
+ })) || []), width: pieSide, height: pieSide, padAngle: angle, outerRadius: radius, cornerRadius: cornerRadius, renderTooltip: renderPieChartTooltip, tooltipStyle: PIE_CHART_TOOLTIP_STYLE, withTooltip: true, onClick: filterName ? item => onFilter(item.name) : undefined, children: showTotal && (jsxRuntime.jsx(PieChartCenter, { children: totalWord || roundTotalSum(+totalSum) })) }) }));
17324
17452
  }
17325
17453
  const barChartData = getDataFromFilterItems(data[0]?.items);
17326
17454
  // Тот же случай, что у stack: обёртка выше тела на подписи оси X (margin.bottom). В fill
@@ -17380,7 +17508,7 @@ const Chart = React.memo(({ config, element, elementConfig, type, renderElement
17380
17508
  ]);
17381
17509
  if (!isVisibleContainer(id, expandable, expanded, expandedContainers))
17382
17510
  return null;
17383
- const chartBody = (jsxRuntime.jsx(ChartWrapper, { width: isPieChart && fill ? pieSide : width, height: isStackBar ? "auto" : isPieChart ? (fill ? pieSide : width) : chartHeight, column: column, loading: loading, children: renderChart }));
17511
+ const chartBody = (jsxRuntime.jsxs(ChartWrapper, { width: isPieChart && fill ? pieSide : width, height: isStackBar ? "auto" : isPieChart ? (fill ? pieSide : width) : chartHeight, column: column, loading: loading, children: [jsxRuntime.jsx(ChartTooltipStyles, {}), renderChart] }));
17384
17512
  if (!fill)
17385
17513
  return chartBody;
17386
17514
  // fill: тело центрируется в измеряемой обёртке, ref которой питает ResizeObserver обеими осями.
@@ -17420,11 +17548,9 @@ const DashboardLoading = React.memo(() => {
17420
17548
  });
17421
17549
 
17422
17550
  const Dashboard = React.memo(({ type = exports.WidgetType.Dashboard, noBorders }) => {
17423
- const { dataSources, isLoading } = useWidgetContext(type);
17424
- const { currentPage } = useWidgetPage(type);
17551
+ const isDataSourceLoading = useDataSourceLoading(type);
17425
17552
  const isDiffPage = useDiffPage(type);
17426
- const dataSourceLoading = React.useMemo(() => !!currentPage?.dataSources?.length && !dataSources?.length && isLoading, [currentPage?.dataSources?.length, dataSources?.length, isLoading]);
17427
- if (dataSourceLoading || isDiffPage) {
17553
+ if (isDataSourceLoading || isDiffPage) {
17428
17554
  return (jsxRuntime.jsx(DashboardLoading, {}));
17429
17555
  }
17430
17556
  return (jsxRuntime.jsx(PagesContainer, { type: type, noBorders: noBorders }));
@@ -18080,6 +18206,7 @@ exports.ContainerLoading = ContainerLoading;
18080
18206
  exports.ContainerRoot = ContainerRoot;
18081
18207
  exports.ContainerWrapper = ContainerWrapper;
18082
18208
  exports.ContainersGroupContainer = ContainersGroupContainer;
18209
+ exports.DASHBOARD_OVERLAY_Z_INDEX = DASHBOARD_OVERLAY_Z_INDEX;
18083
18210
  exports.DEFAULT_ATTRIBUTE_NAME = DEFAULT_ATTRIBUTE_NAME;
18084
18211
  exports.DEFAULT_BARCHART_RADIUS = DEFAULT_BARCHART_RADIUS;
18085
18212
  exports.DEFAULT_BASE_MAP = DEFAULT_BASE_MAP;
@@ -18156,6 +18283,7 @@ exports.DefaultHeaderContainer = DefaultHeaderContainer;
18156
18283
  exports.DefaultHeaderWrapper = DefaultHeaderWrapper;
18157
18284
  exports.DividerContainer = DividerContainer;
18158
18285
  exports.EMPTY_DATA_SOURCE_LAYER_INFO = EMPTY_DATA_SOURCE_LAYER_INFO;
18286
+ exports.EXTENT_FILTER_NAME = EXTENT_FILTER_NAME;
18159
18287
  exports.ElementButton = ElementButton;
18160
18288
  exports.ElementCamera = ElementCamera;
18161
18289
  exports.ElementChart = ElementChart;
@@ -18190,6 +18318,7 @@ exports.FeatureControls = FeatureControls;
18190
18318
  exports.FeatureTitleContainer = FeatureTitleContainer;
18191
18319
  exports.FiltersContainer = FiltersContainer;
18192
18320
  exports.GEOMETRY_ATTRIBUTE = GEOMETRY_ATTRIBUTE;
18321
+ exports.GEOMETRY_FILTER_NAME = GEOMETRY_FILTER_NAME;
18193
18322
  exports.GRID_AUTO_FILL_DEFAULTS = GRID_AUTO_FILL_DEFAULTS;
18194
18323
  exports.GRID_CELL_ATTR = GRID_CELL_ATTR;
18195
18324
  exports.GRID_CELL_ID_PREFIX = GRID_CELL_ID_PREFIX;
@@ -18225,6 +18354,7 @@ exports.LayersListWrapper = LayersListWrapper;
18225
18354
  exports.LinearProgressContainer = LinearProgressContainer;
18226
18355
  exports.LogTerminal = LogTerminal;
18227
18356
  exports.LogoContainer = LogoContainer;
18357
+ exports.MAP_VIEW_FILTER_NAMES = MAP_VIEW_FILTER_NAMES;
18228
18358
  exports.MAX_CHART_WIDTH = MAX_CHART_WIDTH;
18229
18359
  exports.MAX_TRACKS = MAX_TRACKS;
18230
18360
  exports.MIN_TRACK_PX = MIN_TRACK_PX;
@@ -18239,6 +18369,7 @@ exports.NoLiveSnapshotContainer = NoLiveSnapshotContainer;
18239
18369
  exports.OBJECT_FITS = OBJECT_FITS;
18240
18370
  exports.OVERFLOWS = OVERFLOWS;
18241
18371
  exports.OneColumnContainer = OneColumnContainer;
18372
+ exports.PIE_CHART_TOOLTIP_STYLE = PIE_CHART_TOOLTIP_STYLE;
18242
18373
  exports.POLL_SUBTASK_INTERVAL_MS = POLL_SUBTASK_INTERVAL_MS;
18243
18374
  exports.POLL_SUBTASK_TIMEOUT_MS = POLL_SUBTASK_TIMEOUT_MS;
18244
18375
  exports.PROVIDER_PREFIX = PROVIDER_PREFIX;
@@ -18282,6 +18413,7 @@ exports.TopContainerButtons = TopContainerButtons;
18282
18413
  exports.TwoColumnContainer = TwoColumnContainer;
18283
18414
  exports.UploadContainer = UploadContainer;
18284
18415
  exports.VIEW_MODES = VIEW_MODES;
18416
+ exports.ZOOM_FILTER_NAME = ZOOM_FILTER_NAME;
18285
18417
  exports.addDataSource = addDataSource;
18286
18418
  exports.addDataSources = addDataSources;
18287
18419
  exports.adjustColor = adjustColor;
@@ -18367,6 +18499,7 @@ exports.getLayerInfo = getLayerInfo;
18367
18499
  exports.getLayerInfoAttribute = getLayerInfoAttribute;
18368
18500
  exports.getLayerInfoFromDataSources = getLayerInfoFromDataSources;
18369
18501
  exports.getLayoutChildren = getLayoutChildren;
18502
+ exports.getMapViewDataSources = getMapViewDataSources;
18370
18503
  exports.getPagesFromConfig = getPagesFromConfig;
18371
18504
  exports.getPagesFromProjectInfo = getPagesFromProjectInfo;
18372
18505
  exports.getProxyService = getProxyService;
@@ -18425,6 +18558,7 @@ exports.sizeCssMixin = sizeCssMixin;
18425
18558
  exports.sliceShownOtherItems = sliceShownOtherItems;
18426
18559
  exports.stretchPalette = stretchPalette;
18427
18560
  exports.timeOptions = timeOptions;
18561
+ exports.toConditionsArray = toConditionsArray;
18428
18562
  exports.toCssSize = toCssSize;
18429
18563
  exports.toFrSize = toFrSize;
18430
18564
  exports.toPxNumber = toPxNumber;
@@ -18447,6 +18581,7 @@ exports.useContainerRoot = useContainerRoot;
18447
18581
  exports.useCurrentPageLayers = useCurrentPageLayers;
18448
18582
  exports.useCustomFeatureSelect = useCustomFeatureSelect;
18449
18583
  exports.useDashboardHeader = useDashboardHeader;
18584
+ exports.useDataSourceLoading = useDataSourceLoading;
18450
18585
  exports.useDataSources = useDataSources;
18451
18586
  exports.useDebouncedCallback = useDebouncedCallback;
18452
18587
  exports.useDiffPage = useDiffPage;