@evergis/react 4.0.44 → 4.0.46

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/react.esm.js CHANGED
@@ -1,23 +1,23 @@
1
1
  import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
2
  import { IconButton, Flex, transition, Chip, Icon, Description, FlexSpan, IconToggle, Popup, Menu, DraggableTree, shadows, Divider, LegendToggler, Tooltip as Tooltip$1, DropdownField, MultiSelectContainer, IconButtonButton, FlatButton, DraggableTreeContainer, Dialog, DialogTitle, ThemeProvider, darkTheme, DialogContent, CircularProgress, Switch, AutoComplete, Input, Slider, Dropdown, Checkbox, DatePicker, getLocale, LinearProgress, H2, defaultTheme, Preview, Blank, Popover, UploaderItemArea, UploaderTitleWrapper, Uploader, NumberRangeSlider, useAsyncAutocomplete, RangeNumberInput, dateFormat } from '@evergis/uilib-gl';
3
- import { useState, useMemo, useCallback, useRef, useEffect, createContext, memo, useContext, Fragment } from 'react';
3
+ import { useState, useMemo, useCallback, createContext, memo, useRef, useEffect, useContext, Fragment } from 'react';
4
4
  import styled, { createGlobalStyle, css, useTheme } from 'styled-components';
5
5
  import { lineChartClassNames, BarChart as BarChart$1, barChartClassNames, LineChart, PieChart } from '@evergis/charts';
6
- import { AttributeType, OgcGeometryType, STORAGE_TOKEN_KEY, generateId, parseJwt, STORAGE_REFRESH_TOKEN_KEY, RemoteTaskStatus, AttributeConfigurationType } from '@evergis/api';
6
+ import { AttributeType, OgcGeometryType, generateId, STORAGE_TOKEN_KEY, parseJwt, STORAGE_REFRESH_TOKEN_KEY, RemoteTaskStatus, AttributeConfigurationType } from '@evergis/api';
7
7
  import Gradient from 'javascript-color-gradient';
8
8
  import { Color as Color$1 } from '@evergis/color';
9
9
  import { multiPolygon, polygon, multiLineString, lineString, multiPoint, point as point$1, bbox } from '@turf/turf';
10
10
  import { isValid, format, parseJSON, parseISO, toDate } from 'date-fns';
11
- import { isNil, uniqueId, isEmpty, isEqual, unescape } from 'lodash';
11
+ import { isNil, isEmpty, isEqual, uniqueId, unescape } from 'lodash';
12
12
  import { ru, enUS } from 'date-fns/locale';
13
- import { HubConnectionBuilder, HttpTransportType, LogLevel } from '@microsoft/signalr';
14
13
  import { changeProps, returnFound } from 'find-and';
15
- import { jsPDF } from 'jspdf';
16
- import html2canvas from 'html2canvas';
14
+ import { HubConnectionBuilder, HttpTransportType, LogLevel } from '@microsoft/signalr';
17
15
  import MapboxDraw from '@mapbox/mapbox-gl-draw';
18
16
  import MapGL, { Source, Layer as Layer$1 } from 'react-map-gl/maplibre';
19
17
  import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
20
18
  import 'mapbox-gl/dist/mapbox-gl.css';
19
+ import { jsPDF } from 'jspdf';
20
+ import html2canvas from 'html2canvas';
21
21
  import { Swiper, SwiperSlide } from 'swiper/react';
22
22
  import ReactMarkdown from 'react-markdown';
23
23
  import rehypeRaw from 'rehype-raw';
@@ -3959,880 +3959,461 @@ const useAutoCompleteControl = (items) => {
3959
3959
  };
3960
3960
  };
3961
3961
 
3962
- const useFetchWithAuth = (url, transform, cleanup) => {
3963
- const [data, setData] = useState(null);
3964
- const loadingRef = useRef(false);
3965
- const transformRef = useRef(transform);
3966
- const cleanupRef = useRef(cleanup);
3967
- transformRef.current = transform;
3968
- cleanupRef.current = cleanup;
3969
- const fetchData = useCallback(() => {
3970
- if (!url || loadingRef.current)
3971
- return;
3972
- loadingRef.current = true;
3973
- const token = window.localStorage.getItem(STORAGE_TOKEN_KEY);
3974
- fetch(url, {
3975
- headers: token ? { Authorization: `Bearer ${token}` } : {},
3976
- })
3977
- .then(res => (res.ok ? transformRef.current(res) : null))
3978
- .then(setData)
3979
- .catch(() => {
3980
- setData(null);
3981
- })
3982
- .finally(() => {
3983
- loadingRef.current = false;
3984
- });
3985
- }, [url]);
3986
- useEffect(() => {
3987
- if (url) {
3988
- fetchData();
3989
- }
3990
- else {
3991
- setData(null);
3992
- }
3993
- }, [url]);
3994
- useEffect(() => () => {
3995
- if (data !== null)
3996
- cleanupRef.current?.(data);
3997
- }, [data]);
3998
- return data;
3999
- };
4000
-
4001
- const toObjectUrl = (res) => res.blob().then(blob => URL.createObjectURL(blob));
4002
- const useFetchImageWithAuth = (url) => useFetchWithAuth(url, toObjectUrl, URL.revokeObjectURL);
3962
+ const eqlParametersToPayload = (parameters) => Object.keys(parameters).reduce((result, paramName) => ({
3963
+ ...result,
3964
+ [paramName]: parameters[paramName].default,
3965
+ }), {});
4003
3966
 
4004
- const DashboardContext = createContext({});
4005
- const DashboardProvider = memo(({ children, ...props }) => {
4006
- return jsx(DashboardContext.Provider, { value: props, children: children });
4007
- });
3967
+ const addDataSource = (dashboardConfiguration, pageIndex, query, additional) => {
3968
+ const newConfig = JSON.parse(JSON.stringify(dashboardConfiguration));
3969
+ if (!newConfig.children[0].children[pageIndex].dataSources) {
3970
+ newConfig.children[0].children[pageIndex].dataSources = [];
3971
+ }
3972
+ const freeId = newConfig.children[0].children[pageIndex].dataSources.length + 1;
3973
+ const parameters = eqlParametersToPayload(additional.parameters);
3974
+ newConfig.children[0].children[pageIndex].dataSources.push({
3975
+ name: `datasource_${freeId}`,
3976
+ query,
3977
+ parameters,
3978
+ offset: 0,
3979
+ limit: DEFAULT_DATA_SOURCE_LIMIT,
3980
+ });
3981
+ return newConfig.children;
3982
+ };
4008
3983
 
4009
- const FeatureCardContext = createContext({});
4010
- const FeatureCardProvider = memo(({ children, ...props }) => {
4011
- return jsx(FeatureCardContext.Provider, { value: props, children: children });
4012
- });
3984
+ const addDataSources = (dashboardConfiguration, pageIndex, layerNames) => {
3985
+ const newConfig = JSON.parse(JSON.stringify(dashboardConfiguration));
3986
+ if (!newConfig.children[0].children[pageIndex].dataSources) {
3987
+ newConfig.children[0].children[pageIndex].dataSources = [];
3988
+ }
3989
+ layerNames.forEach(layerName => {
3990
+ newConfig.children[0].children[pageIndex].dataSources.push({
3991
+ name: layerName.split(".")[1],
3992
+ layerName,
3993
+ query: "",
3994
+ parameters: {},
3995
+ });
3996
+ });
3997
+ return newConfig.children;
3998
+ };
4013
3999
 
4014
- const GlobalContext = createContext({});
4015
- const GlobalProvider = memo(({ children, ...props }) => {
4016
- return jsx(GlobalContext.Provider, { value: props, children: children });
4017
- });
4000
+ const getConfigFilter = (filterName, configFilters) => configFilters?.find(({ name }) => name === filterName);
4018
4001
 
4019
- const MapContext = createContext({});
4002
+ const getDataSource = (dataSourceName, dataSources) => dataSources?.find(({ name }) => name === dataSourceName);
4020
4003
 
