@evergis/react 4.0.127 → 4.0.129

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.
@@ -0,0 +1,27 @@
1
+ import { StructuredDataContainerConfig, WidgetType } from '../../../types';
2
+ import { StructuredDataContextValue } from '../types';
3
+ /**
4
+ * Оркестратор контейнера: собирает схему, черновик и запись в одно состояние экрана.
5
+ *
6
+ * Правку открывает `options.editMode`: не задан или `false` — таблица целиком на чтение, без
7
+ * редакторов ячеек, добавления, удаления и кнопок сохранения.
8
+ *
9
+ * Вид источника на права правки не влияет — от него зависит только адресат «Сохранить». Слой
10
+ * принимает запись через features-API, источник без `layerName` (EQL, python-скрипт, внешний
11
+ * url) не принимает ничего, и правка такой таблицы уходит только в фильтр.
12
+ */
13
+ export declare const useStructuredData: (type: WidgetType, elementConfig?: StructuredDataContainerConfig) => {
14
+ contextValue: StructuredDataContextValue;
15
+ dirty: boolean;
16
+ saving: boolean;
17
+ loading: boolean;
18
+ hasError: boolean;
19
+ canEdit: boolean;
20
+ isDeleteConfirmOpen: boolean;
21
+ isDeletingSourceRow: boolean;
22
+ onAddRow: () => void;
23
+ onCancel: () => void;
24
+ onSave: () => Promise<void>;
25
+ onDeleteConfirm: () => void;
26
+ onDeleteCancel: () => void;
27
+ };
@@ -0,0 +1,25 @@
1
+ import { FeatureAttributeValue } from '../../../../../types';
2
+ import { SelectedFilter, WidgetDataSource } from '../../../types';
3
+ import { DraftRow, StructuredDataAttribute } from '../types';
4
+ /**
5
+ * Черновик строк: правки копятся локально и никого не трогают до «Сохранить».
6
+ *
7
+ * База (`baseline`) — последнее сохранённое состояние; «Отменить» возвращает к нему.
8
+ * Пока черновик грязный, приходящие обновления источника его НЕ затирают — иначе фоновая
9
+ * перезагрузка данных стирала бы набранное пользователем.
10
+ */
11
+ export declare const useStructuredDataDraft: ({ schema, dataSource, hasDataSource, filterValue, }: {
12
+ schema: StructuredDataAttribute[];
13
+ dataSource?: WidgetDataSource;
14
+ hasDataSource: boolean;
15
+ filterValue?: SelectedFilter["value"];
16
+ }) => {
17
+ rows: DraftRow[];
18
+ visibleRows: DraftRow[];
19
+ dirty: boolean;
20
+ changeCell: (key: string, attributeName: string, value: FeatureAttributeValue) => void;
21
+ addRow: () => void;
22
+ deleteRow: (key: string) => void;
23
+ reset: () => void;
24
+ commitSaved: (next: DraftRow[]) => void;
25
+ };
@@ -0,0 +1,17 @@
1
+ import { WidgetType } from '../../../types';
2
+ import { DraftRow, StructuredDataAttribute } from '../types';
3
+ /**
4
+ * Запись черновика: сперва в источник (если он поддерживает запись), затем в фильтр.
5
+ *
6
+ * Порядок не случаен: потребители фильтра не должны увидеть данные, которых источник не принял.
7
+ * При ошибке черновик остаётся нетронутым — пользователь может исправить значения и повторить.
8
+ */
9
+ export declare const useStructuredDataSave: ({ type, schema, layerName, filterName, }: {
10
+ type: WidgetType;
11
+ schema: StructuredDataAttribute[];
12
+ layerName?: string;
13
+ filterName?: string;
14
+ }) => {
15
+ save: (rows: DraftRow[]) => Promise<DraftRow[] | null>;
16
+ saving: boolean;
17
+ };
@@ -0,0 +1,15 @@
1
+ import { StructuredDataContainerConfig, WidgetType } from '../../../types';
2
+ /**
3
+ * Схема структурированных данных и источник, к которому она привязана.
4
+ *
5
+ * Источник резолвится через общий `useRelatedDataSourceAttributes`: он собирает layerInfo
6
+ * реального слоя, а для EQL/python-источников — синтетический из атрибутов ответа.
7
+ *
8
+ * `layerName` берётся из конфига страницы, а не из загруженного источника: от него зависит,
9
+ * какие ячейки редактируемы, и до окончания загрузки схема не должна меняться.
10
+ */
11
+ export declare const useStructuredDataSchema: (type: WidgetType, elementConfig?: StructuredDataContainerConfig) => {
12
+ schema: import('../types').StructuredDataAttribute[];
13
+ dataSource: import('../../../types').WidgetDataSource;
14
+ layerName: string;
15
+ };
@@ -41,8 +41,6 @@ export interface StructuredDataContextValue {
41
41
  * только на чтение: редакторов в ячейках нет, как и удаления строк.
42
42
  */
43
43
  canEdit: boolean;
44
- /** Строки можно удалять: правка разрешена И источник поддерживает запись (либо его нет вовсе). */
45
- canDeleteRows: boolean;
46
44
  onCellChange: (key: string, attributeName: string, value: FeatureAttributeValue) => void;
47
45
  onRowDelete: (key: string) => void;
48
46
  }
