@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.
- package/dist/components/Dashboard/containers/StructuredDataContainer/hooks/useStructuredData.d.ts +27 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/hooks/useStructuredDataDraft.d.ts +25 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/hooks/useStructuredDataSave.d.ts +17 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/hooks/useStructuredDataSchema.d.ts +15 -0
- package/dist/components/Dashboard/containers/StructuredDataContainer/types.d.ts +0 -2
- package/dist/components/Dashboard/containers/StructuredDataContainer/utils/buildSchema.d.ts +2 -1
- package/dist/components/Dashboard/elements/ElementTable/hooks/useCellEditing.d.ts +15 -0
- package/dist/components/Dashboard/elements/ElementTable/hooks/useTableView.d.ts +16 -0
- package/dist/components/Dashboard/elements/ElementTable/styled.d.ts +6 -1
- package/dist/components/Dashboard/hooks/useRelatedDataSourceAttributes.d.ts +1 -0
- package/dist/index.js +66 -31
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +66 -31
- package/dist/react.esm.js.map +1 -1
- package/package.json +2 -2
package/dist/components/Dashboard/containers/StructuredDataContainer/hooks/useStructuredData.d.ts
ADDED
|
@@ -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
|
-
*
|
|
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 = (
|
|
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(
|
|
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(
|
|
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(
|
|
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({
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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:
|
|
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.
|
|
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)
|
|
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
|
-
|
|
17567
|
-
|
|
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(() => {
|