4021
- const MapProvider = ({ basemapItems, defaultBasemap, children }) => {
4022
- const map = useRef();
4023
- const draw = useRef();
4024
- const [loaded, setLoaded] = useState(false);
4025
- const [basemapName, setBasemapName] = useState(defaultBasemap);
4026
- return (jsx(MapContext.Provider, { value: {
4027
- map,
4028
- draw,
4029
- loaded,
4030
- setLoaded,
4031
- basemapItems,
4032
- basemapName,
4033
- setBasemapName,
4034
- defaultBasemap,
4035
- }, children: children }));
4004
+ const getDataSourceFilterValue = ({ filterName, filterProp, attributeAlias, dataSource, selectedFilters, }) => {
4005
+ if (isNil(selectedFilters[filterName]))
4006
+ return null;
4007
+ const feature = dataSource?.features?.find(({ properties }) => properties[attributeAlias] ===
4008
+ (Array.isArray(selectedFilters[filterName].value)
4009
+ ? selectedFilters[filterName].value[0]
4010
+ : selectedFilters[filterName].value));
4011
+ return feature?.properties?.[filterProp];
4036
4012
  };
4037
4013
 
4038
- var BaseMapTheme;
4039
- (function (BaseMapTheme) {
4040
- BaseMapTheme["Light"] = "light";
4041
- BaseMapTheme["Dark"] = "dark";
4042
- })(BaseMapTheme || (BaseMapTheme = {}));
4043
-
4044
- const ServerNotificationsContext = createContext({});
4014
+ const getSelectedFilterValue = (filterName, selectedFilters, defaultValue) => {
4015
+ return ((!isNil(selectedFilters?.[filterName]?.value) &&
4016
+ Array.isArray(defaultValue) &&
4017
+ !Array.isArray(selectedFilters[filterName].value)
4018
+ ? [selectedFilters[filterName].value]
4019
+ : selectedFilters?.[filterName]?.value) ?? defaultValue);
4020
+ };
4045
4021
 
4046
- const useServerNotifications = (url, initialized, apiClient) => {
4047
- const hubConnection = useRef(null);
4048
- const [connection, setConnection] = useState(null);
4049
- const subscribeNotifications = useCallback(() => {
4050
- if (!connection || connection.state !== "Connected") {
4051
- return;
4022
+ const applyQueryFilters = ({ parameters: configParameters, filters: configFilters, selectedFilters, geometry, attributes, layerInfo, dataSources, projectDataSources, }) => {
4023
+ if (!configParameters) {
4024
+ return {};
4025
+ }
4026
+ return Object.keys(configParameters).reduce((result, key) => {
4027
+ if (typeof configParameters[key] === "string" && configParameters[key].startsWith(PROVIDER_PREFIX)) {
4028
+ const raw = configParameters[key].slice(PROVIDER_PREFIX.length);
4029
+ const [provider, layerName, fieldName] = raw.split(":");
4030
+ if (provider === ProviderPrefix.Card && fieldName && layerInfo.name === layerName && attributes) {
4031
+ const attribute = attributes.find(({ attributeName }) => attributeName === fieldName);
4032
+ const cardValue = attribute?.value ?? null;
4033
+ if (isNil(cardValue))
4034
+ return result;
4035
+ return { ...result, [key]: cardValue };
4036
+ }
4037
+ if (provider === ProviderPrefix.Left && layerName && fieldName && projectDataSources?.length) {
4038
+ const dataSource = projectDataSources.find(({ layerName: name }) => name === layerName);
4039
+ const leftValue = dataSource?.features?.[0]?.properties?.[fieldName] ?? null;
4040
+ if (isNil(leftValue))
4041
+ return result;
4042
+ return { ...result, [key]: leftValue };
4043
+ }
4044
+ return result;
4052
4045
  }
4053
- connection
4054
- .invoke("SubscribeNotifications", [])
4055
- .then(() => console.info("Подписка `SubscribeNotifications` оформлена"))
4056
- .catch(err => console.info("Ошибка подписки `SubscribeNotifications`:", err));
4057
- }, [connection]);
4058
- useEffect(() => {
4059
- if (!initialized) {
4060
- return;
4046
+ if (typeof configParameters[key] === "string" && configParameters[key].includes("{") && attributes?.length) {
4047
+ const exactAttr = attributes.find(({ attributeName }) => configParameters[key] === `{${attributeName}}`);
4048
+ if (exactAttr) {
4049
+ return { ...result, [key]: exactAttr.value ?? "" };
4050
+ }
4051
+ let interpolated = configParameters[key];
4052
+ attributes.forEach(({ attributeName, value: attrValue }) => {
4053
+ interpolated = interpolated.replace(new RegExp(`\\{${attributeName}\\}`, "g"), attrValue?.toString() ?? "");
4054
+ });
4055
+ return { ...result, [key]: interpolated };
4061
4056
  }
4062
- hubConnection.current = new HubConnectionBuilder()
4063
- .withUrl(`${url}?clientId=${generateId()}`, {
4064
- withCredentials: true,
4065
- skipNegotiation: true,
4066
- transport: HttpTransportType.WebSockets,
4067
- accessTokenFactory: async () => {
4068
- let accessToken = window.localStorage.getItem(STORAGE_TOKEN_KEY) || "";
4069
- const { exp } = parseJwt(accessToken);
4070
- const currentTime = new Date().getTime() / 1000;
4071
- if (currentTime > exp) {
4072
- const refreshToken = window.localStorage.getItem(STORAGE_REFRESH_TOKEN_KEY);
4073
- if (refreshToken) {
4074
- const refreshTokenResponse = await apiClient.account.refreshToken({
4075
- refreshToken,
4076
- });
4077
- if (refreshTokenResponse) {
4078
- accessToken = refreshTokenResponse.token;
4079
- window.localStorage.setItem(STORAGE_TOKEN_KEY, refreshTokenResponse.token);
4080
- window.localStorage.setItem(STORAGE_REFRESH_TOKEN_KEY, refreshTokenResponse.refreshToken);
4081
- }
4082
- }
4083
- else {
4084
- await apiClient.logout();
4085
- }
4086
- }
4087
- return accessToken;
4088
- },
4089
- })
4090
- .withAutomaticReconnect()
4091
- .configureLogging(LogLevel.Information)
4092
- .build();
4093
- hubConnection.current
4094
- .start()
4095
- .then(() => console.info("Серверные нотификации подключены"))
4096
- .catch(err => console.info("Ошибка:", err))
4097
- .finally(() => setConnection(hubConnection.current));
4098
- }, [initialized]); // eslint-disable-line
4099
- useEffect(() => {
4100
- if (!connection || connection.state !== "Connected") {
4101
- return;
4057
+ if (typeof configParameters[key] !== "string" || !configParameters[key].startsWith("%")) {
4058
+ return {
4059
+ ...result,
4060
+ [key]: configParameters[key],
4061
+ };
4102
4062
  }
4103
- connection.onreconnecting(() => console.info("Переподключение к серверным нотификациям"));
4104
- connection.onreconnected(subscribeNotifications);
4105
- subscribeNotifications();
4106
- }, [connection]);
4107
- return connection;
4108
- };
4109
-
4110
- const ServerNotificationsProvider = ({ url, initialized, apiClient, children }) => {
4111
- const connection = useServerNotifications(url, initialized, apiClient);
4112
- const addSubscription = useCallback(async (payload) => {
4113
- if (!connection || connection.state !== "Connected" || !payload) {
4114
- return;
4063
+ const filterFullName = configParameters[key].replace("%", "");
4064
+ const [filterName, filterProp] = filterFullName.includes(".") ? filterFullName.split(".") : [filterFullName, null];
4065
+ const { defaultValue, relatedDataSource, attributeAlias } = getConfigFilter(filterName, configFilters) || {};
4066
+ if (filterName === "geometry" && geometry && !geometry.includes("()") && geometry.endsWith(")")) {
4067
+ return {
4068
+ ...result,
4069
+ [key]: geometry,
4070
+ };
4115
4071
  }
4116
- try {
4117
- const id = await connection.invoke("AddSubscription", payload);
4118
- console.info("Подписка добавлена, id:", id);
4119
- return id;
4072
+ if (configParameters[key].endsWith(".max")) {
4073
+ return {
4074
+ ...result,
4075
+ [key]: selectedFilters?.[filterName]?.max ?? (Array.isArray(defaultValue) ? defaultValue[1] : defaultValue),
4076
+ };
4120
4077
  }
4121
- catch (err) {
4122
- console.info("Ошибка добавления подписки:", err);
4123
- return Promise.resolve(null);
4124
- }
4125
- }, [connection]);
4126
- const updateSubscription = useCallback(async (id, payload) => {
4127
- if (!connection || connection.state !== "Connected" || !id || !payload) {
4128
- return;
4129
- }
4130
- try {
4131
- await connection.invoke("UpdateSubscription", id, payload);
4132
- }
4133
- catch (err) {
4134
- console.info(`Ошибка обновления подписки ${id}:`, err);
4135
- }
4136
- }, [connection]);
4137
- const unsubscribeById = useCallback(async (id) => {
4138
- if (!connection || connection.state !== "Connected" || !id) {
4139
- return;
4078
+ if (configParameters[key].endsWith(".min")) {
4079
+ return {
4080
+ ...result,
4081
+ [key]: selectedFilters?.[filterName]?.min ?? (Array.isArray(defaultValue) ? defaultValue[0] : defaultValue),
4082
+ };
4140
4083
  }
4141
- try {
4142
- await connection.invoke("Unsubscribe", [id]);
4084
+ if (configParameters[key].includes(".")) {
4085
+ return {
4086
+ ...result,
4087
+ [key]: getDataSourceFilterValue({
4088
+ filterName,
4089
+ filterProp,
4090
+ selectedFilters,
4091
+ attributeAlias,
4092
+ dataSource: getDataSource(relatedDataSource, dataSources),
4093
+ }) ?? defaultValue,
4094
+ };
4143
4095
  }
4144
- catch (err) {
4145
- console.info(`Ошибка отписки по ${id}:`, err);
4096
+ const value = getSelectedFilterValue(filterName, selectedFilters, defaultValue);
4097
+ if (isNil(value)) {
4098
+ return result;
4146
4099
  }
4147
- }, [connection]);
4148
- return (jsx(ServerNotificationsContext.Provider, { value: {
4149
- connection,
4150
- addSubscription,
4151
- updateSubscription,
4152
- unsubscribeById,
4153
- }, children: children }));
4100
+ return {
4101
+ ...result,
4102
+ [key]: value,
4103
+ };
4104
+ }, {});
4154
4105
  };
4155
4106
 
4156
- const useWidgetContext = (type = WidgetType.Dashboard) => {
4157
- const { toggleLayersVisibility, visibleLayers, projectInfo, updateProject, layerInfos, geometryFilter, dashboardLayers, setDashboardLayer, components: dashboardComponents, config: dashboardConfig, containerIds, pageIndex: projectPageIndex, selectedTabId: projectSelectedTabId, setSelectedTabId: setProjectSelectedTabId, dataSources: projectDataSources, loading: projectLoading, editMode: projectEditMode, filters: projectFilters, changeFilters: projectChangeFilters, expandContainer: projectExpandContainer, expandedContainers: projectExpandedContainers, nextPage: projectNextPage, prevPage: projectPrevPage, changePage: projectChangePage, } = useContext(DashboardContext) || {};
4158
- const { layerInfo, attributes, feature, controls, changeControls, closeFeatureCard, config: featureConfig, pageIndex: featurePageIndex, selectedTabId: featureSelectedTabId, setSelectedTabId: setFeatureSelectedTabId, dataSources: featureDataSources, loading: featureLoading, editMode: featureEditMode, filters: featureFilters, changeFilters: featureChangeFilters, expandContainer: featureExpandContainer, expandedContainers: featureExpandedContainers, nextPage: featureNextPage, prevPage: featurePrevPage, changePage: featureChangePage, } = useContext(FeatureCardContext) || {};
4107
+ const checkEqualOrIncludes = (arrayOrSingle, value) => arrayOrSingle && Array.isArray(arrayOrSingle) ? arrayOrSingle.includes(value) : arrayOrSingle === value;
4108
+
4109
+ const checkIsLoading = (dataSources, config, filters) => config?.children?.some(child => {
4110
+ const filter = filters?.find(({ name }) => name === child.options?.filterName);
4111
+ return (!!filter && !!child.options?.filterName && !dataSources?.some(({ name }) => name === filter.relatedDataSource));
4112
+ });
4113
+
4114
+ const createConfigLayer = (layerName) => ({
4115
+ name: layerName,
4116
+ query: "",
4117
+ parameters: {},
4118
+ opacity: 1,
4119
+ selectable: false,
4120
+ filterZoomTo: false,
4121
+ isVisible: true,
4122
+ });
4123
+
4124
+ const createNewPageId = (pages) => {
4125
+ if (!pages?.length)
4126
+ return 1;
4127
+ const maxPageId = pages.reduce((maxId, page) => {
4128
+ const pageId = parseInt(page.id.replace(CONFIG_PAGE_ID, ""), 10);
4129
+ return Math.max(maxId, pageId);
4130
+ }, 0);
4131
+ return maxPageId + 1;
4132
+ };
4133
+
4134
+ const createConfigPage = (props) => {
4135
+ const { title, defaultTitle, pages, baseMapName, position, resolution /* , srid*/ } = props || {};
4136
+ const pageId = createNewPageId(pages);
4159
4137
  return {
4160
- toggleLayersVisibility,
4161
- visibleLayers,
4162
- projectInfo,
4163
- layerInfos,
4164
- updateProject,
4165
- dashboardLayers,
4166
- setDashboardLayer,
4167
- geometryFilter,
4168
- layerInfo,
4169
- attributes,
4170
- feature,
4171
- closeFeatureCard,
4172
- containerIds,
4173
- controls,
4174
- changeControls,
4175
- components: dashboardComponents,
4176
- config: type === WidgetType.Dashboard ? dashboardConfig : featureConfig,
4177
- isEditing: type === WidgetType.Dashboard ? projectEditMode : featureEditMode,
4178
- isLoading: type === WidgetType.Dashboard ? projectLoading : featureLoading,
4179
- pageIndex: type === WidgetType.Dashboard ? projectPageIndex || 1 : featurePageIndex || 1,
4180
- filters: type === WidgetType.Dashboard ? projectFilters : featureFilters,
4181
- changeFilters: type === WidgetType.Dashboard ? projectChangeFilters : featureChangeFilters,
4182
- dataSources: type === WidgetType.Dashboard ? projectDataSources : featureDataSources,
4183
- expandContainer: type === WidgetType.Dashboard ? projectExpandContainer : featureExpandContainer,
4184
- expandedContainers: type === WidgetType.Dashboard ? projectExpandedContainers : featureExpandedContainers,
4185
- selectedTabId: type === WidgetType.Dashboard ? projectSelectedTabId : featureSelectedTabId,
4186
- setSelectedTabId: type === WidgetType.Dashboard ? setProjectSelectedTabId : setFeatureSelectedTabId,
4187
- nextPage: type === WidgetType.Dashboard ? projectNextPage : featureNextPage,
4188
- prevPage: type === WidgetType.Dashboard ? projectPrevPage : featurePrevPage,
4189
- changePage: type === WidgetType.Dashboard ? projectChangePage : featureChangePage,
4138
+ id: `${CONFIG_PAGE_ID}${pageId}`,
4139
+ templateName: ContainerTemplate.ContainersGroup,
4140
+ children: [],
4141
+ layers: [],
4142
+ dataSources: [],
4143
+ filters: [],
4144
+ tasks: [],
4145
+ style: {},
4146
+ options: {
4147
+ title: title || [defaultTitle, pageId].filter(Boolean).join(" "),
4148
+ position: position || [DEFAULT_LNG, DEFAULT_LAT],
4149
+ resolution: resolution || DEFAULT_ZOOM,
4150
+ baseMapName: baseMapName || DEFAULT_BASE_MAP,
4151
+ baseMapSettings: {},
4152
+ expandedLayers: true,
4153
+ // srid: srid || null,
4154
+ },
4190
4155
  };
4191
4156
  };
4192
4157
 
4193
- const useGlobalContext = () => {
4194
- const { t, language, themeName, api, ewktGeometry } = useContext(GlobalContext) || {};
4195
- const translate = useCallback((value, options) => {
4196
- if (t)
4197
- return t(value, options);
4198
- return options?.defaultValue ?? value;
4199
- }, [t]);
4200
- return useMemo(() => ({
4201
- t: translate,
4202
- language,
4203
- themeName,
4204
- api,
4205
- ewktGeometry,
4206
- }), [language, translate, api, ewktGeometry, themeName]);
4158
+ const getAttributesConfiguration = (layer) => {
4159
+ const layerAttributeConfiguration = layer?.configuration?.attributesConfiguration ?? {};
4160
+ const { geometryAttribute, idAttribute } = layerAttributeConfiguration;
4161
+ const emptyLayerDefinition = {
4162
+ attributes: [],
4163
+ geometryAttribute: geometryAttribute ?? GEOMETRY_ATTRIBUTE,
4164
+ idAttribute: idAttribute ?? DEFAULT_ID_ATTRIBUTE_NAME,
4165
+ titleAttribute: "",
4166
+ };
4167
+ if (!isLayerService(layer)) {
4168
+ return emptyLayerDefinition;
4169
+ }
4170
+ return {
4171
+ ...emptyLayerDefinition,
4172
+ ...layerAttributeConfiguration,
4173
+ attributes: layerAttributeConfiguration?.attributes ||
4174
+ emptyLayerDefinition.attributes,
4175
+ };
4207
4176
  };
4208
4177
 
4209
- const HEIGHT_OFFSET = 20;
4210
- const FILL_OPACITY = 0.28;
4211
- const lineGenerator = line()
4212
- .x(d => d[0])
4213
- .y(d => d[1])
4214
- .curve(monotoneX);
4215
- const areaGenerator = (height) => area()
4216
- .defined(d => d !== null)
4217
- .x(d => d[0])
4218
- .y0(height - HEIGHT_OFFSET)
4219
- .y1(d => d[1])
4220
- .curve(monotoneX);
4221
- function getLinePoints(numPoints, svgLine) {
4222
- if (!svgLine?.getTotalLength) {
4223
- return [];
4224
- }
4225
- const lineLength = svgLine.getTotalLength();
4226
- let interval;
4227
- if (numPoints === 1) {
4228
- interval = 0;
4178
+ const formatChartRelatedValue = (t, value, layerInfo, relatedAttributes) => {
4179
+ const layerDefinition = getAttributesConfiguration(layerInfo);
4180
+ const relatedAxis = relatedAttributes.find(({ chartAxis }) => chartAxis === "y");
4181
+ const attribute = layerDefinition.attributes[relatedAxis.attributeName];
4182
+ return attribute ? formatAttributeValue({ t, type: attribute.type, value, stringFormat: attribute.stringFormat }) : value;
4183
+ };
4184
+
4185
+ const isEmptyValue = (value) => value === "" || value === null || value === undefined;
4186
+
4187
+ const checkIsDateFormat = (value) => value.startsWith("#'") && value.endsWith("'");
4188
+ const checkIfNeedQuotes = (value, attributeType) => {
4189
+ return attributeType
4190
+ ? !NUMERIC_ATTRIBUTE_TYPES.includes(attributeType)
4191
+ : typeof value === "number"
4192
+ ? false
4193
+ : typeof value === "string" && !isNumeric(value) && !checkIsDateFormat(value);
4194
+ };
4195
+ const formatConditionValue = ({ value, attributeType, defaultValue, checkQuotes = true, isSetParams = false, }) => {
4196
+ if (isEmptyValue(value))
4197
+ return "";
4198
+ const formattedValue = Array.isArray(defaultValue) && !Array.isArray(value) ? [value] : value;
4199
+ const isArray = Array.isArray(formattedValue);
4200
+ let stringValue = formattedValue.toString();
4201
+ if (isArray) {
4202
+ return formattedValue.length && !formattedValue.every(item => !item)
4203
+ ? `[${formattedValue
4204
+ .map(item => (checkQuotes && checkIfNeedQuotes(item, attributeType) ? `'${item}'` : item))
4205
+ .join(",")}]`
4206
+ : "";
4229
4207
  }
4230
- else {
4231
- interval = lineLength / (numPoints - 1);
4208
+ if (isSetParams && checkIsDateFormat(stringValue)) {
4209
+ stringValue = stringValue.slice(2, -1);
4232
4210
  }
4233
- return range(numPoints)
4234
- .filter(d => d * interval)
4235
- .map(d => {
4236
- const value = d * interval;
4237
- const { x, y } = svgLine.getPointAtLength(value);
4238
- return [x, y];
4211
+ return checkQuotes && checkIfNeedQuotes(stringValue, attributeType) ? `'${stringValue}'` : stringValue;
4212
+ };
4213
+
4214
+ const applyFiltersToCondition = ({ condition, name, defaultValue, filters, isSingle, isSetParams, }) => {
4215
+ const hasFilter = filters[name] !== undefined && !!filters[name].value?.toString().length;
4216
+ const min = formatConditionValue({
4217
+ value: hasFilter ? filters[name].min : null,
4218
+ checkQuotes: !isSingle,
4219
+ isSetParams,
4239
4220
  });
4240
- }
4241
- function wrap() {
4242
- const width = 80;
4243
- const padding = 10;
4244
- const self = select(this);
4245
- let textLength = self.node().getComputedTextLength();
4246
- let text = self.text();
4247
- while (textLength > width - 2 * padding && text.length > 0) {
4248
- text = text.slice(0, -1);
4249
- self.text(`${text}...`);
4250
- textLength = self.node().getComputedTextLength();
4251
- }
4252
- }
4253
- const useChartChange = ({ dataSources, chartId, width, height, relatedAttributes, defaultColor, fontColor, markers, showMarkers, }) => {
4254
- const { t } = useGlobalContext();
4255
- const { layerInfos } = useWidgetContext();
4256
- const strokeColors = relatedAttributes
4257
- .filter(({ chartAxis }) => chartAxis === "y")
4258
- .map(({ axisColor }) => axisColor);
4259
- const ref = useRef({
4260
- path: null,
4261
- area: null,
4262
- points: [],
4221
+ const max = formatConditionValue({
4222
+ value: hasFilter ? filters[name].max : null,
4223
+ checkQuotes: !isSingle,
4224
+ isSetParams,
4263
4225
  });
4264
- const onChange = useCallback((range) => {
4265
- const { path, area, points } = ref.current;
4266
- let filteredPoints = [...points];
4267
- if (range) {
4268
- const hundred = 100;
4269
- const x1 = +width * (range[0] / hundred);
4270
- const x2 = +width * (range[1] / hundred);
4271
- filteredPoints = points.filter(([x]) => x >= x1 && x <= x2);
4226
+ const value = formatConditionValue({
4227
+ value: hasFilter ? filters[name].value : filters[name] === undefined ? defaultValue : "",
4228
+ defaultValue,
4229
+ checkQuotes: !isSingle,
4230
+ isSetParams,
4231
+ });
4232
+ const filterName = `${FILTER_PREFIX}${name}`;
4233
+ const hasMin = min !== "" && min !== null && min !== undefined;
4234
+ const hasMax = max !== "" && max !== null && max !== undefined;
4235
+ let result = condition;
4236
+ if (hasMin || hasMax) {
4237
+ if (hasMin) {
4238
+ result = result.replace(new RegExp(`${filterName}\\.min`), min);
4239
+ }
4240
+ if (hasMax) {
4241
+ result = result.replace(new RegExp(`${filterName}\\.max`), max);
4272
4242
  }
4273
- path && path.attr("d", lineGenerator(filteredPoints));
4274
- area && area.attr("d", areaGenerator(height)(filteredPoints));
4275
- }, [height, width]);
4276
- const customize = useCallback(({ svg }) => {
4277
- svg.style("overflow", "visible");
4278
- svg
4279
- .selectAll(`.${lineChartClassNames.lineChartXScaleGlobal} line,
4280
- .${lineChartClassNames.lineChartYScaleGlobal} line,
4281
- .domain`)
4282
- .each((_, index, nodes) => {
4283
- nodes[index].remove();
4284
- });
4285
- svg
4286
- .selectAll(`.${lineChartClassNames.lineChartXScaleGlobal} .tick`)
4287
- .each((_, index, nodes) => {
4288
- if (!index) {
4289
- nodes[index].style.textAnchor = "start";
4290
- }
4291
- if (index === nodes.length - 1) {
4292
- nodes[index].style.textAnchor = "end";
4293
- }
4294
- if (markers) {
4295
- nodes[index].remove();
4296
- }
4297
- if (showMarkers) {
4298
- if (index % showMarkers !== 0) {
4299
- nodes[index].remove();
4300
- }
4301
- }
4302
- else {
4303
- if (index && index < nodes.length - 1) {
4304
- nodes[index].remove();
4305
- }
4306
- }
4307
- });
4308
- svg
4309
- .selectAll(`.${lineChartClassNames.lineChartXScaleGlobal} .tick text`)
4310
- .attr("y", 16);
4311
- svg
4312
- .selectAll(`.${lineChartClassNames.lineChartYScaleGlobal} .tick text`)
4313
- .text(item => {
4314
- if (!item)
4315
- return 0;
4316
- const dataSource = dataSources?.find(({ name }) => name === relatedAttributes[0].dataSourceName);
4317
- const layerInfo = dataSource
4318
- ? layerInfos.find(({ name }) => name === dataSource.layerName)
4319
- : null;
4320
- const attribute = layerInfo?.configuration?.attributesConfiguration?.attributes[relatedAttributes[0].attributeName];
4321
- return attribute
4322
- ? formatAttributeValue({
4323
- t,
4324
- type: attribute.type,
4325
- value: item,
4326
- stringFormat: attribute.stringFormat,
4327
- noUnits: true,
4328
- })
4329
- : item;
4330
- })
4331
- .each(wrap);
4332
- svg.selectAll(".tick text").attr("style", `color: ${fontColor}`);
4333
- const global = svg.select(`.${lineChartClassNames.lineChartLinesGlobal}`);
4334
- const lineChartLines = svg.selectAll(`.${lineChartClassNames.lineChartLine}`);
4335
- const defs = [];
4336
- lineChartLines.each((_, index, nodes) => {
4337
- const lineChartLine = nodes[index];
4338
- const gradientId = uniqueId(`${chartId}-gradient-`);
4339
- const color = strokeColors[index] || defaultColor;
4340
- const newPath = global
4341
- .append("path")
4342
- .attr("stroke", color)
4343
- .attr("stroke-width", "0")
4344
- .attr("class", lineChartClassNames.lineChartLine);
4345
- const points = getLinePoints(+width, lineChartLine);
4346
- const area = global
4347
- .append("path")
4348
- .attr("fill", `url(#${gradientId})`)
4349
- .attr("stroke-width", "0")
4350
- .attr("fill-opacity", FILL_OPACITY);
4351
- defs.push(`
4352
- <linearGradient id="${gradientId}" x1="0" y1="0" x2="0" y2="1">
4353
- <stop offset="0" stop-color="${color}" stop-opacity="1" />
4354
- <stop offset="1" stop-color="${color}" stop-opacity="0" />
4355
- </linearGradient>
4356
- `);
4357
- ref.current = {
4358
- path: newPath,
4359
- area,
4360
- points,
4361
- };
4362
- onChange();
4363
- });
4364
- svg.append("defs").html(() => defs.join(""));
4365
- }, [
4366
- fontColor,
4367
- dataSources,
4368
- layerInfos,
4369
- relatedAttributes,
4370
- chartId,
4371
- strokeColors,
4372
- defaultColor,
4373
- width,
4374
- onChange,
4375
- showMarkers,
4376
- markers,
4377
- ]);
4378
- return [customize, onChange];
4379
- };
4380
-
4381
- const eqlParametersToPayload = (parameters) => Object.keys(parameters).reduce((result, paramName) => ({
4382
- ...result,
4383
- [paramName]: parameters[paramName].default,
4384
- }), {});
4385
-
4386
- const addDataSource = (dashboardConfiguration, pageIndex, query, additional) => {
4387
- const newConfig = JSON.parse(JSON.stringify(dashboardConfiguration));
4388
- if (!newConfig.children[0].children[pageIndex].dataSources) {
4389
- newConfig.children[0].children[pageIndex].dataSources = [];
4390
4243
  }
4391
- const freeId = newConfig.children[0].children[pageIndex].dataSources.length + 1;
4392
- const parameters = eqlParametersToPayload(additional.parameters);
4393
- newConfig.children[0].children[pageIndex].dataSources.push({
4394
- name: `datasource_${freeId}`,
4395
- query,
4396
- parameters,
4397
- offset: 0,
4398
- limit: DEFAULT_DATA_SOURCE_LIMIT,
4244
+ else if (value) {
4245
+ result = result.replace(new RegExp(filterName), value);
4246
+ }
4247
+ return isSingle && isNumeric(result) ? Number(result) : result;
4248
+ };
4249
+ const applyVarsToCondition = ({ section, configFilters, filters, attributes, layerParams, eqlParameters, geometry, isSetParams, }) => {
4250
+ if (!section?.length)
4251
+ return [];
4252
+ const isSingle = typeof section === "string";
4253
+ const result = isSingle ? [section] : [...section];
4254
+ result.forEach((_, index) => {
4255
+ if (geometry && !geometry.includes("()") && geometry.endsWith(")")) {
4256
+ result[index] = result[index].replace(new RegExp("%geometry"), `'${geometry}'`);
4257
+ }
4258
+ if (configFilters?.length) {
4259
+ configFilters.forEach(filter => {
4260
+ result[index] = applyFiltersToCondition({
4261
+ filters,
4262
+ condition: result[index],
4263
+ name: filter.name,
4264
+ defaultValue: filter.defaultValue,
4265
+ isSetParams,
4266
+ isSingle: isSingle && !Array.isArray(filter.defaultValue),
4267
+ }).toString();
4268
+ });
4269
+ }
4270
+ if (attributes?.length) {
4271
+ attributes.forEach(({ attributeName, value, type: attributeType }) => {
4272
+ result[index] = result[index].replace(new RegExp(`{${attributeName}}`), formatConditionValue({ value: value?.toString(), attributeType, checkQuotes: !isSingle }));
4273
+ });
4274
+ }
4275
+ if (eqlParameters && layerParams) {
4276
+ Object.keys(eqlParameters).forEach(param => {
4277
+ result[index] = result[index].replace(new RegExp(`\\$\\(${param}=`), "***");
4278
+ result[index] = result[index].replace(new RegExp(param), formatConditionValue({ value: layerParams[param], checkQuotes: !isSingle }));
4279
+ result[index] = result[index].replace(new RegExp("\\*\\*\\*"), `$(${param}=`);
4280
+ });
4281
+ }
4399
4282
  });
4400
- return newConfig.children;
4283
+ return isSingle ? result?.[0] : result;
4401
4284
  };
4402
-
4403
- const addDataSources = (dashboardConfiguration, pageIndex, layerNames) => {
4404
- const newConfig = JSON.parse(JSON.stringify(dashboardConfiguration));
4405
- if (!newConfig.children[0].children[pageIndex].dataSources) {
4406
- newConfig.children[0].children[pageIndex].dataSources = [];
4407
- }
4408
- layerNames.forEach(layerName => {
4409
- newConfig.children[0].children[pageIndex].dataSources.push({
4410
- name: layerName.split(".")[1],
4411
- layerName,
4412
- query: "",
4413
- parameters: {},
4414
- });
4285
+ const formatSingleCondition = (condition, { configFilters, filters, attributes, eqlParameters, layerParams, geometry }) => {
4286
+ const setParams = condition.match(new RegExp("\\$\\([^)]+\\)", "g"));
4287
+ const setParamsSection = applyVarsToCondition({
4288
+ section: setParams,
4289
+ configFilters,
4290
+ filters,
4291
+ attributes,
4292
+ eqlParameters,
4293
+ layerParams,
4294
+ geometry,
4295
+ isSetParams: true,
4415
4296
  });
4416
- return newConfig.children;
4297
+ const splitter = " AND ";
4298
+ const setParamsLength = setParams?.join("").length || 0;
4299
+ const conditionSection = applyVarsToCondition({
4300
+ section: condition.substring(setParamsLength).split(splitter),
4301
+ configFilters,
4302
+ filters,
4303
+ attributes,
4304
+ eqlParameters,
4305
+ layerParams,
4306
+ geometry,
4307
+ });
4308
+ return setParamsSection?.length && conditionSection.length
4309
+ ? [setParamsSection.join(""), conditionSection.join(splitter)].join(" ")
4310
+ : setParamsSection?.length
4311
+ ? setParamsSection.join("")
4312
+ : conditionSection.join(splitter);
4313
+ };
4314
+ const formatDataSourceCondition = ({ condition, ...rest }) => {
4315
+ if (Array.isArray(condition)) {
4316
+ return condition.map(item => formatSingleCondition(item, rest));
4317
+ }
4318
+ if (!condition) {
4319
+ return "";
4320
+ }
4321
+ return formatSingleCondition(condition, rest);
4417
4322
  };
4418
4323
 
4419
- const getConfigFilter = (filterName, configFilters) => configFilters?.find(({ name }) => name === filterName);
4324
+ const DashboardChipsContainer = styled(Flex) `
4325
+ flex-wrap: wrap;
4326
+ `;
4327
+ const DefaultChipColorMixin = css `
4328
+ && {
4329
+ color: ${({ theme: { palette } }) => palette.textPrimary};
4330
+ }
4420
4331
 
4421
- const getDataSource = (dataSourceName, dataSources) => dataSources?.find(({ name }) => name === dataSourceName);
4332
+ && > * {
4333
+ color: ${({ theme: { palette } }) => palette.textPrimary};
4334
+ }
4422
4335
 
4423
- const getDataSourceFilterValue = ({ filterName, filterProp, attributeAlias, dataSource, selectedFilters, }) => {
4424
- if (isNil(selectedFilters[filterName]))
4425
- return null;
4426
- const feature = dataSource?.features?.find(({ properties }) => properties[attributeAlias] ===
4427
- (Array.isArray(selectedFilters[filterName].value)
4428
- ? selectedFilters[filterName].value[0]
4429
- : selectedFilters[filterName].value));
4430
- return feature?.properties?.[filterProp];
4431
- };
4336
+ && span[kind]:after {
4337
+ color: ${({ theme: { palette } }) => palette.icon};
4338
+ }
4339
+ `;
4340
+ const CustomChipColorMixin = css `
4341
+ && {
4342
+ color: ${({ $fontColor }) => $fontColor};
4343
+ }
4432
4344
 
4433
- const getSelectedFilterValue = (filterName, selectedFilters, defaultValue) => {
4434
- return ((!isNil(selectedFilters?.[filterName]?.value) &&
4435
- Array.isArray(defaultValue) &&
4436
- !Array.isArray(selectedFilters[filterName].value)
4437
- ? [selectedFilters[filterName].value]
4438
- : selectedFilters?.[filterName]?.value) ?? defaultValue);
4439
- };
4345
+ && > * {
4346
+ color: ${({ $fontColor }) => $fontColor};
4347
+ }
4440
4348
 
4441
- const applyQueryFilters = ({ parameters: configParameters, filters: configFilters, selectedFilters, geometry, attributes, layerInfo, dataSources, projectDataSources, }) => {
4442
- if (!configParameters) {
4443
- return {};
4444
- }
4445
- return Object.keys(configParameters).reduce((result, key) => {
4446
- if (typeof configParameters[key] === "string" && configParameters[key].startsWith(PROVIDER_PREFIX)) {
4447
- const raw = configParameters[key].slice(PROVIDER_PREFIX.length);
4448
- const [provider, layerName, fieldName] = raw.split(":");
4449
- if (provider === ProviderPrefix.Card && fieldName && layerInfo.name === layerName && attributes) {
4450
- const attribute = attributes.find(({ attributeName }) => attributeName === fieldName);
4451
- const cardValue = attribute?.value ?? null;
4452
- if (isNil(cardValue))
4453
- return result;
4454
- return { ...result, [key]: cardValue };
4455
- }
4456
- if (provider === ProviderPrefix.Left && layerName && fieldName && projectDataSources?.length) {
4457
- const dataSource = projectDataSources.find(({ layerName: name }) => name === layerName);
4458
- const leftValue = dataSource?.features?.[0]?.properties?.[fieldName] ?? null;
4459
- if (isNil(leftValue))
4460
- return result;
4461
- return { ...result, [key]: leftValue };
4462
- }
4463
- return result;
4464
- }
4465
- if (typeof configParameters[key] === "string" && configParameters[key].includes("{") && attributes?.length) {
4466
- const exactAttr = attributes.find(({ attributeName }) => configParameters[key] === `{${attributeName}}`);
4467
- if (exactAttr) {
4468
- return { ...result, [key]: exactAttr.value ?? "" };
4469
- }
4470
- let interpolated = configParameters[key];
4471
- attributes.forEach(({ attributeName, value: attrValue }) => {
4472
- interpolated = interpolated.replace(new RegExp(`\\{${attributeName}\\}`, "g"), attrValue?.toString() ?? "");
4473
- });
4474
- return { ...result, [key]: interpolated };
4475
- }
4476
- if (typeof configParameters[key] !== "string" || !configParameters[key].startsWith("%")) {
4477
- return {
4478
- ...result,
4479
- [key]: configParameters[key],
4480
- };
4481
- }
4482
- const filterFullName = configParameters[key].replace("%", "");
4483
- const [filterName, filterProp] = filterFullName.includes(".") ? filterFullName.split(".") : [filterFullName, null];
4484
- const { defaultValue, relatedDataSource, attributeAlias } = getConfigFilter(filterName, configFilters) || {};
4485
- if (filterName === "geometry" && geometry && !geometry.includes("()") && geometry.endsWith(")")) {
4486
- return {
4487
- ...result,
4488
- [key]: geometry,
4489
- };
4490
- }
4491
- if (configParameters[key].endsWith(".max")) {
4492
- return {
4493
- ...result,
4494
- [key]: selectedFilters?.[filterName]?.max ?? (Array.isArray(defaultValue) ? defaultValue[1] : defaultValue),
4495
- };
4496
- }
4497
- if (configParameters[key].endsWith(".min")) {
4498
- return {
4499
- ...result,
4500
- [key]: selectedFilters?.[filterName]?.min ?? (Array.isArray(defaultValue) ? defaultValue[0] : defaultValue),
4501
- };
4502
- }
4503
- if (configParameters[key].includes(".")) {
4504
- return {
4505
- ...result,
4506
- [key]: getDataSourceFilterValue({
4507
- filterName,
4508
- filterProp,
4509
- selectedFilters,
4510
- attributeAlias,
4511
- dataSource: getDataSource(relatedDataSource, dataSources),
4512
- }) ?? defaultValue,
4513
- };
4514
- }
4515
- const value = getSelectedFilterValue(filterName, selectedFilters, defaultValue);
4516
- if (isNil(value)) {
4517
- return result;
4518
- }
4519
- return {
4520
- ...result,
4521
- [key]: value,
4522
- };
4523
- }, {});
4524
- };
4349
+ && span[kind]:after {
4350
+ color: ${({ $fontColor }) => $fontColor};
4351
+ }
4352
+ `;
4353
+ const DashboardChip$1 = styled(Chip) `
4354
+ margin: 0 0.25rem 0.25rem 0;
4355
+ background: ${({ $isDefault, $bgColor, theme: { palette } }) => $isDefault ? palette.element : $bgColor || palette.primary};
4356
+ border-radius: ${({ $radius, theme: { borderRadius } }) => $radius || borderRadius.medium};
4357
+ white-space: nowrap;
4358
+ font-size: ${({ $fontSize }) => $fontSize || "0.875rem"};
4359
+ color: ${({ theme: { palette } }) => palette.iconContrast};
4525
4360
 
4526
- const checkEqualOrIncludes = (arrayOrSingle, value) => arrayOrSingle && Array.isArray(arrayOrSingle) ? arrayOrSingle.includes(value) : arrayOrSingle === value;
4361
+ > * {
4362
+ font-size: ${({ $fontSize }) => $fontSize || "0.875rem"};
4363
+ }
4527
4364
 
4528
- const checkIsLoading = (dataSources, config, filters) => config?.children?.some(child => {
4529
- const filter = filters?.find(({ name }) => name === child.options?.filterName);
4530
- return (!!filter && !!child.options?.filterName && !dataSources?.some(({ name }) => name === filter.relatedDataSource));
4531
- });
4365
+ span[kind] {
4366
+ height: 0.875rem;
4532
4367
 
4533
- const createConfigLayer = (layerName) => ({
4534
- name: layerName,
4535
- query: "",
4536
- parameters: {},
4537
- opacity: 1,
4538
- selectable: false,
4539
- filterZoomTo: false,
4540
- isVisible: true,
4541
- });
4368
+ :after {
4369
+ font-size: 0.875rem;
4370
+ }
4371
+ }
4542
4372
 
4543
- const createNewPageId = (pages) => {
4544
- if (!pages?.length)
4545
- return 1;
4546
- const maxPageId = pages.reduce((maxId, page) => {
4547
- const pageId = parseInt(page.id.replace(CONFIG_PAGE_ID, ""), 10);
4548
- return Math.max(maxId, pageId);
4549
- }, 0);
4550
- return maxPageId + 1;
4551
- };
4373
+ button {
4374
+ width: auto;
4375
+ padding: 0 0.5rem;
4376
+ }
4552
4377
 
4553
- const createConfigPage = (props) => {
4554
- const { title, defaultTitle, pages, baseMapName, position, resolution /* , srid*/ } = props || {};
4555
- const pageId = createNewPageId(pages);
4556
- return {
4557
- id: `${CONFIG_PAGE_ID}${pageId}`,
4558
- templateName: ContainerTemplate.ContainersGroup,
4559
- children: [],
4560
- layers: [],
4561
- dataSources: [],
4562
- filters: [],
4563
- tasks: [],
4564
- style: {},
4565
- options: {
4566
- title: title || [defaultTitle, pageId].filter(Boolean).join(" "),
4567
- position: position || [DEFAULT_LNG, DEFAULT_LAT],
4568
- resolution: resolution || DEFAULT_ZOOM,
4569
- baseMapName: baseMapName || DEFAULT_BASE_MAP,
4570
- baseMapSettings: {},
4571
- expandedLayers: true,
4572
- // srid: srid || null,
4573
- },
4574
- };
4575
- };
4378
+ ${({ $isDefault }) => $isDefault && DefaultChipColorMixin}
4379
+ ${({ $fontColor, $isDefault }) => !!$fontColor && !$isDefault && CustomChipColorMixin}
4380
+ `;
4576
4381
 
4577
- const getAttributesConfiguration = (layer) => {
4578
- const layerAttributeConfiguration = layer?.configuration?.attributesConfiguration ?? {};
4579
- const { geometryAttribute, idAttribute } = layerAttributeConfiguration;
4580
- const emptyLayerDefinition = {
4581
- attributes: [],
4582
- geometryAttribute: geometryAttribute ?? GEOMETRY_ATTRIBUTE,
4583
- idAttribute: idAttribute ?? DEFAULT_ID_ATTRIBUTE_NAME,
4584
- titleAttribute: "",
4585
- };
4586
- if (!isLayerService(layer)) {
4587
- return emptyLayerDefinition;
4588
- }
4589
- return {
4590
- ...emptyLayerDefinition,
4591
- ...layerAttributeConfiguration,
4592
- attributes: layerAttributeConfiguration?.attributes ||
4593
- emptyLayerDefinition.attributes,
4594
- };
4595
- };
4382
+ const LayerGroupContainer = styled(Flex) `
4383
+ display: flex;
4384
+ justify-content: center;
4385
+ position: relative;
4386
+ flex-direction: column;
4387
+ padding: 0 0.25rem 0 1rem;
4388
+ box-sizing: border-box;
4389
+ transition: opacity ${transition.hover}, background-color ${transition.hover};
4390
+ font-family: "NunitoSans", sans-serif;
4391
+ `;
4392
+ const LayerGroupMain = styled(Flex) `
4393
+ flex-direction: row;
4394
+ flex-wrap: nowrap;
4395
+ align-items: center;
4396
+ justify-content: space-between;
4397
+ width: 100%;
4596
4398
 
4597
- const formatChartRelatedValue = (t, value, layerInfo, relatedAttributes) => {
4598
- const layerDefinition = getAttributesConfiguration(layerInfo);
4599
- const relatedAxis = relatedAttributes.find(({ chartAxis }) => chartAxis === "y");
4600
- const attribute = layerDefinition.attributes[relatedAxis.attributeName];
4601
- return attribute ? formatAttributeValue({ t, type: attribute.type, value, stringFormat: attribute.stringFormat }) : value;
4602
- };
4399
+ ${Icon} {
4400
+ width: 2rem;
4401
+ min-width: 2rem;
4402
+ height: 2rem;
4403
+ display: inline-flex;
4404
+ align-items: center;
4405
+ justify-content: center;
4406
+ margin-right: 0.75rem;
4407
+ }
4603
4408
 
4604
- const isEmptyValue = (value) => value === "" || value === null || value === undefined;
4605
-
4606
- const checkIsDateFormat = (value) => value.startsWith("#'") && value.endsWith("'");
4607
- const checkIfNeedQuotes = (value, attributeType) => {
4608
- return attributeType
4609
- ? !NUMERIC_ATTRIBUTE_TYPES.includes(attributeType)
4610
- : typeof value === "number"
4611
- ? false
4612
- : typeof value === "string" && !isNumeric(value) && !checkIsDateFormat(value);
4613
- };
4614
- const formatConditionValue = ({ value, attributeType, defaultValue, checkQuotes = true, isSetParams = false, }) => {
4615
- if (isEmptyValue(value))
4616
- return "";
4617
- const formattedValue = Array.isArray(defaultValue) && !Array.isArray(value) ? [value] : value;
4618
- const isArray = Array.isArray(formattedValue);
4619
- let stringValue = formattedValue.toString();
4620
- if (isArray) {
4621
- return formattedValue.length && !formattedValue.every(item => !item)
4622
- ? `[${formattedValue
4623
- .map(item => (checkQuotes && checkIfNeedQuotes(item, attributeType) ? `'${item}'` : item))
4624
- .join(",")}]`
4625
- : "";
4626
- }
4627
- if (isSetParams && checkIsDateFormat(stringValue)) {
4628
- stringValue = stringValue.slice(2, -1);
4629
- }
4630
- return checkQuotes && checkIfNeedQuotes(stringValue, attributeType) ? `'${stringValue}'` : stringValue;
4631
- };
4632
-
4633
- const applyFiltersToCondition = ({ condition, name, defaultValue, filters, isSingle, isSetParams, }) => {
4634
- const hasFilter = filters[name] !== undefined && !!filters[name].value?.toString().length;
4635
- const min = formatConditionValue({
4636
- value: hasFilter ? filters[name].min : null,
4637
- checkQuotes: !isSingle,
4638
- isSetParams,
4639
- });
4640
- const max = formatConditionValue({
4641
- value: hasFilter ? filters[name].max : null,
4642
- checkQuotes: !isSingle,
4643
- isSetParams,
4644
- });
4645
- const value = formatConditionValue({
4646
- value: hasFilter ? filters[name].value : filters[name] === undefined ? defaultValue : "",
4647
- defaultValue,
4648
- checkQuotes: !isSingle,
4649
- isSetParams,
4650
- });
4651
- const filterName = `${FILTER_PREFIX}${name}`;
4652
- const hasMin = min !== "" && min !== null && min !== undefined;
4653
- const hasMax = max !== "" && max !== null && max !== undefined;
4654
- let result = condition;
4655
- if (hasMin || hasMax) {
4656
- if (hasMin) {
4657
- result = result.replace(new RegExp(`${filterName}\\.min`), min);
4658
- }
4659
- if (hasMax) {
4660
- result = result.replace(new RegExp(`${filterName}\\.max`), max);
4661
- }
4662
- }
4663
- else if (value) {
4664
- result = result.replace(new RegExp(filterName), value);
4665
- }
4666
- return isSingle && isNumeric(result) ? Number(result) : result;
4667
- };
4668
- const applyVarsToCondition = ({ section, configFilters, filters, attributes, layerParams, eqlParameters, geometry, isSetParams, }) => {
4669
- if (!section?.length)
4670
- return [];
4671
- const isSingle = typeof section === "string";
4672
- const result = isSingle ? [section] : [...section];
4673
- result.forEach((_, index) => {
4674
- if (geometry && !geometry.includes("()") && geometry.endsWith(")")) {
4675
- result[index] = result[index].replace(new RegExp("%geometry"), `'${geometry}'`);
4676
- }
4677
- if (configFilters?.length) {
4678
- configFilters.forEach(filter => {
4679
- result[index] = applyFiltersToCondition({
4680
- filters,
4681
- condition: result[index],
4682
- name: filter.name,
4683
- defaultValue: filter.defaultValue,
4684
- isSetParams,
4685
- isSingle: isSingle && !Array.isArray(filter.defaultValue),
4686
- }).toString();
4687
- });
4688
- }
4689
- if (attributes?.length) {
4690
- attributes.forEach(({ attributeName, value, type: attributeType }) => {
4691
- result[index] = result[index].replace(new RegExp(`{${attributeName}}`), formatConditionValue({ value: value?.toString(), attributeType, checkQuotes: !isSingle }));
4692
- });
4693
- }
4694
- if (eqlParameters && layerParams) {
4695
- Object.keys(eqlParameters).forEach(param => {
4696
- result[index] = result[index].replace(new RegExp(`\\$\\(${param}=`), "***");
4697
- result[index] = result[index].replace(new RegExp(param), formatConditionValue({ value: layerParams[param], checkQuotes: !isSingle }));
4698
- result[index] = result[index].replace(new RegExp("\\*\\*\\*"), `$(${param}=`);
4699
- });
4700
- }
4701
- });
4702
- return isSingle ? result?.[0] : result;
4703
- };
4704
- const formatSingleCondition = (condition, { configFilters, filters, attributes, eqlParameters, layerParams, geometry }) => {
4705
- const setParams = condition.match(new RegExp("\\$\\([^)]+\\)", "g"));
4706
- const setParamsSection = applyVarsToCondition({
4707
- section: setParams,
4708
- configFilters,
4709
- filters,
4710
- attributes,
4711
- eqlParameters,
4712
- layerParams,
4713
- geometry,
4714
- isSetParams: true,
4715
- });
4716
- const splitter = " AND ";
4717
- const setParamsLength = setParams?.join("").length || 0;
4718
- const conditionSection = applyVarsToCondition({
4719
- section: condition.substring(setParamsLength).split(splitter),
4720
- configFilters,
4721
- filters,
4722
- attributes,
4723
- eqlParameters,
4724
- layerParams,
4725
- geometry,
4726
- });
4727
- return setParamsSection?.length && conditionSection.length
4728
- ? [setParamsSection.join(""), conditionSection.join(splitter)].join(" ")
4729
- : setParamsSection?.length
4730
- ? setParamsSection.join("")
4731
- : conditionSection.join(splitter);
4732
- };
4733
- const formatDataSourceCondition = ({ condition, ...rest }) => {
4734
- if (Array.isArray(condition)) {
4735
- return condition.map(item => formatSingleCondition(item, rest));
4736
- }
4737
- if (!condition) {
4738
- return "";
4739
- }
4740
- return formatSingleCondition(condition, rest);
4741
- };
4742
-
4743
- const DashboardChipsContainer = styled(Flex) `
4744
- flex-wrap: wrap;
4745
- `;
4746
- const DefaultChipColorMixin = css `
4747
- && {
4748
- color: ${({ theme: { palette } }) => palette.textPrimary};
4749
- }
4750
-
4751
- && > * {
4752
- color: ${({ theme: { palette } }) => palette.textPrimary};
4753
- }
4754
-
4755
- && span[kind]:after {
4756
- color: ${({ theme: { palette } }) => palette.icon};
4757
- }
4758
- `;
4759
- const CustomChipColorMixin = css `
4760
- && {
4761
- color: ${({ $fontColor }) => $fontColor};
4762
- }
4763
-
4764
- && > * {
4765
- color: ${({ $fontColor }) => $fontColor};
4766
- }
4767
-
4768
- && span[kind]:after {
4769
- color: ${({ $fontColor }) => $fontColor};
4770
- }
4771
- `;
4772
- const DashboardChip$1 = styled(Chip) `
4773
- margin: 0 0.25rem 0.25rem 0;
4774
- background: ${({ $isDefault, $bgColor, theme: { palette } }) => $isDefault ? palette.element : $bgColor || palette.primary};
4775
- border-radius: ${({ $radius, theme: { borderRadius } }) => $radius || borderRadius.medium};
4776
- white-space: nowrap;
4777
- font-size: ${({ $fontSize }) => $fontSize || "0.875rem"};
4778
- color: ${({ theme: { palette } }) => palette.iconContrast};
4779
-
4780
- > * {
4781
- font-size: ${({ $fontSize }) => $fontSize || "0.875rem"};
4782
- }
4783
-
4784
- span[kind] {
4785
- height: 0.875rem;
4786
-
4787
- :after {
4788
- font-size: 0.875rem;
4789
- }
4790
- }
4791
-
4792
- button {
4793
- width: auto;
4794
- padding: 0 0.5rem;
4795
- }
4796
-
4797
- ${({ $isDefault }) => $isDefault && DefaultChipColorMixin}
4798
- ${({ $fontColor, $isDefault }) => !!$fontColor && !$isDefault && CustomChipColorMixin}
4799
- `;
4800
-
4801
- const LayerGroupContainer = styled(Flex) `
4802
- display: flex;
4803
- justify-content: center;
4804
- position: relative;
4805
- flex-direction: column;
4806
- padding: 0 0.25rem 0 1rem;
4807
- box-sizing: border-box;
4808
- transition: opacity ${transition.hover}, background-color ${transition.hover};
4809
- font-family: "NunitoSans", sans-serif;
4810
- `;
4811
- const LayerGroupMain = styled(Flex) `
4812
- flex-direction: row;
4813
- flex-wrap: nowrap;
4814
- align-items: center;
4815
- justify-content: space-between;
4816
- width: 100%;
4817
-
4818
- ${Icon} {
4819
- width: 2rem;
4820
- min-width: 2rem;
4821
- height: 2rem;
4822
- display: inline-flex;
4823
- align-items: center;
4824
- justify-content: center;
4825
- margin-right: 0.75rem;
4826
- }
4827
-
4828
- ${Description} {
4829
- display: flex;
4830
- align-items: center;
4831
- flex-grow: 1;
4832
- width: 100%;
4833
- margin-right: 0.25rem;
4834
- color: ${({ theme }) => theme.palette.textPrimary};
4835
- }
4409
+ ${Description} {
4410
+ display: flex;
4411
+ align-items: center;
4412
+ flex-grow: 1;
4413
+ width: 100%;
4414
+ margin-right: 0.25rem;
4415
+ color: ${({ theme }) => theme.palette.textPrimary};
4416
+ }
4836
4417
 
4837
4418
  button {
4838
4419
  width: 2.25rem;
@@ -4969,41 +4550,193 @@ const customStyles = [
4969
4550
  },
4970
4551
  ];
4971
4552
 
4972
- const useMapContext = () => {
4973
- return useContext(MapContext);
4974
- };
4553
+ const DashboardContext = createContext({});
4554
+ const DashboardProvider = memo(({ children, ...props }) => {
4555
+ return jsx(DashboardContext.Provider, { value: props, children: children });
4556
+ });
4975
4557
 
4976
- const draw = new MapboxDraw({
4977
- displayControlsDefault: false,
4978
- styles: customStyles,
4979
- modes: customModes,
4980
- defaultMode: "static",
4981
- controls: {
4982
- trash: true,
4983
- },
4558
+ const FeatureCardContext = createContext({});
4559
+ const FeatureCardProvider = memo(({ children, ...props }) => {
4560
+ return jsx(FeatureCardContext.Provider, { value: props, children: children });
4984
4561
  });
4985
- const useMapDraw = (triggerDeps = []) => {
4986
- const { map, draw: drawContext, loaded, basemapName } = useMapContext();
4987
- useEffect(() => {
4988
- if (!loaded || !map.current) {
4989
- return;
4990
- }
4991
- drawContext.current = draw;
4992
- map.current.addControl(drawContext.current);
4993
- }, [loaded]); // eslint-disable-line
4994
- useEffect(() => {
4995
- if (map.current && map.current.hasControl(drawContext.current)) {
4996
- map.current.removeControl(drawContext.current);
4997
- map.current.addControl(drawContext.current);
4998
- }
4999
- }, [basemapName, ...triggerDeps]); // eslint-disable-line
5000
- };
5001
4562
 
5002
- /**
5003
- * Определяет, является ли URL ссылкой на SVG файл.
5004
- */
5005
- const isSvgUrl = (url) => {
5006
- const lowercaseUrl = url.toLowerCase();
4563
+ const GlobalContext = createContext({});
4564
+ const GlobalProvider = memo(({ children, ...props }) => {
4565
+ return jsx(GlobalContext.Provider, { value: props, children: children });
4566
+ });
4567
+
4568
+ const MapContext = createContext({});
4569
+
4570
+ const MapProvider = ({ basemapItems, defaultBasemap, children }) => {
4571
+ const map = useRef();
4572
+ const draw = useRef();
4573
+ const [loaded, setLoaded] = useState(false);
4574
+ const [basemapName, setBasemapName] = useState(defaultBasemap);
4575
+ return (jsx(MapContext.Provider, { value: {
4576
+ map,
4577
+ draw,
4578
+ loaded,
4579
+ setLoaded,
4580
+ basemapItems,
4581
+ basemapName,
4582
+ setBasemapName,
4583
+ defaultBasemap,
4584
+ }, children: children }));
4585
+ };
4586
+
4587
+ var BaseMapTheme;
4588
+ (function (BaseMapTheme) {
4589
+ BaseMapTheme["Light"] = "light";
4590
+ BaseMapTheme["Dark"] = "dark";
4591
+ })(BaseMapTheme || (BaseMapTheme = {}));
4592
+
4593
+ const ServerNotificationsContext = createContext({});
4594
+
4595
+ const useServerNotifications = (url, initialized, apiClient) => {
4596
+ const hubConnection = useRef(null);
4597
+ const [connection, setConnection] = useState(null);
4598
+ const subscribeNotifications = useCallback(() => {
4599
+ if (!connection || connection.state !== "Connected") {
4600
+ return;
4601
+ }
4602
+ connection
4603
+ .invoke("SubscribeNotifications", [])
4604
+ .then(() => console.info("Подписка `SubscribeNotifications` оформлена"))
4605
+ .catch(err => console.info("Ошибка подписки `SubscribeNotifications`:", err));
4606
+ }, [connection]);
4607
+ useEffect(() => {
4608
+ if (!initialized) {
4609
+ return;
4610
+ }
4611
+ hubConnection.current = new HubConnectionBuilder()
4612
+ .withUrl(`${url}?clientId=${generateId()}`, {
4613
+ withCredentials: true,
4614
+ skipNegotiation: true,
4615
+ transport: HttpTransportType.WebSockets,
4616
+ accessTokenFactory: async () => {
4617
+ let accessToken = window.localStorage.getItem(STORAGE_TOKEN_KEY) || "";
4618
+ const { exp } = parseJwt(accessToken);
4619
+ const currentTime = new Date().getTime() / 1000;
4620
+ if (currentTime > exp) {
4621
+ const refreshToken = window.localStorage.getItem(STORAGE_REFRESH_TOKEN_KEY);
4622
+ if (refreshToken) {
4623
+ const refreshTokenResponse = await apiClient.account.refreshToken({
4624
+ refreshToken,
4625
+ });
4626
+ if (refreshTokenResponse) {
4627
+ accessToken = refreshTokenResponse.token;
4628
+ window.localStorage.setItem(STORAGE_TOKEN_KEY, refreshTokenResponse.token);
4629
+ window.localStorage.setItem(STORAGE_REFRESH_TOKEN_KEY, refreshTokenResponse.refreshToken);
4630
+ }
4631
+ }
4632
+ else {
4633
+ await apiClient.logout();
4634
+ }
4635
+ }
4636
+ return accessToken;
4637
+ },
4638
+ })
4639
+ .withAutomaticReconnect()
4640
+ .configureLogging(LogLevel.Information)
4641
+ .build();
4642
+ hubConnection.current
4643
+ .start()
4644
+ .then(() => console.info("Серверные нотификации подключены"))
4645
+ .catch(err => console.info("Ошибка:", err))
4646
+ .finally(() => setConnection(hubConnection.current));
4647
+ }, [initialized]); // eslint-disable-line
4648
+ useEffect(() => {
4649
+ if (!connection || connection.state !== "Connected") {
4650
+ return;
4651
+ }
4652
+ connection.onreconnecting(() => console.info("Переподключение к серверным нотификациям"));
4653
+ connection.onreconnected(subscribeNotifications);
4654
+ subscribeNotifications();
4655
+ }, [connection]);
4656
+ return connection;
4657
+ };
4658
+
4659
+ const ServerNotificationsProvider = ({ url, initialized, apiClient, children }) => {
4660
+ const connection = useServerNotifications(url, initialized, apiClient);
4661
+ const addSubscription = useCallback(async (payload) => {
4662
+ if (!connection || connection.state !== "Connected" || !payload) {
4663
+ return;
4664
+ }
4665
+ try {
4666
+ const id = await connection.invoke("AddSubscription", payload);
4667
+ console.info("Подписка добавлена, id:", id);
4668
+ return id;
4669
+ }
4670
+ catch (err) {
4671
+ console.info("Ошибка добавления подписки:", err);
4672
+ return Promise.resolve(null);
4673
+ }
4674
+ }, [connection]);
4675
+ const updateSubscription = useCallback(async (id, payload) => {
4676
+ if (!connection || connection.state !== "Connected" || !id || !payload) {
4677
+ return;
4678
+ }
4679
+ try {
4680
+ await connection.invoke("UpdateSubscription", id, payload);
4681
+ }
4682
+ catch (err) {
4683
+ console.info(`Ошибка обновления подписки ${id}:`, err);
4684
+ }
4685
+ }, [connection]);
4686
+ const unsubscribeById = useCallback(async (id) => {
4687
+ if (!connection || connection.state !== "Connected" || !id) {
4688
+ return;
4689
+ }
4690
+ try {
4691
+ await connection.invoke("Unsubscribe", [id]);
4692
+ }
4693
+ catch (err) {
4694
+ console.info(`Ошибка отписки по ${id}:`, err);
4695
+ }
4696
+ }, [connection]);
4697
+ return (jsx(ServerNotificationsContext.Provider, { value: {
4698
+ connection,
4699
+ addSubscription,
4700
+ updateSubscription,
4701
+ unsubscribeById,
4702
+ }, children: children }));
4703
+ };
4704
+
4705
+ const useMapContext = () => {
4706
+ return useContext(MapContext);
4707
+ };
4708
+
4709
+ const draw = new MapboxDraw({
4710
+ displayControlsDefault: false,
4711
+ styles: customStyles,
4712
+ modes: customModes,
4713
+ defaultMode: "static",
4714
+ controls: {
4715
+ trash: true,
4716
+ },
4717
+ });
4718
+ const useMapDraw = (triggerDeps = []) => {
4719
+ const { map, draw: drawContext, loaded, basemapName } = useMapContext();
4720
+ useEffect(() => {
4721
+ if (!loaded || !map.current) {
4722
+ return;
4723
+ }
4724
+ drawContext.current = draw;
4725
+ map.current.addControl(drawContext.current);
4726
+ }, [loaded]); // eslint-disable-line
4727
+ useEffect(() => {
4728
+ if (map.current && map.current.hasControl(drawContext.current)) {
4729
+ map.current.removeControl(drawContext.current);
4730
+ map.current.addControl(drawContext.current);
4731
+ }
4732
+ }, [basemapName, ...triggerDeps]); // eslint-disable-line
4733
+ };
4734
+
4735
+ /**
4736
+ * Определяет, является ли URL ссылкой на SVG файл.
4737
+ */
4738
+ const isSvgUrl = (url) => {
4739
+ const lowercaseUrl = url.toLowerCase();
5007
4740
  return lowercaseUrl.endsWith(".svg") || lowercaseUrl.startsWith("data:image/svg");
5008
4741
  };
5009
4742
  /**
@@ -5383,6 +5116,7 @@ const useZoomToFeatures = () => {
5383
5116
  map.current.fitBounds([minX, minY, maxX, maxY], {
5384
5117
  ...options,
5385
5118
  padding: options?.padding ?? 150,
5119
+ maxZoom: options?.maxZoom ?? SINGLE_FEATURE_FALLBACK_ZOOM,
5386
5120
  });
5387
5121
  }, [map]);
5388
5122
  };
@@ -6336,71 +6070,12 @@ const TwoColumnContainerWrapper = styled(Flex) `
6336
6070
  }
6337
6071
  `;
6338
6072
 
6339
- const useRenderContainerItem = (type, renderElement) => {
6340
- const { config, layerInfo, selectedTabId, attributes } = useWidgetContext(type);
6341
- return useCallback((elementConfig, attribute) => {
6342
- const { id, options, style, children } = elementConfig || {};
6343
- const { hideEmpty, innerTemplateStyle } = options || {};
6344
- const hasUnits = children?.some(item => item.id === "units");
6345
- const iconIndex = children?.findIndex(item => item.id === "icon");
6346
- const icon = children?.[iconIndex];
6347
- const hasIcon = !!icon;
6348
- const elementChildren = elementConfig?.children?.map(child => ({
6349
- type: "attributeValue",
6350
- ...child,
6351
- attributeName: attribute,
6352
- options: { noUnits: hasUnits, ...child.options },
6353
- }));
6354
- const attr = attribute
6355
- ? layerInfo?.configuration?.attributesConfiguration?.attributes?.find(({ attributeName }) => attributeName === attribute)
6356
- : null;
6357
- if (hasIcon) {
6358
- elementChildren[iconIndex] = {
6359
- ...elementChildren[iconIndex],
6360
- type: attr?.icon?.type?.toLowerCase(),
6361
- value: attr?.icon?.resourceId || attr?.icon?.url || attr?.icon?.iconName,
6362
- attributeName: null,
6363
- };
6364
- }
6365
- const render = attribute
6366
- ? getRenderElement({
6367
- config,
6368
- elementConfig: {
6369
- ...elementConfig,
6370
- children: elementChildren,
6371
- },
6372
- selectedTabId,
6373
- attributes,
6374
- layerInfo,
6375
- type,
6376
- })
6377
- : renderElement;
6378
- const value = render({ id: "value" });
6379
- return {
6380
- id,
6381
- value,
6382
- hideEmpty,
6383
- style: innerTemplateStyle || style,
6384
- hasIcon,
6385
- hasUnits,
6386
- render,
6387
- };
6388
- }, [config, layerInfo, selectedTabId, attributes, type, renderElement]);
6389
- };
6390
-
6391
6073
  const OneColumnContainer = memo(({ type, elementConfig, renderElement }) => {
6392
- const getRenderContainerItem = useRenderContainerItem(type, renderElement);
6393
- const { options } = elementConfig || {};
6394
- const { attributes: optionAttributes } = options || {};
6395
- const { attributes: contextAttributes } = useWidgetContext(type);
6396
- const attributesToRender = useMemo(() => {
6397
- if (!optionAttributes)
6398
- return null;
6399
- if (optionAttributes.length === 0) {
6400
- return contextAttributes?.map(({ attributeName }) => attributeName) ?? [];
6401
- }
6402
- return optionAttributes;
6403
- }, [optionAttributes, contextAttributes]);
6074
+ const { getRenderContainerItem, attributesToRender } = useContainerAttributes({
6075
+ elementConfig,
6076
+ type,
6077
+ renderElement,
6078
+ });
6404
6079
  const renderContainer = useCallback((attribute) => {
6405
6080
  const { id, value, hideEmpty, style, hasUnits, render } = getRenderContainerItem(elementConfig, attribute);
6406
6081
  if (!value && hideEmpty)
@@ -6411,18 +6086,11 @@ const OneColumnContainer = memo(({ type, elementConfig, renderElement }) => {
6411
6086
  });
6412
6087
 
6413
6088
  const TwoColumnContainer = memo(({ elementConfig, type, renderElement }) => {
6414
- const getRenderContainerItem = useRenderContainerItem(type, renderElement);
6415
- const { options } = elementConfig || {};
6416
- const { attributes: renderAttributes } = options || {};
6417
- const { attributes: contextAttributes } = useWidgetContext(type);
6418
- const attributesToRender = useMemo(() => {
6419
- if (!renderAttributes)
6420
- return null;
6421
- if (renderAttributes.length === 0) {
6422
- return contextAttributes?.map(({ attributeName }) => attributeName) ?? [];
6423
- }
6424
- return renderAttributes;
6425
- }, [renderAttributes, contextAttributes]);
6089
+ const { getRenderContainerItem, attributesToRender } = useContainerAttributes({
6090
+ elementConfig,
6091
+ type,
6092
+ renderElement,
6093
+ });
6426
6094
  const renderContainer = useCallback((attribute) => {
6427
6095
  const { id, value, hideEmpty, style, hasIcon, hasUnits, render } = getRenderContainerItem(elementConfig, attribute);
6428
6096
  if (!value && hideEmpty)
@@ -7737,14 +7405,51 @@ const EditGroupContainer = memo(({ type, elementConfig, renderElement }) => {
7737
7405
  return (jsx(Fragment$1, { children: controls.map(({ targetAttributeName }) => renderContainer(targetAttributeName)) }));
7738
7406
  });
7739
7407
 
7740
- const useEditControl = (type, elementConfig) => {
7741
- const { attributes, controls, dataSources, changeControls } = useWidgetContext(type);
7742
- const { children, options } = elementConfig || {};
7743
- const { controls: controlsOption } = options || {};
7744
- const valueElement = useMemo(() => children.find(({ id }) => id === "value"), [children]);
7745
- const control = useMemo(() => controlsOption?.find(item => item.targetAttributeName === valueElement.attributeName), [controlsOption, valueElement.attributeName]);
7746
- const attributeName = (control?.targetAttributeName ?? valueElement?.attributeName);
7747
- const value = useMemo(() => {
7408
+ const useWidgetContext = (type = WidgetType.Dashboard) => {
7409
+ const { toggleLayersVisibility, visibleLayers, projectInfo, updateProject, layerInfos, geometryFilter, dashboardLayers, setDashboardLayer, components: dashboardComponents, config: dashboardConfig, containerIds, pageIndex: projectPageIndex, selectedTabId: projectSelectedTabId, setSelectedTabId: setProjectSelectedTabId, dataSources: projectDataSources, loading: projectLoading, editMode: projectEditMode, filters: projectFilters, changeFilters: projectChangeFilters, expandContainer: projectExpandContainer, expandedContainers: projectExpandedContainers, nextPage: projectNextPage, prevPage: projectPrevPage, changePage: projectChangePage, } = useContext(DashboardContext) || {};
7410
+ const { layerInfo, attributes, feature, controls, changeControls, closeFeatureCard, config: featureConfig, pageIndex: featurePageIndex, selectedTabId: featureSelectedTabId, setSelectedTabId: setFeatureSelectedTabId, dataSources: featureDataSources, loading: featureLoading, editMode: featureEditMode, filters: featureFilters, changeFilters: featureChangeFilters, expandContainer: featureExpandContainer, expandedContainers: featureExpandedContainers, nextPage: featureNextPage, prevPage: featurePrevPage, changePage: featureChangePage, } = useContext(FeatureCardContext) || {};
7411
+ return {
7412
+ toggleLayersVisibility,
7413
+ visibleLayers,
7414
+ projectInfo,
7415
+ layerInfos,
7416
+ updateProject,
7417
+ dashboardLayers,
7418
+ setDashboardLayer,
7419
+ geometryFilter,
7420
+ layerInfo,
7421
+ attributes,
7422
+ feature,
7423
+ closeFeatureCard,
7424
+ containerIds,
7425
+ controls,
7426
+ changeControls,
7427
+ components: dashboardComponents,
7428
+ config: type === WidgetType.Dashboard ? dashboardConfig : featureConfig,
7429
+ isEditing: type === WidgetType.Dashboard ? projectEditMode : featureEditMode,
7430
+ isLoading: type === WidgetType.Dashboard ? projectLoading : featureLoading,
7431
+ pageIndex: type === WidgetType.Dashboard ? projectPageIndex || 1 : featurePageIndex || 1,
7432
+ filters: type === WidgetType.Dashboard ? projectFilters : featureFilters,
7433
+ changeFilters: type === WidgetType.Dashboard ? projectChangeFilters : featureChangeFilters,
7434
+ dataSources: type === WidgetType.Dashboard ? projectDataSources : featureDataSources,
7435
+ expandContainer: type === WidgetType.Dashboard ? projectExpandContainer : featureExpandContainer,
7436
+ expandedContainers: type === WidgetType.Dashboard ? projectExpandedContainers : featureExpandedContainers,
7437
+ selectedTabId: type === WidgetType.Dashboard ? projectSelectedTabId : featureSelectedTabId,
7438
+ setSelectedTabId: type === WidgetType.Dashboard ? setProjectSelectedTabId : setFeatureSelectedTabId,
7439
+ nextPage: type === WidgetType.Dashboard ? projectNextPage : featureNextPage,
7440
+ prevPage: type === WidgetType.Dashboard ? projectPrevPage : featurePrevPage,
7441
+ changePage: type === WidgetType.Dashboard ? projectChangePage : featureChangePage,
7442
+ };
7443
+ };
7444
+
7445
+ const useEditControl = (type, elementConfig) => {
7446
+ const { attributes, controls, dataSources, changeControls } = useWidgetContext(type);
7447
+ const { children, options } = elementConfig || {};
7448
+ const { controls: controlsOption } = options || {};
7449
+ const valueElement = useMemo(() => children.find(({ id }) => id === "value"), [children]);
7450
+ const control = useMemo(() => controlsOption?.find(item => item.targetAttributeName === valueElement.attributeName), [controlsOption, valueElement.attributeName]);
7451
+ const attributeName = (control?.targetAttributeName ?? valueElement?.attributeName);
7452
+ const value = useMemo(() => {
7748
7453
  const currentValue = controls[attributeName] === undefined
7749
7454
  ? attributes.find(({ attributeName: name }) => name === attributeName)?.value
7750
7455
  : controls[attributeName];
@@ -10771,6 +10476,307 @@ const tooltipValueFromRelatedFeatures = (t, value, relatedAttributes, layerInfo)
10771
10476
  return formatChartRelatedValue(t, value, layerInfo, relatedAttributes);
10772
10477
  };
10773
10478
 
10479
+ const useRenderContainerItem = (type, renderElement) => {
10480
+ const { config, layerInfo, selectedTabId, attributes } = useWidgetContext(type);
10481
+ return useCallback((elementConfig, attribute) => {
10482
+ const { id, options, style, children } = elementConfig || {};
10483
+ const { hideEmpty, innerTemplateStyle } = options || {};
10484
+ const hasUnits = children?.some(item => item.id === "units");
10485
+ const iconIndex = children?.findIndex(item => item.id === "icon");
10486
+ const icon = children?.[iconIndex];
10487
+ const hasIcon = !!icon;
10488
+ const elementChildren = elementConfig?.children?.map(child => ({
10489
+ type: "attributeValue",
10490
+ ...child,
10491
+ attributeName: attribute,
10492
+ options: { noUnits: hasUnits, ...child.options },
10493
+ }));
10494
+ const attr = attribute
10495
+ ? layerInfo?.configuration?.attributesConfiguration?.attributes?.find(({ attributeName }) => attributeName === attribute)
10496
+ : null;
10497
+ if (hasIcon) {
10498
+ elementChildren[iconIndex] = {
10499
+ ...elementChildren[iconIndex],
10500
+ type: attr?.icon?.type?.toLowerCase(),
10501
+ value: attr?.icon?.resourceId || attr?.icon?.url || attr?.icon?.iconName,
10502
+ attributeName: null,
10503
+ };
10504
+ }
10505
+ const render = attribute
10506
+ ? getRenderElement({
10507
+ config,
10508
+ elementConfig: {
10509
+ ...elementConfig,
10510
+ children: elementChildren,
10511
+ },
10512
+ selectedTabId,
10513
+ attributes,
10514
+ layerInfo,
10515
+ type,
10516
+ })
10517
+ : renderElement;
10518
+ const value = render({ id: "value" });
10519
+ return {
10520
+ id,
10521
+ value,
10522
+ hideEmpty,
10523
+ style: innerTemplateStyle || style,
10524
+ hasIcon,
10525
+ hasUnits,
10526
+ render,
10527
+ };
10528
+ }, [config, layerInfo, selectedTabId, attributes, type, renderElement]);
10529
+ };
10530
+
10531
+ const useContainerAttributes = ({ elementConfig, type, renderElement }) => {
10532
+ const getRenderContainerItem = useRenderContainerItem(type, renderElement);
10533
+ const { options } = elementConfig || {};
10534
+ const { attributes: optionAttributes, useProjectHiddenAttributes } = options || {};
10535
+ const { attributes: contextAttributes, layerInfo } = useWidgetContext(type);
10536
+ const [hiddenAttributes] = useLayerHiddenAttributes(layerInfo?.name ?? "");
10537
+ const attributesToRender = useMemo(() => {
10538
+ if (!optionAttributes)
10539
+ return null;
10540
+ const baseList = optionAttributes.length === 0
10541
+ ? contextAttributes?.map(({ attributeName }) => attributeName) ?? []
10542
+ : optionAttributes;
10543
+ if (!useProjectHiddenAttributes)
10544
+ return baseList;
10545
+ return baseList.filter(attribute => !hiddenAttributes.includes(attribute));
10546
+ }, [optionAttributes, contextAttributes, hiddenAttributes, useProjectHiddenAttributes]);
10547
+ return { getRenderContainerItem, attributesToRender };
10548
+ };
10549
+
10550
+ const useFetchWithAuth = (url, transform, cleanup) => {
10551
+ const [data, setData] = useState(null);
10552
+ const loadingRef = useRef(false);
10553
+ const transformRef = useRef(transform);
10554
+ const cleanupRef = useRef(cleanup);
10555
+ transformRef.current = transform;
10556
+ cleanupRef.current = cleanup;
10557
+ const fetchData = useCallback(() => {
10558
+ if (!url || loadingRef.current)
10559
+ return;
10560
+ loadingRef.current = true;
10561
+ const token = window.localStorage.getItem(STORAGE_TOKEN_KEY);
10562
+ fetch(url, {
10563
+ headers: token ? { Authorization: `Bearer ${token}` } : {},
10564
+ })
10565
+ .then(res => (res.ok ? transformRef.current(res) : null))
10566
+ .then(setData)
10567
+ .catch(() => {
10568
+ setData(null);
10569
+ })
10570
+ .finally(() => {
10571
+ loadingRef.current = false;
10572
+ });
10573
+ }, [url]);
10574
+ useEffect(() => {
10575
+ if (url) {
10576
+ fetchData();
10577
+ }
10578
+ else {
10579
+ setData(null);
10580
+ }
10581
+ }, [url]);
10582
+ useEffect(() => () => {
10583
+ if (data !== null)
10584
+ cleanupRef.current?.(data);
10585
+ }, [data]);
10586
+ return data;
10587
+ };
10588
+
10589
+ const toObjectUrl = (res) => res.blob().then(blob => URL.createObjectURL(blob));
10590
+ const useFetchImageWithAuth = (url) => useFetchWithAuth(url, toObjectUrl, URL.revokeObjectURL);
10591
+
10592
+ const useGlobalContext = () => {
10593
+ const { t, language, themeName, api, ewktGeometry } = useContext(GlobalContext) || {};
10594
+ const translate = useCallback((value, options) => {
10595
+ if (t)
10596
+ return t(value, options);
10597
+ return options?.defaultValue ?? value;
10598
+ }, [t]);
10599
+ return useMemo(() => ({
10600
+ t: translate,
10601
+ language,
10602
+ themeName,
10603
+ api,
10604
+ ewktGeometry,
10605
+ }), [language, translate, api, ewktGeometry, themeName]);
10606
+ };
10607
+
10608
+ const HEIGHT_OFFSET = 20;
10609
+ const FILL_OPACITY = 0.28;
10610
+ const lineGenerator = line()
10611
+ .x(d => d[0])
10612
+ .y(d => d[1])
10613
+ .curve(monotoneX);
10614
+ const areaGenerator = (height) => area()
10615
+ .defined(d => d !== null)
10616
+ .x(d => d[0])
10617
+ .y0(height - HEIGHT_OFFSET)
10618
+ .y1(d => d[1])
10619
+ .curve(monotoneX);
10620
+ function getLinePoints(numPoints, svgLine) {
10621
+ if (!svgLine?.getTotalLength) {
10622
+ return [];
10623
+ }
10624
+ const lineLength = svgLine.getTotalLength();
10625
+ let interval;
10626
+ if (numPoints === 1) {
10627
+ interval = 0;
10628
+ }
10629
+ else {
10630
+ interval = lineLength / (numPoints - 1);
10631
+ }
10632
+ return range(numPoints)
10633
+ .filter(d => d * interval)
10634
+ .map(d => {
10635
+ const value = d * interval;
10636
+ const { x, y } = svgLine.getPointAtLength(value);
10637
+ return [x, y];
10638
+ });
10639
+ }
10640
+ function wrap() {
10641
+ const width = 80;
10642
+ const padding = 10;
10643
+ const self = select(this);
10644
+ let textLength = self.node().getComputedTextLength();
10645
+ let text = self.text();
10646
+ while (textLength > width - 2 * padding && text.length > 0) {
10647
+ text = text.slice(0, -1);
10648
+ self.text(`${text}...`);
10649
+ textLength = self.node().getComputedTextLength();
10650
+ }
10651
+ }
10652
+ const useChartChange = ({ dataSources, chartId, width, height, relatedAttributes, defaultColor, fontColor, markers, showMarkers, }) => {
10653
+ const { t } = useGlobalContext();
10654
+ const { layerInfos } = useWidgetContext();
10655
+ const strokeColors = relatedAttributes
10656
+ .filter(({ chartAxis }) => chartAxis === "y")
10657
+ .map(({ axisColor }) => axisColor);
10658
+ const ref = useRef({
10659
+ path: null,
10660
+ area: null,
10661
+ points: [],
10662
+ });
10663
+ const onChange = useCallback((range) => {
10664
+ const { path, area, points } = ref.current;
10665
+ let filteredPoints = [...points];
10666
+ if (range) {
10667
+ const hundred = 100;
10668
+ const x1 = +width * (range[0] / hundred);
10669
+ const x2 = +width * (range[1] / hundred);
10670
+ filteredPoints = points.filter(([x]) => x >= x1 && x <= x2);
10671
+ }
10672
+ path && path.attr("d", lineGenerator(filteredPoints));
10673
+ area && area.attr("d", areaGenerator(height)(filteredPoints));
10674
+ }, [height, width]);
10675
+ const customize = useCallback(({ svg }) => {
10676
+ svg.style("overflow", "visible");
10677
+ svg
10678
+ .selectAll(`.${lineChartClassNames.lineChartXScaleGlobal} line,
10679
+ .${lineChartClassNames.lineChartYScaleGlobal} line,
10680
+ .domain`)
10681
+ .each((_, index, nodes) => {
10682
+ nodes[index].remove();
10683
+ });
10684
+ svg
10685
+ .selectAll(`.${lineChartClassNames.lineChartXScaleGlobal} .tick`)
10686
+ .each((_, index, nodes) => {
10687
+ if (!index) {
10688
+ nodes[index].style.textAnchor = "start";
10689
+ }
10690
+ if (index === nodes.length - 1) {
10691
+ nodes[index].style.textAnchor = "end";
10692
+ }
10693
+ if (markers) {
10694
+ nodes[index].remove();
10695
+ }
10696
+ if (showMarkers) {
10697
+ if (index % showMarkers !== 0) {
10698
+ nodes[index].remove();
10699
+ }
10700
+ }
10701
+ else {
10702
+ if (index && index < nodes.length - 1) {
10703
+ nodes[index].remove();
10704
+ }
10705
+ }
10706
+ });
10707
+ svg
10708
+ .selectAll(`.${lineChartClassNames.lineChartXScaleGlobal} .tick text`)
10709
+ .attr("y", 16);
10710
+ svg
10711
+ .selectAll(`.${lineChartClassNames.lineChartYScaleGlobal} .tick text`)
10712
+ .text(item => {
10713
+ if (!item)
10714
+ return 0;
10715
+ const dataSource = dataSources?.find(({ name }) => name === relatedAttributes[0].dataSourceName);
10716
+ const layerInfo = dataSource
10717
+ ? layerInfos.find(({ name }) => name === dataSource.layerName)
10718
+ : null;
10719
+ const attribute = layerInfo?.configuration?.attributesConfiguration?.attributes[relatedAttributes[0].attributeName];
10720
+ return attribute
10721
+ ? formatAttributeValue({
10722
+ t,
10723
+ type: attribute.type,
10724
+ value: item,
10725
+ stringFormat: attribute.stringFormat,
10726
+ noUnits: true,
10727
+ })
10728
+ : item;
10729
+ })
10730
+ .each(wrap);
10731
+ svg.selectAll(".tick text").attr("style", `color: ${fontColor}`);
10732
+ const global = svg.select(`.${lineChartClassNames.lineChartLinesGlobal}`);
10733
+ const lineChartLines = svg.selectAll(`.${lineChartClassNames.lineChartLine}`);
10734
+ const defs = [];
10735
+ lineChartLines.each((_, index, nodes) => {
10736
+ const lineChartLine = nodes[index];
10737
+ const gradientId = uniqueId(`${chartId}-gradient-`);
10738
+ const color = strokeColors[index] || defaultColor;
10739
+ const newPath = global
10740
+ .append("path")
10741
+ .attr("stroke", color)
10742
+ .attr("stroke-width", "0")
10743
+ .attr("class", lineChartClassNames.lineChartLine);
10744
+ const points = getLinePoints(+width, lineChartLine);
10745
+ const area = global
10746
+ .append("path")
10747
+ .attr("fill", `url(#${gradientId})`)
10748
+ .attr("stroke-width", "0")
10749
+ .attr("fill-opacity", FILL_OPACITY);
10750
+ defs.push(`
10751
+ <linearGradient id="${gradientId}" x1="0" y1="0" x2="0" y2="1">
10752
+ <stop offset="0" stop-color="${color}" stop-opacity="1" />
10753
+ <stop offset="1" stop-color="${color}" stop-opacity="0" />
10754
+ </linearGradient>
10755
+ `);
10756
+ ref.current = {
10757
+ path: newPath,
10758
+ area,
10759
+ points,
10760
+ };
10761
+ onChange();
10762
+ });
10763
+ svg.append("defs").html(() => defs.join(""));
10764
+ }, [
10765
+ fontColor,
10766
+ dataSources,
10767
+ layerInfos,
10768
+ relatedAttributes,
10769
+ chartId,
10770
+ strokeColors,
10771
+ defaultColor,
10772
+ width,
10773
+ onChange,
10774
+ showMarkers,
10775
+ markers,
10776
+ ]);
10777
+ return [customize, onChange];
10778
+ };
10779
+
10774
10780
  const useWidgetConfig = (type = WidgetType.Dashboard) => {
10775
10781
  const { config: configProp, containerIds, projectInfo, layerInfo, isEditing } = useWidgetContext(type);
10776
10782
  const config = useMemo(() => {
@@ -12479,5 +12485,5 @@ const Map$1 = ({ zIndex, lowerSiblings, upperSiblings, onError, children, ...res
12479
12485
  }, children: children }), upperSiblings] }));
12480
12486
  };
12481
12487
 
12482
- export { AddFeatureButton, AddFeatureContainer, AlertIconContainer, AttributeGalleryContainer, AttributeLabel, BASE_CONTAINER_STYLE, BaseMapTheme, CONFIG_PAGES_ID, CONFIG_PAGE_ID, CameraContainer, Chart, ChartContainer, ChartLegend, ChartLoading, Container, ContainerChildren, ContainerLoading, ContainerTemplate, ContainerWrapper, ContainersGroupContainer, DEFAULT_ATTRIBUTE_NAME, DEFAULT_BARCHART_RADIUS, DEFAULT_BASE_MAP, DEFAULT_CHART_ANGLE, DEFAULT_CHART_HEIGHT, DEFAULT_CHART_WIDTH, DEFAULT_CIRCLE_PAINT, DEFAULT_DASHBOARD_CONFIG, DEFAULT_DATA_SOURCE_LIMIT, DEFAULT_DROPDOWN_WIDTH, DEFAULT_FILL_EXTRUSION_PAINT, DEFAULT_FILL_PAINT, DEFAULT_FILTER_PADDING, DEFAULT_ID_ATTRIBUTE_NAME, DEFAULT_LAT, DEFAULT_LINE_PAINT, DEFAULT_LNG, DEFAULT_PAGES_CONFIG, DEFAULT_PIECHART_RADIUS, DEFAULT_ZOOM, Dashboard, DashboardCheckbox, DashboardChip, DashboardContent, DashboardContext, DashboardDefaultHeader, DashboardHeader, DashboardLoading, DashboardPlaceholder, DashboardPlaceholderWrap, DashboardProvider, DashboardWrapper, DataSourceContainer, DataSourceError, DataSourceErrorContainer, DataSourceInnerContainer, DataSourceProgressContainer, DateFormat, DefaultAttributesContainer, DefaultHeaderContainer, DefaultHeaderWrapper, DividerContainer, EditGeometryType, ElementButton, ElementCamera, ElementChart, ElementChips, ElementControl, ElementIcon, ElementImage, ElementLegend, ElementLink, ElementMarkdown, ElementSlideshow, ElementSvg, ElementTooltip, ElementValueWrapper, ExpandableTitle, FEATURE_CARD_DEFAULT_COLORS, FEATURE_CARD_OTHER_COLOR, FILTERED_VALUE_OPACITY, FILTER_PREFIX, FeatureCardButtons, FeatureCardContext, FeatureCardDefaultHeader, FeatureCardGradientHeader, FeatureCardHeader, FeatureCardIconHeader, FeatureCardProvider, FeatureCardSlideshowHeader, FeatureCardTitle, FeatureControls, FeatureTitleContainer, FiltersContainer, GEOMETRY_ATTRIBUTE, GlobalContext, GlobalProvider, Header, HeaderContainer, HeaderFrontView, HeaderTemplate, HeaderTitleContainer, HiddenTitleItems, IconContainer, ImageContainer, LEFT_PANEL_HEADER_HEIGHT, Layer, LayerDescription, LayerGroup, LayerGroupList, LayerIcon, LayerIconContainer, LayerListContainer, LayerTree, LayersContainer, LayersListWrapper, LinearProgressContainer, LogTerminal, LogoContainer, MAX_CHART_WIDTH, Map$1 as Map, MapContext, MapProvider, NO_CONTENT_VALUE, NUMERIC_ATTRIBUTE_TYPES, NoLiveSnapshotContainer, OneColumnContainer, POLL_SUBTASK_INTERVAL_MS, POLL_SUBTASK_TIMEOUT_MS, PROVIDER_PREFIX, PageNavigator, PageTitle, PageTitleContainer, PagesContainer, Pagination, PresentationHeader, PresentationHeaderButtons, PresentationHeaderTools, PresentationPanelContainer, PresentationPanelWrapper, PresentationWrapper, ProgressContainer, ProviderPrefix, RoundedBackgroundContainer, SERVER_NOTIFICATION_EVENT, STACK_BAR_TOTAL_HEIGHT, ScalingFactor, ServerNotificationsContext, ServerNotificationsProvider, SlideshowContainer, SmallPreviewContainer$1 as SmallPreviewContainer, SmallPreviewControl, SmallPreviewCounter, SmallPreviewImages, SmallPreviewLeft, SmallPreviewRight, StackBar, SvgImage, TIME_ZONE_FORMAT, TabsContainer, TextTrim, ThemeName, TitleContainer, TopContainer, TopContainerButtons, TwoColumnContainer, UploadContainer, WidgetType, addDataSource, addDataSources, adjustColor, applyFiltersToCondition, applyQueryFilters, applyVarsToCondition, checkEqualOrIncludes, checkIsLoading, convertSpToTurfFeature, createConfigLayer, createConfigPage, createNewPageId, createTreeNode, dateOptions, debounce, decimalOpacityToHex, eqlParametersToPayload, findAttributeInExpression, formatArea, formatAttributeValue, formatChartRelatedValue, formatConditionValue, formatDataSourceCondition, formatDate$1 as formatDate, formatElementValue, formatLength, formatNumber, formatPolygonMeasure, getActualExtrusionHeight, getAttributeByName, getAttributeValue, getAttributesConfiguration, getChartAxes, getChartFilterName, getChartMarkers, getConfigFilter, getContainerComponent, getDashboardHeader, getDataFromAttributes, getDataFromRelatedFeatures, getDataSource, getDataSourceFilterValue, getDate, getDefaultConfig, getElementValue, getFeatureAttributes, getFeatureCardHeader, getFilterComponent, getFilterSelectedItems, getFilterValue, getFormattedAttributes, getGradientColors, getLayerInfo, getLayerInfoFromDataSources, getPagesFromConfig, getPagesFromProjectInfo, getProxyService, getRelatedAttribute, getRenderElement, getResourceUrl, getRootElementId, getSelectedFilterValue, getSlideshowImages, getSvgUrl, getTemplateNameFromAttribute, getTotalFromAttributes, getTotalFromRelatedFeatures, hexToRgba, isCompositeLayerConfiguration, isEmptyElementValue, isEmptyValue, isHiddenEmptyValue, isLayerService, isNotValidSelectedTab, isNumeric, isObject, isProxyService, isVisibleContainer, metersPerPixel, numberOptions, parseClientStyle, parseIconNames, parseIconNamesFromClientStyle, pieChartTooltipFromAttributes, pieChartTooltipFromRelatedFeatures, pointOptions, removeDataSource, rgbToHex, roundTotalSum, sliceShownOtherItems, timeOptions, tooltipNameFromAttributes, tooltipValueFromAttributes, tooltipValueFromRelatedFeatures, transparentizeColor, treeNodesToProjectItems, updateDataSource, useAppHeight, useAutoCompleteControl, useChartChange, useChartData, useCurrentPageLayers, useCustomFeatureSelect, useDashboardHeader, useDataSources, useDebouncedCallback, useDiffPage, useExpandableContainers, useExportPdf, useFetchImageWithAuth, useFetchWithAuth, useGetConfigLayer, useGlobalContext, useHeaderRender, useHideIfEmptyDataSource, useIconsFromLayers, useLayerHiddenAttributes, useLayerParams, useMapContext, useMapDraw, useMapImages, useMaxZoomTo, useProjectDashboardInit, usePythonSandbox, usePythonTask, useRedrawLayer, useRelatedDataSourceAttributes, useRenderElement, useServerNotificationsContext, useShownOtherItems, useToggle, useUpdateDataSource, useVisibleProjectItems, useWidgetConfig, useWidgetContext, useWidgetFilters, useWidgetPage, useWindowResize, useZoomToFeatures, useZoomToPoint };
12488
+ export { AddFeatureButton, AddFeatureContainer, AlertIconContainer, AttributeGalleryContainer, AttributeLabel, BASE_CONTAINER_STYLE, BaseMapTheme, CONFIG_PAGES_ID, CONFIG_PAGE_ID, CameraContainer, Chart, ChartContainer, ChartLegend, ChartLoading, Container, ContainerChildren, ContainerLoading, ContainerTemplate, ContainerWrapper, ContainersGroupContainer, DEFAULT_ATTRIBUTE_NAME, DEFAULT_BARCHART_RADIUS, DEFAULT_BASE_MAP, DEFAULT_CHART_ANGLE, DEFAULT_CHART_HEIGHT, DEFAULT_CHART_WIDTH, DEFAULT_CIRCLE_PAINT, DEFAULT_DASHBOARD_CONFIG, DEFAULT_DATA_SOURCE_LIMIT, DEFAULT_DROPDOWN_WIDTH, DEFAULT_FILL_EXTRUSION_PAINT, DEFAULT_FILL_PAINT, DEFAULT_FILTER_PADDING, DEFAULT_ID_ATTRIBUTE_NAME, DEFAULT_LAT, DEFAULT_LINE_PAINT, DEFAULT_LNG, DEFAULT_PAGES_CONFIG, DEFAULT_PIECHART_RADIUS, DEFAULT_ZOOM, Dashboard, DashboardCheckbox, DashboardChip, DashboardContent, DashboardContext, DashboardDefaultHeader, DashboardHeader, DashboardLoading, DashboardPlaceholder, DashboardPlaceholderWrap, DashboardProvider, DashboardWrapper, DataSourceContainer, DataSourceError, DataSourceErrorContainer, DataSourceInnerContainer, DataSourceProgressContainer, DateFormat, DefaultAttributesContainer, DefaultHeaderContainer, DefaultHeaderWrapper, DividerContainer, EditGeometryType, ElementButton, ElementCamera, ElementChart, ElementChips, ElementControl, ElementIcon, ElementImage, ElementLegend, ElementLink, ElementMarkdown, ElementSlideshow, ElementSvg, ElementTooltip, ElementValueWrapper, ExpandableTitle, FEATURE_CARD_DEFAULT_COLORS, FEATURE_CARD_OTHER_COLOR, FILTERED_VALUE_OPACITY, FILTER_PREFIX, FeatureCardButtons, FeatureCardContext, FeatureCardDefaultHeader, FeatureCardGradientHeader, FeatureCardHeader, FeatureCardIconHeader, FeatureCardProvider, FeatureCardSlideshowHeader, FeatureCardTitle, FeatureControls, FeatureTitleContainer, FiltersContainer, GEOMETRY_ATTRIBUTE, GlobalContext, GlobalProvider, Header, HeaderContainer, HeaderFrontView, HeaderTemplate, HeaderTitleContainer, HiddenTitleItems, IconContainer, ImageContainer, LEFT_PANEL_HEADER_HEIGHT, Layer, LayerDescription, LayerGroup, LayerGroupList, LayerIcon, LayerIconContainer, LayerListContainer, LayerTree, LayersContainer, LayersListWrapper, LinearProgressContainer, LogTerminal, LogoContainer, MAX_CHART_WIDTH, Map$1 as Map, MapContext, MapProvider, NO_CONTENT_VALUE, NUMERIC_ATTRIBUTE_TYPES, NoLiveSnapshotContainer, OneColumnContainer, POLL_SUBTASK_INTERVAL_MS, POLL_SUBTASK_TIMEOUT_MS, PROVIDER_PREFIX, PageNavigator, PageTitle, PageTitleContainer, PagesContainer, Pagination, PresentationHeader, PresentationHeaderButtons, PresentationHeaderTools, PresentationPanelContainer, PresentationPanelWrapper, PresentationWrapper, ProgressContainer, ProviderPrefix, RoundedBackgroundContainer, SERVER_NOTIFICATION_EVENT, STACK_BAR_TOTAL_HEIGHT, ScalingFactor, ServerNotificationsContext, ServerNotificationsProvider, SlideshowContainer, SmallPreviewContainer$1 as SmallPreviewContainer, SmallPreviewControl, SmallPreviewCounter, SmallPreviewImages, SmallPreviewLeft, SmallPreviewRight, StackBar, SvgImage, TIME_ZONE_FORMAT, TabsContainer, TextTrim, ThemeName, TitleContainer, TopContainer, TopContainerButtons, TwoColumnContainer, UploadContainer, WidgetType, addDataSource, addDataSources, adjustColor, applyFiltersToCondition, applyQueryFilters, applyVarsToCondition, checkEqualOrIncludes, checkIsLoading, convertSpToTurfFeature, createConfigLayer, createConfigPage, createNewPageId, createTreeNode, dateOptions, debounce, decimalOpacityToHex, eqlParametersToPayload, findAttributeInExpression, formatArea, formatAttributeValue, formatChartRelatedValue, formatConditionValue, formatDataSourceCondition, formatDate$1 as formatDate, formatElementValue, formatLength, formatNumber, formatPolygonMeasure, getActualExtrusionHeight, getAttributeByName, getAttributeValue, getAttributesConfiguration, getChartAxes, getChartFilterName, getChartMarkers, getConfigFilter, getContainerComponent, getDashboardHeader, getDataFromAttributes, getDataFromRelatedFeatures, getDataSource, getDataSourceFilterValue, getDate, getDefaultConfig, getElementValue, getFeatureAttributes, getFeatureCardHeader, getFilterComponent, getFilterSelectedItems, getFilterValue, getFormattedAttributes, getGradientColors, getLayerInfo, getLayerInfoFromDataSources, getPagesFromConfig, getPagesFromProjectInfo, getProxyService, getRelatedAttribute, getRenderElement, getResourceUrl, getRootElementId, getSelectedFilterValue, getSlideshowImages, getSvgUrl, getTemplateNameFromAttribute, getTotalFromAttributes, getTotalFromRelatedFeatures, hexToRgba, isCompositeLayerConfiguration, isEmptyElementValue, isEmptyValue, isHiddenEmptyValue, isLayerService, isNotValidSelectedTab, isNumeric, isObject, isProxyService, isVisibleContainer, metersPerPixel, numberOptions, parseClientStyle, parseIconNames, parseIconNamesFromClientStyle, pieChartTooltipFromAttributes, pieChartTooltipFromRelatedFeatures, pointOptions, removeDataSource, rgbToHex, roundTotalSum, sliceShownOtherItems, timeOptions, tooltipNameFromAttributes, tooltipValueFromAttributes, tooltipValueFromRelatedFeatures, transparentizeColor, treeNodesToProjectItems, updateDataSource, useAppHeight, useAutoCompleteControl, useChartChange, useChartData, useContainerAttributes, useCurrentPageLayers, useCustomFeatureSelect, useDashboardHeader, useDataSources, useDebouncedCallback, useDiffPage, useExpandableContainers, useExportPdf, useFetchImageWithAuth, useFetchWithAuth, useGetConfigLayer, useGlobalContext, useHeaderRender, useHideIfEmptyDataSource, useIconsFromLayers, useLayerHiddenAttributes, useLayerParams, useMapContext, useMapDraw, useMapImages, useMaxZoomTo, useProjectDashboardInit, usePythonSandbox, usePythonTask, useRedrawLayer, useRelatedDataSourceAttributes, useRenderElement, useServerNotificationsContext, useShownOtherItems, useToggle, useUpdateDataSource, useVisibleProjectItems, useWidgetConfig, useWidgetContext, useWidgetFilters, useWidgetPage, useWindowResize, useZoomToFeatures, useZoomToPoint };
12483
12489
  //# sourceMappingURL=react.esm.js.map