@@ -8,7 +8,8 @@ import { StructuredDataAttribute } from '../types';
8
8
  * `alias`, `stringFormat` и `isEditable`, тогда как типы приходят от источника. Без описания
9
9
  * берутся все атрибуты источника. Без источника описание — единственная схема, и оно обязательно.
10
10
  */
11
- export declare const buildStructuredDataSchema: ({ attributesDescription, attributesConfiguration, }: {
11
+ export declare const buildStructuredDataSchema: ({ attributesDescription, attributesConfiguration, canWriteToSource, }: {
12
12
  attributesDescription?: ConfigAttributeDescription[];
13
13
  attributesConfiguration?: AttributesConfigurationDc;
14
+ canWriteToSource: boolean;
14
15
  }) => StructuredDataAttribute[];
@@ -0,0 +1,15 @@
1
+ import { KeyboardEvent } from 'react';
2
+ /**
3
+ * Режим правки одной ячейки: открывается кликом по значению, закрывается кликом снаружи.
4
+ *
5
+ * Закрывать по `blur` нельзя: `DatePicker` уводит фокус из поля уже на клике по иконке
6
+ * календаря — редактор исчезал бы раньше, чем календарь успевал открыться. Поэтому слушаем
7
+ * `mousedown` на документе, а клики внутри портала (`#portal-root`) считаем «своими»:
8
+ * выпадающие слои контролов uilib живут именно там, вне DOM-поддерева ячейки.
9
+ */
10
+ export declare const useCellEditing: () => {
11
+ editing: boolean;
12
+ editorRef: import('react').MutableRefObject<HTMLDivElement>;
13
+ startEditing: () => void;
14
+ onKeyDown: ({ key }: KeyboardEvent<HTMLDivElement>) => void;
15
+ };
@@ -0,0 +1,16 @@
1
+ import { ElementTableConfig } from '../../../types';
2
+ import { TableSort } from '../types';
3
+ /**
4
+ * Вид таблицы: набор и порядок колонок из `columnNames` плюс локальная сортировка.
5
+ *
6
+ * Сортировка живёт здесь, а не в контейнере: она ничего не меняет в данных и не должна
7
+ * влиять на порядок строк, уходящих в фильтр.
8
+ */
9
+ export declare const useTableView: (elementConfig?: ElementTableConfig) => {
10
+ context: import('../../../containers/StructuredDataContainer/types').StructuredDataContextValue;
11
+ columns: import('../../../containers/StructuredDataContainer/types').StructuredDataAttribute[];
12
+ rows: import('../../../containers/StructuredDataContainer/types').DraftRow[];
13
+ sort: TableSort;
14
+ sortEnabled: boolean;
15
+ onSortToggle: (attributeName: string) => void;
16
+ };
@@ -1,5 +1,10 @@
1
1
  export declare const TableWrapper: import('styled-components').StyledComponent<"table", any, {}, never>;
2
- /** Шапка липнет к верху области прокрутки — при длинной таблице заголовки остаются видны. */
2
+ /**
3
+ * Шапка липнет к верху области прокрутки — при длинной таблице заголовки остаются видны.
4
+ *
5
+ * Собственного фона у шапки нет: цвет из палитры не следовал за подложкой контейнера
6
+ * и выделялся белым прямоугольником на любом фоне, отличном от базового.
7
+ */
3
8
  export declare const TableHead: import('styled-components').StyledComponent<"thead", any, {}, never>;
4
9
  export declare const TableHeadCell: import('styled-components').StyledComponent<"th", any, {
5
10
  $sortable?: boolean;
@@ -9,4 +9,5 @@ export declare const useRelatedDataSourceAttributes: ({ type, elementConfig, dat
9
9
  layerInfo: import('@evergis/api').QueryLayerServiceInfoDc;
10
10
  attributes: import('../types').ClientFeatureAttribute[];
11
11
  dataSource: import('../types').WidgetDataSource;
12
+ configDataSource: import('../types').ConfigDataSource;
12
13
  };
package/dist/index.js CHANGED
@@ -7928,7 +7928,7 @@ const useRelatedDataSourceAttributes = ({ type = exports.WidgetType.Dashboard, e
7928
7928
  const layerInfo = React.useMemo(() => getDataSourceLayerInfo({ layerInfos, configDataSource, fetchedDataSource: dataSource }) ||
7929
7929
  EMPTY_DATA_SOURCE_LAYER_INFO, [configDataSource, dataSource, layerInfos]);
7930
7930
  const attributes = React.useMemo(() => getFeatureAttributes(feature, layerInfo, dataSource), [dataSource, feature, layerInfo]);
7931
- return { layerInfo, attributes, dataSource };
7931
+ return { layerInfo, attributes, dataSource, configDataSource };
7932
7932
  };
7933
7933
 
7934
7934
  const useRenderElement = (type = exports.WidgetType.Dashboard, elementConfig) => {
@@ -11176,11 +11176,16 @@ const getSourceAttributes = (attributesConfiguration) => {
11176
11176
  return (attributes ?? []).filter(({ attributeName }) => attributeName !== geometryAttribute);
11177
11177
  };
11178
11178
  /**
11179
- * Конфиг может только ЗАПРЕТИТЬ правку, но не разрешить её там, где источник её не допускает:
11180
- * id-атрибут и вычисляемые поля сервер всё равно не примет.
11179
+ * Ограничения источника действуют там, где правка в него и уезжает: id-атрибут и вычисляемое
11180
+ * поле сервер всё равно не примет, поэтому конфиг может такую ячейку только ЗАПРЕТИТЬ, но не
11181
+ * разрешить.
11182
+ *
11183
+ * Источник без записи (EQL-запрос, python-скрипт, внешний url) их не накладывает вовсе: его
11184
+ * строки уходят только в фильтр, и «нередактируемо» там значит лишь «нельзя записать обратно».
11185
+ * Решает конфиг — по умолчанию правка разрешена.
11181
11186
  */
11182
- const resolveIsEditable = (description, source, idAttribute) => {
11183
- const sourceEditable = source
11187
+ const resolveIsEditable = ({ description, source, idAttribute, canWriteToSource }) => {
11188
+ const sourceEditable = source && canWriteToSource
11184
11189
  ? source.isEditable !== false &&
11185
11190
  source.attributeConfigurationType !== api.AttributeConfigurationType.Calculated &&
11186
11191
  source.attributeName !== idAttribute
@@ -11194,7 +11199,8 @@ const resolveStringFormat = (description, source) => {
11194
11199
  }
11195
11200
  return { ...source?.stringFormat, ...description?.stringFormat };
11196
11201
  };
11197
- const toSchemaAttribute = (description, source, idAttribute) => {
11202
+ const toSchemaAttribute = (params) => {
11203
+ const { description, source } = params;
11198
11204
  const attributeName = description?.attributeName ?? source?.attributeName;
11199
11205
  return {
11200
11206
  attributeName,
@@ -11202,7 +11208,7 @@ const toSchemaAttribute = (description, source, idAttribute) => {
11202
11208
  type: source?.type ?? description?.type ?? DEFAULT_ATTRIBUTE_TYPE,
11203
11209
  alias: description?.alias ?? source?.alias ?? attributeName,
11204
11210
  description: description?.description ?? source?.description,
11205
- isEditable: resolveIsEditable(description, source, idAttribute),
11211
+ isEditable: resolveIsEditable(params),
11206
11212
  stringFormat: resolveStringFormat(description, source),
11207
11213
  };
11208
11214
  };
@@ -11213,15 +11219,20 @@ const toSchemaAttribute = (description, source, idAttribute) => {
11213
11219
  * `alias`, `stringFormat` и `isEditable`, тогда как типы приходят от источника. Без описания
11214
11220
  * берутся все атрибуты источника. Без источника описание — единственная схема, и оно обязательно.
11215
11221
  */
11216
- const buildStructuredDataSchema = ({ attributesDescription, attributesConfiguration, }) => {
11222
+ const buildStructuredDataSchema = ({ attributesDescription, attributesConfiguration, canWriteToSource, }) => {
11217
11223
  const sourceAttributes = getSourceAttributes(attributesConfiguration);
11218
11224
  const { idAttribute } = attributesConfiguration || {};
11219
11225
  if (attributesDescription?.length) {
11220
11226
  return attributesDescription
11221
11227
  .filter(({ attributeName }) => !!attributeName)
11222
- .map(description => toSchemaAttribute(description, sourceAttributes.find(({ attributeName }) => attributeName === description.attributeName), idAttribute));
11228
+ .map(description => toSchemaAttribute({
11229
+ description,
11230
+ source: sourceAttributes.find(({ attributeName }) => attributeName === description.attributeName),
11231
+ idAttribute,
11232
+ canWriteToSource,
11233
+ }));
11223
11234
  }
11224
- return sourceAttributes.map(source => toSchemaAttribute(undefined, source, idAttribute));
11235
+ return sourceAttributes.map(source => toSchemaAttribute({ source, idAttribute, canWriteToSource }));
11225
11236
  };
11226
11237
 
11227
11238
  /**
@@ -11229,14 +11240,22 @@ const buildStructuredDataSchema = ({ attributesDescription, attributesConfigurat
11229
11240
  *
11230
11241
  * Источник резолвится через общий `useRelatedDataSourceAttributes`: он собирает layerInfo
11231
11242
  * реального слоя, а для EQL/python-источников — синтетический из атрибутов ответа.
11243
+ *
11244
+ * `layerName` берётся из конфига страницы, а не из загруженного источника: от него зависит,
11245
+ * какие ячейки редактируемы, и до окончания загрузки схема не должна меняться.
11232
11246
  */
11233
11247
  const useStructuredDataSchema = (type, elementConfig) => {
11234
11248
  const { dataSources } = useWidgetContext(type);
11235
11249
  const { attributesDescription, relatedDataSource } = elementConfig?.options || {};
11236
- const { layerInfo, dataSource } = useRelatedDataSourceAttributes({ type, elementConfig, dataSources });
11250
+ const { layerInfo, dataSource, configDataSource } = useRelatedDataSourceAttributes({
11251
+ type,
11252
+ elementConfig,
11253
+ dataSources,
11254
+ });
11255
+ const layerName = configDataSource?.layerName;
11237
11256
  const attributesConfiguration = React.useMemo(() => (relatedDataSource ? getAttributesConfiguration(layerInfo) : undefined), [layerInfo, relatedDataSource]);
11238
- const schema = React.useMemo(() => buildStructuredDataSchema({ attributesDescription, attributesConfiguration }), [attributesDescription, attributesConfiguration]);
11239
- return { schema, dataSource };
11257
+ const schema = React.useMemo(() => buildStructuredDataSchema({ attributesDescription, attributesConfiguration, canWriteToSource: !!layerName }), [attributesDescription, attributesConfiguration, layerName]);
11258
+ return { schema, dataSource, layerName };
11240
11259
  };
11241
11260
 
11242
11261
  /**
@@ -11245,14 +11264,14 @@ const useStructuredDataSchema = (type, elementConfig) => {
11245
11264
  * Правку открывает `options.editMode`: не задан или `false` — таблица целиком на чтение, без
11246
11265
  * редакторов ячеек, добавления, удаления и кнопок сохранения.
11247
11266
  *
11248
- * Источник без `layerName` (EQL, python-скрипт, внешний url) записи не поддерживает контейнер
11249
- * деградирует в «ручную структуру поверх данных источника»: строки правятся и уезжают в фильтр,
11250
- * но добавление и удаление строк недоступны.
11267
+ * Вид источника на права правки не влияет от него зависит только адресат «Сохранить». Слой
11268
+ * принимает запись через features-API, источник без `layerName` (EQL, python-скрипт, внешний
11269
+ * url) не принимает ничего, и правка такой таблицы уходит только в фильтр.
11251
11270
  */
11252
11271
  const useStructuredData = (type, elementConfig) => {
11253
11272
  const { filters } = useWidgetContext(type);
11254
11273
  const { relatedDataSource, filterName, editMode } = elementConfig?.options || {};
11255
- const { schema, dataSource } = useStructuredDataSchema(type, elementConfig);
11274
+ const { schema, dataSource, layerName } = useStructuredDataSchema(type, elementConfig);
11256
11275
  const hasDataSource = !!relatedDataSource;
11257
11276
  const filterValue = filterName ? filters?.[filterName]?.value : undefined;
11258
11277
  const { rows, visibleRows, dirty, changeCell, addRow, deleteRow, reset, commitSaved } = useStructuredDataDraft({
@@ -11264,14 +11283,13 @@ const useStructuredData = (type, elementConfig) => {
11264
11283
  const { save, saving } = useStructuredDataSave({
11265
11284
  type,
11266
11285
  schema,
11267
- layerName: dataSource?.layerName,
11286
+ layerName,
11268
11287
  filterName,
11269
11288
  });
11270
11289
  const [deletingKey, setDeletingKey] = React.useState(null);
11271
11290
  const loading = hasDataSource && (!dataSource || dataSource.features === undefined);
11272
11291
  const hasError = hasDataSource && dataSource?.features === null;
11273
11292
  const canEdit = !!editMode;
11274
- const canEditRows = canEdit && (!hasDataSource || !!dataSource?.layerName);
11275
11293
  const onSave = React.useCallback(async () => {
11276
11294
  const savedRows = await save(rows);
11277
11295
  if (savedRows) {
@@ -11280,7 +11298,9 @@ const useStructuredData = (type, elementConfig) => {
11280
11298
  }, [commitSaved, rows, save]);
11281
11299
  const onRowDelete = React.useCallback((key) => setDeletingKey(key), []);
11282
11300
  const onDeleteCancel = React.useCallback(() => setDeletingKey(null), []);
11283
- const isDeletingSourceRow = React.useMemo(() => !!rows.find(({ key }) => key === deletingKey)?.featureId, [deletingKey, rows]);
11301
+ // Про необратимость предупреждаем только там, где удаление и правда дойдёт до источника:
11302
+ // у строки источника без записи id есть, но удаление уберёт её лишь из значения фильтра.
11303
+ const isDeletingSourceRow = React.useMemo(() => !!layerName && !!rows.find(({ key }) => key === deletingKey)?.featureId, [deletingKey, layerName, rows]);
11284
11304
  const onDeleteConfirm = React.useCallback(() => {
11285
11305
  if (deletingKey) {
11286
11306
  deleteRow(deletingKey);
@@ -11292,10 +11312,9 @@ const useStructuredData = (type, elementConfig) => {
11292
11312
  rows: visibleRows,
11293
11313
  loading,
11294
11314
  canEdit,
11295
- canDeleteRows: canEditRows,
11296
11315
  onCellChange: changeCell,
11297
11316
  onRowDelete,
11298
- }), [canEdit, canEditRows, changeCell, loading, onRowDelete, schema, visibleRows]);
11317
+ }), [canEdit, changeCell, loading, onRowDelete, schema, visibleRows]);
11299
11318
  return {
11300
11319
  contextValue,
11301
11320
  dirty,
@@ -11303,7 +11322,6 @@ const useStructuredData = (type, elementConfig) => {
11303
11322
  loading,
11304
11323
  hasError,
11305
11324
  canEdit,
11306
- canAddRows: canEditRows,
11307
11325
  isDeleteConfirmOpen: !!deletingKey,
11308
11326
  isDeletingSourceRow,
11309
11327
  onAddRow: addRow,
@@ -11324,11 +11342,11 @@ const useStructuredData = (type, elementConfig) => {
11324
11342
  const StructuredDataContainer = React.memo(({ type, elementConfig, isVisible, renderElement }) => {
11325
11343
  const { t } = useGlobalContext();
11326
11344
  const { root, body } = useContainerRoot({ elementConfig });
11327
- const { contextValue, dirty, saving, hasError, canEdit, canAddRows, isDeleteConfirmOpen, isDeletingSourceRow, onAddRow, onCancel, onSave, onDeleteConfirm, onDeleteCancel, } = useStructuredData(type, elementConfig);
11345
+ const { contextValue, dirty, saving, hasError, canEdit, isDeleteConfirmOpen, isDeletingSourceRow, onAddRow, onCancel, onSave, onDeleteConfirm, onDeleteCancel, } = useStructuredData(type, elementConfig);
11328
11346
  if (hasError) {
11329
11347
  return jsxRuntime.jsx(DataSourceError, { name: elementConfig?.templateName });
11330
11348
  }
11331
- return (jsxRuntime.jsxs(ContainerRoot, { ...root, children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsxs(Container, { ...body, isColumn: true, children: [jsxRuntime.jsx(StructuredDataView, { children: jsxRuntime.jsx(StructuredDataContext.Provider, { value: contextValue, children: renderElement({ id: "data" }) }) }), canEdit && (jsxRuntime.jsxs(StructuredDataToolbar, { children: [jsxRuntime.jsx(StructuredDataActions, { children: canAddRows && (jsxRuntime.jsx(uilibGl.IconButton, { kind: "plus", primary: true, disabled: saving, onClick: onAddRow, children: t("structuredData.addRow", { ns: "dashboard", defaultValue: "Добавить строку" }) })) }), dirty && (jsxRuntime.jsxs(StructuredDataActions, { children: [jsxRuntime.jsx(uilibGl.FlatButton, { disabled: saving, onClick: onCancel, children: t("actions.cancel", { ns: "common", defaultValue: "Отменить" }) }), jsxRuntime.jsx(uilibGl.RaisedButton, { primary: true, disabled: saving, onClick: onSave, children: t("actions.save", { ns: "common", defaultValue: "Сохранить" }) })] }))] }))] })), jsxRuntime.jsx(DeleteRowDialog, { isOpen: isDeleteConfirmOpen, isSourceRow: isDeletingSourceRow, onConfirm: onDeleteConfirm, onCancel: onDeleteCancel })] }));
11349
+ return (jsxRuntime.jsxs(ContainerRoot, { ...root, children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxRuntime.jsxs(Container, { ...body, isColumn: true, children: [jsxRuntime.jsx(StructuredDataView, { children: jsxRuntime.jsx(StructuredDataContext.Provider, { value: contextValue, children: renderElement({ id: "data" }) }) }), canEdit && (jsxRuntime.jsxs(StructuredDataToolbar, { children: [jsxRuntime.jsx(StructuredDataActions, { children: jsxRuntime.jsx(uilibGl.IconButton, { kind: "plus", primary: true, disabled: saving, onClick: onAddRow, children: t("structuredData.addRow", { ns: "dashboard", defaultValue: "Добавить строку" }) }) }), dirty && (jsxRuntime.jsxs(StructuredDataActions, { children: [jsxRuntime.jsx(uilibGl.FlatButton, { disabled: saving, onClick: onCancel, children: t("actions.cancel", { ns: "common", defaultValue: "Отменить" }) }), jsxRuntime.jsx(uilibGl.RaisedButton, { primary: true, disabled: saving, onClick: onSave, children: t("actions.save", { ns: "common", defaultValue: "Сохранить" }) })] }))] }))] })), jsxRuntime.jsx(DeleteRowDialog, { isOpen: isDeleteConfirmOpen, isSourceRow: isDeletingSourceRow, onConfirm: onDeleteConfirm, onCancel: onDeleteCancel })] }));
11332
11350
  });
11333
11351
 
11334
11352
  const TabAnchor = styled.div.withConfig({ displayName: "TabAnchor", componentId: "sc-emqf31" }) `
@@ -14284,12 +14302,16 @@ const TableWrapper = styled.table.withConfig({ displayName: "TableWrapper", comp
14284
14302
  border-collapse: collapse;
14285
14303
  font-size: 0.875rem;
14286
14304
  `;
14287
- /** Шапка липнет к верху области прокрутки — при длинной таблице заголовки остаются видны. */
14305
+ /**
14306
+ * Шапка липнет к верху области прокрутки — при длинной таблице заголовки остаются видны.
14307
+ *
14308
+ * Собственного фона у шапки нет: цвет из палитры не следовал за подложкой контейнера
14309
+ * и выделялся белым прямоугольником на любом фоне, отличном от базового.
14310
+ */
14288
14311
  const TableHead = styled.thead.withConfig({ displayName: "TableHead", componentId: "sc-pa89d3" }) `
14289
14312
  position: sticky;
14290
14313
  top: 0;
14291
14314
  z-index: 1;
14292
- background: ${({ theme }) => theme.palette.background};
14293
14315
  `;
14294
14316
  const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", componentId: "sc-1f151xj" }) `
14295
14317
  padding: 0.375rem 0.5rem;
@@ -14603,7 +14625,7 @@ const ElementTable = React.memo(({ elementConfig }) => {
14603
14625
  defaultValue: "Схема данных не задана",
14604
14626
  }) }));
14605
14627
  }
14606
- return (jsxRuntime.jsxs(TableWrapper, { children: [jsxRuntime.jsx(TableHead, { children: jsxRuntime.jsxs("tr", { children: [columns.map(({ attributeName, alias, description }) => (jsxRuntime.jsx(TableHeadCell, { title: description || alias, "$sortable": sortEnabled, onClick: sortEnabled ? () => onSortToggle(attributeName) : undefined, children: jsxRuntime.jsxs(TableHeadContent, { children: [alias, sort?.attributeName === attributeName && (jsxRuntime.jsx(uilibGl.Icon, { kind: sort.direction === "asc" ? "sorting_asc" : "sorting_des" }))] }) }, attributeName))), context.canDeleteRows && jsxRuntime.jsx(TableHeadCell, {})] }) }), jsxRuntime.jsx("tbody", { children: rows.map(row => (jsxRuntime.jsxs(TableRow, { children: [columns.map(attribute => (jsxRuntime.jsx(TableCellWrapper, { children: jsxRuntime.jsx(TableCell, { attribute: attribute, row: row, canEdit: context.canEdit, onChange: context.onCellChange }) }, attribute.attributeName))), context.canDeleteRows && (jsxRuntime.jsx(TableActionsCell, { children: jsxRuntime.jsx(uilibGl.IconButton, { kind: "delete", title: t("actions.delete", { ns: "common", defaultValue: "Удалить" }), onClick: () => context.onRowDelete(row.key) }) }))] }, row.key))) })] }));
14628
+ return (jsxRuntime.jsxs(TableWrapper, { children: [jsxRuntime.jsx(TableHead, { children: jsxRuntime.jsxs("tr", { children: [columns.map(({ attributeName, alias, description }) => (jsxRuntime.jsx(TableHeadCell, { title: description || alias, "$sortable": sortEnabled, onClick: sortEnabled ? () => onSortToggle(attributeName) : undefined, children: jsxRuntime.jsxs(TableHeadContent, { children: [alias, sort?.attributeName === attributeName && (jsxRuntime.jsx(uilibGl.Icon, { kind: sort.direction === "asc" ? "sorting_asc" : "sorting_des" }))] }) }, attributeName))), context.canEdit && jsxRuntime.jsx(TableHeadCell, {})] }) }), jsxRuntime.jsx("tbody", { children: rows.map(row => (jsxRuntime.jsxs(TableRow, { children: [columns.map(attribute => (jsxRuntime.jsx(TableCellWrapper, { children: jsxRuntime.jsx(TableCell, { attribute: attribute, row: row, canEdit: context.canEdit, onChange: context.onCellChange }) }, attribute.attributeName))), context.canEdit && (jsxRuntime.jsx(TableActionsCell, { children: jsxRuntime.jsx(uilibGl.IconButton, { kind: "delete", title: t("actions.delete", { ns: "common", defaultValue: "Удалить" }), onClick: () => context.onRowDelete(row.key) }) }))] }, row.key))) })] }));
14607
14629
  });
14608
14630
 
14609
14631
  const TooltipIcon = styled(uilibGl.Icon).withConfig({ displayName: "TooltipIcon", componentId: "sc-1lkxudm" }) `
@@ -17550,7 +17572,9 @@ const RasterLayer = ({ layer, tileUrl, visible, beforeId, }) => {
17550
17572
  const VectorLayer = ({ layer, tileUrl, visible, beforeId, getLayerTempStyle, }) => {
17551
17573
  const layerConfiguration = layer?.configuration;
17552
17574
  const clientStyle = layerConfiguration?.clientStyle;
17553
- const currentStyle = React.useMemo(() => getLayerTempStyle(layer.name) ?? clientStyle, [clientStyle, getLayerTempStyle, layer.name]);
17575
+ const currentStyle = React.useMemo(() => !lodash.isNil(getLayerTempStyle?.(layer.name)) && !lodash.isEmpty(getLayerTempStyle?.(layer.name))
17576
+ ? getLayerTempStyle(layer.name)
17577
+ : clientStyle, [clientStyle, getLayerTempStyle, layer.name]);
17554
17578
  const idAttribute = layerConfiguration?.attributesConfiguration?.idAttribute;
17555
17579
  const tiles = React.useMemo(() => [tileUrl], [tileUrl]);
17556
17580
  // Собираем конфигурации иконок для загрузки из clientStyle
@@ -17563,8 +17587,19 @@ const VectorLayer = ({ layer, tileUrl, visible, beforeId, getLayerTempStyle, })
17563
17587
  return [];
17564
17588
  }
17565
17589
  return iconNames.map(name => {
17566
- return currentStyle.icons?.find((icon) => icon.name === name) ?? null;
17567
- }).filter(Boolean);
17590
+ const customIcon = currentStyle.icons?.find((icon) => icon.name === name);
17591
+ if (customIcon) {
17592
+ return {
17593
+ name: customIcon.name,
17594
+ url: customIcon.url,
17595
+ sdf: customIcon.sdf,
17596
+ size: customIcon.size,
17597
+ pixelRatio: customIcon.pixelRatio,
17598
+ };
17599
+ }
17600
+ // Fallback - иконка не найдена в конфиге, пропускаем
17601
+ return null;
17602
+ }).filter((config) => config !== null);
17568
17603
  }, [currentStyle]);
17569
17604
  useMapImages({ images: iconConfigs });
17570
17605
  const renderClientStyle = React.useCallback(() => {