@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/react.esm.js
CHANGED
|
@@ -7926,7 +7926,7 @@ const useRelatedDataSourceAttributes = ({ type = WidgetType.Dashboard, elementCo
|
|
|
7926
7926
|
const layerInfo = useMemo(() => getDataSourceLayerInfo({ layerInfos, configDataSource, fetchedDataSource: dataSource }) ||
|
|
7927
7927
|
EMPTY_DATA_SOURCE_LAYER_INFO, [configDataSource, dataSource, layerInfos]);
|
|
7928
7928
|
const attributes = useMemo(() => getFeatureAttributes(feature, layerInfo, dataSource), [dataSource, feature, layerInfo]);
|
|
7929
|
-
return { layerInfo, attributes, dataSource };
|
|
7929
|
+
return { layerInfo, attributes, dataSource, configDataSource };
|
|
7930
7930
|
};
|
|
7931
7931
|
|
|
7932
7932
|
const useRenderElement = (type = WidgetType.Dashboard, elementConfig) => {
|
|
@@ -11174,11 +11174,16 @@ const getSourceAttributes = (attributesConfiguration) => {
|
|
|
11174
11174
|
return (attributes ?? []).filter(({ attributeName }) => attributeName !== geometryAttribute);
|
|
11175
11175
|
};
|
|
11176
11176
|
/**
|
|
11177
|
-
*
|
|
11178
|
-
*
|
|
11177
|
+
* Ограничения источника действуют там, где правка в него и уезжает: id-атрибут и вычисляемое
|
|
11178
|
+
* поле сервер всё равно не примет, поэтому конфиг может такую ячейку только ЗАПРЕТИТЬ, но не
|
|
11179
|
+
* разрешить.
|
|
11180
|
+
*
|
|
11181
|
+
* Источник без записи (EQL-запрос, python-скрипт, внешний url) их не накладывает вовсе: его
|
|
11182
|
+
* строки уходят только в фильтр, и «нередактируемо» там значит лишь «нельзя записать обратно».
|
|
11183
|
+
* Решает конфиг — по умолчанию правка разрешена.
|
|
11179
11184
|
*/
|
|
11180
|
-
const resolveIsEditable = (description, source, idAttribute) => {
|
|
11181
|
-
const sourceEditable = source
|
|
11185
|
+
const resolveIsEditable = ({ description, source, idAttribute, canWriteToSource }) => {
|
|
11186
|
+
const sourceEditable = source && canWriteToSource
|
|
11182
11187
|
? source.isEditable !== false &&
|
|
11183
11188
|
source.attributeConfigurationType !== AttributeConfigurationType.Calculated &&
|
|
11184
11189
|
source.attributeName !== idAttribute
|
|
@@ -11192,7 +11197,8 @@ const resolveStringFormat = (description, source) => {
|
|
|
11192
11197
|
}
|
|
11193
11198
|
return { ...source?.stringFormat, ...description?.stringFormat };
|
|
11194
11199
|
};
|
|
11195
|
-
const toSchemaAttribute = (
|
|
11200
|
+
const toSchemaAttribute = (params) => {
|
|
11201
|
+
const { description, source } = params;
|
|
11196
11202
|
const attributeName = description?.attributeName ?? source?.attributeName;
|
|
11197
11203
|
return {
|
|
11198
11204
|
attributeName,
|
|
@@ -11200,7 +11206,7 @@ const toSchemaAttribute = (description, source, idAttribute) => {
|
|
|
11200
11206
|
type: source?.type ?? description?.type ?? DEFAULT_ATTRIBUTE_TYPE,
|
|
11201
11207
|
alias: description?.alias ?? source?.alias ?? attributeName,
|
|
11202
11208
|
description: description?.description ?? source?.description,
|
|
11203
|
-
isEditable: resolveIsEditable(
|
|
11209
|
+
isEditable: resolveIsEditable(params),
|
|
11204
11210
|
stringFormat: resolveStringFormat(description, source),
|
|
11205
11211
|
};
|
|
11206
11212
|
};
|
|
@@ -11211,15 +11217,20 @@ const toSchemaAttribute = (description, source, idAttribute) => {
|
|
|
11211
11217
|
* `alias`, `stringFormat` и `isEditable`, тогда как типы приходят от источника. Без описания
|
|
11212
11218
|
* берутся все атрибуты источника. Без источника описание — единственная схема, и оно обязательно.
|
|
11213
11219
|
*/
|
|
11214
|
-
const buildStructuredDataSchema = ({ attributesDescription, attributesConfiguration, }) => {
|
|
11220
|
+
const buildStructuredDataSchema = ({ attributesDescription, attributesConfiguration, canWriteToSource, }) => {
|
|
11215
11221
|
const sourceAttributes = getSourceAttributes(attributesConfiguration);
|
|
11216
11222
|
const { idAttribute } = attributesConfiguration || {};
|
|
11217
11223
|
if (attributesDescription?.length) {
|
|
11218
11224
|
return attributesDescription
|
|
11219
11225
|
.filter(({ attributeName }) => !!attributeName)
|
|
11220
|
-
.map(description => toSchemaAttribute(
|
|
11226
|
+
.map(description => toSchemaAttribute({
|
|
11227
|
+
description,
|
|
11228
|
+
source: sourceAttributes.find(({ attributeName }) => attributeName === description.attributeName),
|
|
11229
|
+
idAttribute,
|
|
11230
|
+
canWriteToSource,
|
|
11231
|
+
}));
|
|
11221
11232
|
}
|
|
11222
|
-
return sourceAttributes.map(source => toSchemaAttribute(
|
|
11233
|
+
return sourceAttributes.map(source => toSchemaAttribute({ source, idAttribute, canWriteToSource }));
|
|
11223
11234
|
};
|
|
11224
11235
|
|
|
11225
11236
|
/**
|
|
@@ -11227,14 +11238,22 @@ const buildStructuredDataSchema = ({ attributesDescription, attributesConfigurat
|
|
|
11227
11238
|
*
|
|
11228
11239
|
* Источник резолвится через общий `useRelatedDataSourceAttributes`: он собирает layerInfo
|
|
11229
11240
|
* реального слоя, а для EQL/python-источников — синтетический из атрибутов ответа.
|
|
11241
|
+
*
|
|
11242
|
+
* `layerName` берётся из конфига страницы, а не из загруженного источника: от него зависит,
|
|
11243
|
+
* какие ячейки редактируемы, и до окончания загрузки схема не должна меняться.
|
|
11230
11244
|
*/
|
|
11231
11245
|
const useStructuredDataSchema = (type, elementConfig) => {
|
|
11232
11246
|
const { dataSources } = useWidgetContext(type);
|
|
11233
11247
|
const { attributesDescription, relatedDataSource } = elementConfig?.options || {};
|
|
11234
|
-
const { layerInfo, dataSource } = useRelatedDataSourceAttributes({
|
|
11248
|
+
const { layerInfo, dataSource, configDataSource } = useRelatedDataSourceAttributes({
|
|
11249
|
+
type,
|
|
11250
|
+
elementConfig,
|
|
11251
|
+
dataSources,
|
|
11252
|
+
});
|
|
11253
|
+
const layerName = configDataSource?.layerName;
|
|
11235
11254
|
const attributesConfiguration = useMemo(() => (relatedDataSource ? getAttributesConfiguration(layerInfo) : undefined), [layerInfo, relatedDataSource]);
|
|
11236
|
-
const schema = useMemo(() => buildStructuredDataSchema({ attributesDescription, attributesConfiguration }), [attributesDescription, attributesConfiguration]);
|
|
11237
|
-
return { schema, dataSource };
|
|
11255
|
+
const schema = useMemo(() => buildStructuredDataSchema({ attributesDescription, attributesConfiguration, canWriteToSource: !!layerName }), [attributesDescription, attributesConfiguration, layerName]);
|
|
11256
|
+
return { schema, dataSource, layerName };
|
|
11238
11257
|
};
|
|
11239
11258
|
|
|
11240
11259
|
/**
|
|
@@ -11243,14 +11262,14 @@ const useStructuredDataSchema = (type, elementConfig) => {
|
|
|
11243
11262
|
* Правку открывает `options.editMode`: не задан или `false` — таблица целиком на чтение, без
|
|
11244
11263
|
* редакторов ячеек, добавления, удаления и кнопок сохранения.
|
|
11245
11264
|
*
|
|
11246
|
-
*
|
|
11247
|
-
*
|
|
11248
|
-
*
|
|
11265
|
+
* Вид источника на права правки не влияет — от него зависит только адресат «Сохранить». Слой
|
|
11266
|
+
* принимает запись через features-API, источник без `layerName` (EQL, python-скрипт, внешний
|
|
11267
|
+
* url) не принимает ничего, и правка такой таблицы уходит только в фильтр.
|
|
11249
11268
|
*/
|
|
11250
11269
|
const useStructuredData = (type, elementConfig) => {
|
|
11251
11270
|
const { filters } = useWidgetContext(type);
|
|
11252
11271
|
const { relatedDataSource, filterName, editMode } = elementConfig?.options || {};
|
|
11253
|
-
const { schema, dataSource } = useStructuredDataSchema(type, elementConfig);
|
|
11272
|
+
const { schema, dataSource, layerName } = useStructuredDataSchema(type, elementConfig);
|
|
11254
11273
|
const hasDataSource = !!relatedDataSource;
|
|
11255
11274
|
const filterValue = filterName ? filters?.[filterName]?.value : undefined;
|
|
11256
11275
|
const { rows, visibleRows, dirty, changeCell, addRow, deleteRow, reset, commitSaved } = useStructuredDataDraft({
|
|
@@ -11262,14 +11281,13 @@ const useStructuredData = (type, elementConfig) => {
|
|
|
11262
11281
|
const { save, saving } = useStructuredDataSave({
|
|
11263
11282
|
type,
|
|
11264
11283
|
schema,
|
|
11265
|
-
layerName
|
|
11284
|
+
layerName,
|
|
11266
11285
|
filterName,
|
|
11267
11286
|
});
|
|
11268
11287
|
const [deletingKey, setDeletingKey] = useState(null);
|
|
11269
11288
|
const loading = hasDataSource && (!dataSource || dataSource.features === undefined);
|
|
11270
11289
|
const hasError = hasDataSource && dataSource?.features === null;
|
|
11271
11290
|
const canEdit = !!editMode;
|
|
11272
|
-
const canEditRows = canEdit && (!hasDataSource || !!dataSource?.layerName);
|
|
11273
11291
|
const onSave = useCallback(async () => {
|
|
11274
11292
|
const savedRows = await save(rows);
|
|
11275
11293
|
if (savedRows) {
|
|
@@ -11278,7 +11296,9 @@ const useStructuredData = (type, elementConfig) => {
|
|
|
11278
11296
|
}, [commitSaved, rows, save]);
|
|
11279
11297
|
const onRowDelete = useCallback((key) => setDeletingKey(key), []);
|
|
11280
11298
|
const onDeleteCancel = useCallback(() => setDeletingKey(null), []);
|
|
11281
|
-
|
|
11299
|
+
// Про необратимость предупреждаем только там, где удаление и правда дойдёт до источника:
|
|
11300
|
+
// у строки источника без записи id есть, но удаление уберёт её лишь из значения фильтра.
|
|
11301
|
+
const isDeletingSourceRow = useMemo(() => !!layerName && !!rows.find(({ key }) => key === deletingKey)?.featureId, [deletingKey, layerName, rows]);
|
|
11282
11302
|
const onDeleteConfirm = useCallback(() => {
|
|
11283
11303
|
if (deletingKey) {
|
|
11284
11304
|
deleteRow(deletingKey);
|
|
@@ -11290,10 +11310,9 @@ const useStructuredData = (type, elementConfig) => {
|
|
|
11290
11310
|
rows: visibleRows,
|
|
11291
11311
|
loading,
|
|
11292
11312
|
canEdit,
|
|
11293
|
-
canDeleteRows: canEditRows,
|
|
11294
11313
|
onCellChange: changeCell,
|
|
11295
11314
|
onRowDelete,
|
|
11296
|
-
}), [canEdit,
|
|
11315
|
+
}), [canEdit, changeCell, loading, onRowDelete, schema, visibleRows]);
|
|
11297
11316
|
return {
|
|
11298
11317
|
contextValue,
|
|
11299
11318
|
dirty,
|
|
@@ -11301,7 +11320,6 @@ const useStructuredData = (type, elementConfig) => {
|
|
|
11301
11320
|
loading,
|
|
11302
11321
|
hasError,
|
|
11303
11322
|
canEdit,
|
|
11304
|
-
canAddRows: canEditRows,
|
|
11305
11323
|
isDeleteConfirmOpen: !!deletingKey,
|
|
11306
11324
|
isDeletingSourceRow,
|
|
11307
11325
|
onAddRow: addRow,
|
|
@@ -11322,11 +11340,11 @@ const useStructuredData = (type, elementConfig) => {
|
|
|
11322
11340
|
const StructuredDataContainer = memo(({ type, elementConfig, isVisible, renderElement }) => {
|
|
11323
11341
|
const { t } = useGlobalContext();
|
|
11324
11342
|
const { root, body } = useContainerRoot({ elementConfig });
|
|
11325
|
-
const { contextValue, dirty, saving, hasError, canEdit,
|
|
11343
|
+
const { contextValue, dirty, saving, hasError, canEdit, isDeleteConfirmOpen, isDeletingSourceRow, onAddRow, onCancel, onSave, onDeleteConfirm, onDeleteCancel, } = useStructuredData(type, elementConfig);
|
|
11326
11344
|
if (hasError) {
|
|
11327
11345
|
return jsx(DataSourceError, { name: elementConfig?.templateName });
|
|
11328
11346
|
}
|
|
11329
|
-
return (jsxs(ContainerRoot, { ...root, children: [jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxs(Container, { ...body, isColumn: true, children: [jsx(StructuredDataView, { children: jsx(StructuredDataContext.Provider, { value: contextValue, children: renderElement({ id: "data" }) }) }), canEdit && (jsxs(StructuredDataToolbar, { children: [jsx(StructuredDataActions, { children:
|
|
11347
|
+
return (jsxs(ContainerRoot, { ...root, children: [jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && (jsxs(Container, { ...body, isColumn: true, children: [jsx(StructuredDataView, { children: jsx(StructuredDataContext.Provider, { value: contextValue, children: renderElement({ id: "data" }) }) }), canEdit && (jsxs(StructuredDataToolbar, { children: [jsx(StructuredDataActions, { children: jsx(IconButton, { kind: "plus", primary: true, disabled: saving, onClick: onAddRow, children: t("structuredData.addRow", { ns: "dashboard", defaultValue: "Добавить строку" }) }) }), dirty && (jsxs(StructuredDataActions, { children: [jsx(FlatButton, { disabled: saving, onClick: onCancel, children: t("actions.cancel", { ns: "common", defaultValue: "Отменить" }) }), jsx(RaisedButton, { primary: true, disabled: saving, onClick: onSave, children: t("actions.save", { ns: "common", defaultValue: "Сохранить" }) })] }))] }))] })), jsx(DeleteRowDialog, { isOpen: isDeleteConfirmOpen, isSourceRow: isDeletingSourceRow, onConfirm: onDeleteConfirm, onCancel: onDeleteCancel })] }));
|
|
11330
11348
|
});
|
|
11331
11349
|
|
|
11332
11350
|
const TabAnchor = styled.div.withConfig({ displayName: "TabAnchor", componentId: "sc-emqf31" }) `
|
|
@@ -14282,12 +14300,16 @@ const TableWrapper = styled.table.withConfig({ displayName: "TableWrapper", comp
|
|
|
14282
14300
|
border-collapse: collapse;
|
|
14283
14301
|
font-size: 0.875rem;
|
|
14284
14302
|
`;
|
|
14285
|
-
/**
|
|
14303
|
+
/**
|
|
14304
|
+
* Шапка липнет к верху области прокрутки — при длинной таблице заголовки остаются видны.
|
|
14305
|
+
*
|
|
14306
|
+
* Собственного фона у шапки нет: цвет из палитры не следовал за подложкой контейнера
|
|
14307
|
+
* и выделялся белым прямоугольником на любом фоне, отличном от базового.
|
|
14308
|
+
*/
|
|
14286
14309
|
const TableHead = styled.thead.withConfig({ displayName: "TableHead", componentId: "sc-pa89d3" }) `
|
|
14287
14310
|
position: sticky;
|
|
14288
14311
|
top: 0;
|
|
14289
14312
|
z-index: 1;
|
|
14290
|
-
background: ${({ theme }) => theme.palette.background};
|
|
14291
14313
|
`;
|
|
14292
14314
|
const TableHeadCell = styled.th.withConfig({ displayName: "TableHeadCell", componentId: "sc-1f151xj" }) `
|
|
14293
14315
|
padding: 0.375rem 0.5rem;
|
|
@@ -14601,7 +14623,7 @@ const ElementTable = memo(({ elementConfig }) => {
|
|
|
14601
14623
|
defaultValue: "Схема данных не задана",
|
|
14602
14624
|
}) }));
|
|
14603
14625
|
}
|
|
14604
|
-
return (jsxs(TableWrapper, { children: [jsx(TableHead, { children: jsxs("tr", { children: [columns.map(({ attributeName, alias, description }) => (jsx(TableHeadCell, { title: description || alias, "$sortable": sortEnabled, onClick: sortEnabled ? () => onSortToggle(attributeName) : undefined, children: jsxs(TableHeadContent, { children: [alias, sort?.attributeName === attributeName && (jsx(Icon, { kind: sort.direction === "asc" ? "sorting_asc" : "sorting_des" }))] }) }, attributeName))), context.
|
|
14626
|
+
return (jsxs(TableWrapper, { children: [jsx(TableHead, { children: jsxs("tr", { children: [columns.map(({ attributeName, alias, description }) => (jsx(TableHeadCell, { title: description || alias, "$sortable": sortEnabled, onClick: sortEnabled ? () => onSortToggle(attributeName) : undefined, children: jsxs(TableHeadContent, { children: [alias, sort?.attributeName === attributeName && (jsx(Icon, { kind: sort.direction === "asc" ? "sorting_asc" : "sorting_des" }))] }) }, attributeName))), context.canEdit && jsx(TableHeadCell, {})] }) }), jsx("tbody", { children: rows.map(row => (jsxs(TableRow, { children: [columns.map(attribute => (jsx(TableCellWrapper, { children: jsx(TableCell, { attribute: attribute, row: row, canEdit: context.canEdit, onChange: context.onCellChange }) }, attribute.attributeName))), context.canEdit && (jsx(TableActionsCell, { children: jsx(IconButton, { kind: "delete", title: t("actions.delete", { ns: "common", defaultValue: "Удалить" }), onClick: () => context.onRowDelete(row.key) }) }))] }, row.key))) })] }));
|
|
14605
14627
|
});
|
|
14606
14628
|
|
|
14607
14629
|
const TooltipIcon = styled(Icon).withConfig({ displayName: "TooltipIcon", componentId: "sc-1lkxudm" }) `
|
|
@@ -17548,7 +17570,9 @@ const RasterLayer = ({ layer, tileUrl, visible, beforeId, }) => {
|
|
|
17548
17570
|
const VectorLayer = ({ layer, tileUrl, visible, beforeId, getLayerTempStyle, }) => {
|
|
17549
17571
|
const layerConfiguration = layer?.configuration;
|
|
17550
17572
|
const clientStyle = layerConfiguration?.clientStyle;
|
|
17551
|
-
const currentStyle = useMemo(() => getLayerTempStyle(layer.name)
|
|
17573
|
+
const currentStyle = useMemo(() => !isNil(getLayerTempStyle?.(layer.name)) && !isEmpty(getLayerTempStyle?.(layer.name))
|
|
17574
|
+
? getLayerTempStyle(layer.name)
|
|
17575
|
+
: clientStyle, [clientStyle, getLayerTempStyle, layer.name]);
|
|
17552
17576
|
const idAttribute = layerConfiguration?.attributesConfiguration?.idAttribute;
|
|
17553
17577
|
const tiles = useMemo(() => [tileUrl], [tileUrl]);
|
|
17554
17578
|
// Собираем конфигурации иконок для загрузки из clientStyle
|
|
@@ -17561,8 +17585,19 @@ const VectorLayer = ({ layer, tileUrl, visible, beforeId, getLayerTempStyle, })
|
|
|
17561
17585
|
return [];
|
|
17562
17586
|
}
|
|
17563
17587
|
return iconNames.map(name => {
|
|
17564
|
-
|
|
17565
|
-
|
|
17588
|
+
const customIcon = currentStyle.icons?.find((icon) => icon.name === name);
|
|
17589
|
+
if (customIcon) {
|
|
17590
|
+
return {
|
|
17591
|
+
name: customIcon.name,
|
|
17592
|
+
url: customIcon.url,
|
|
17593
|
+
sdf: customIcon.sdf,
|
|
17594
|
+
size: customIcon.size,
|
|
17595
|
+
pixelRatio: customIcon.pixelRatio,
|
|
17596
|
+
};
|
|
17597
|
+
}
|
|
17598
|
+
// Fallback - иконка не найдена в конфиге, пропускаем
|
|
17599
|
+
return null;
|
|
17600
|
+
}).filter((config) => config !== null);
|
|
17566
17601
|
}, [currentStyle]);
|
|
17567
17602
|
useMapImages({ images: iconConfigs });
|
|
17568
17603
|
const renderClientStyle = useCallback(() => {
|