@evergis/react 4.0.30 → 4.0.32

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,2 @@
1
+ import { SelectedFilters } from '../../../types';
2
+ export declare const buildFiltersFromResponse: (responseFilters: Record<string, string> | undefined, result: Record<string, unknown> | null) => SelectedFilters | null;
@@ -1 +1 @@
1
- export declare const ModalIcon: import('styled-components').StyledComponent<"span", any, import('@evergis/uilib-gl').IIconProps, never>;
1
+ export declare const ModalIcon: import('styled-components').StyledComponent<import('react').FC<import('@evergis/uilib-gl').IIconButtonProps>, any, {}, never>;
@@ -149,6 +149,7 @@ export interface ConfigOptions {
149
149
  tabId?: string;
150
150
  column?: boolean;
151
151
  relatedDataSource?: string;
152
+ responseFilters?: Record<string, string>;
152
153
  control?: ConfigControl;
153
154
  controls?: ConfigControl[];
154
155
  filterName?: string;
@@ -1,4 +1,5 @@
1
1
  export declare const SERVER_NOTIFICATION_EVENT: {
2
2
  ReceiveFeaturesUpdate: string;
3
3
  PythonProgressNotification: string;
4
+ PythonSandboxStats: string;
4
5
  };
@@ -1,3 +1,4 @@
1
1
  export * from './constants';
2
2
  export * from './usePythonTask';
3
+ export * from './usePythonSandbox';
3
4
  export * from './types';
@@ -1,7 +1,7 @@
1
1
  import { RemoteTaskStatus } from '@evergis/api';
2
2
  export interface PythonTaskProgressSubscription {
3
3
  tag: "python_task_progress_event";
4
- taskId: string;
4
+ resourceId: string;
5
5
  }
6
6
  export interface PythonTaskProgressNotification {
7
7
  data: {
@@ -14,3 +14,7 @@ export interface PythonTaskProgressNotification {
14
14
  tag: string;
15
15
  createdAt: string;
16
16
  }
17
+ export interface PythonSandbox {
18
+ path: string;
19
+ sandboxId: string;
20
+ }
@@ -0,0 +1,7 @@
1
+ import { PythonSandbox } from './types';
2
+ export declare const usePythonSandbox: () => {
3
+ preparePythonSandbox: ({ resourceId, isNotebook }: {
4
+ resourceId: string;
5
+ isNotebook?: boolean;
6
+ }) => Promise<PythonSandbox>;
7
+ };
@@ -17,4 +17,5 @@ export declare const usePythonTask: () => {
17
17
  executionTime: number;
18
18
  isLogDialogOpen: boolean;
19
19
  closeLog: () => void;
20
+ result: Record<string, unknown>;
20
21
  };
package/dist/index.js CHANGED
@@ -5392,11 +5392,23 @@ const useServerNotificationsContext = () => {
5392
5392
  const SERVER_NOTIFICATION_EVENT = {
5393
5393
  ReceiveFeaturesUpdate: "ReceiveFeaturesUpdateNotification",
5394
5394
  PythonProgressNotification: "ReceivePythonProgressNotification",
5395
+ PythonSandboxStats: "ReceivePythonSandboxStatsNotification",
5396
+ };
5397
+
5398
+ const usePythonSandbox = () => {
5399
+ const { api } = useGlobalContext();
5400
+ const preparePythonSandbox = React.useCallback(({ resourceId, isNotebook = false }) => api.remoteTaskManager.post({
5401
+ workerType: "pythonService",
5402
+ methodType: "pythonrunner/prepare",
5403
+ data: { resourceId, isNotebook },
5404
+ }), [api.remoteTaskManager]);
5405
+ return { preparePythonSandbox };
5395
5406
  };
5396
5407
 
5397
5408
  const usePythonTask = () => {
5398
5409
  const { api: api$1, t } = useGlobalContext();
5399
5410
  const { addSubscription, connection, unsubscribeById } = useServerNotificationsContext();
5411
+ const { preparePythonSandbox } = usePythonSandbox();
5400
5412
  const [status, setStatus] = React.useState(api.RemoteTaskStatus.Unknown);
5401
5413
  const [log, setLog] = React.useState(null);
5402
5414
  const [error, setError] = React.useState(null);
@@ -5405,6 +5417,7 @@ const usePythonTask = () => {
5405
5417
  const [taskId, setTaskId] = React.useState(null);
5406
5418
  const [subscriptionId, setSubscriptionId] = React.useState(null);
5407
5419
  const [isLogDialogOpen, setIsLogDialogOpen] = React.useState(false);
5420
+ const [result, setResult] = React.useState(null);
5408
5421
  const logRef = React.useRef(null);
5409
5422
  const reset = React.useCallback(() => {
5410
5423
  setStatus(api.RemoteTaskStatus.Unknown);
@@ -5413,6 +5426,7 @@ const usePythonTask = () => {
5413
5426
  setExecutionTime(null);
5414
5427
  setTaskId(null);
5415
5428
  setSubscriptionId(null);
5429
+ setResult(null);
5416
5430
  }, []);
5417
5431
  const runTask = React.useCallback(async ({ resourceId, parameters, script, fileName, methodName, }) => {
5418
5432
  reset();
@@ -5439,6 +5453,7 @@ const usePythonTask = () => {
5439
5453
  ],
5440
5454
  });
5441
5455
  prototypeId = prototypeId.replace(/["']+/g, "");
5456
+ await preparePythonSandbox({ resourceId });
5442
5457
  const { id: newTaskId, success } = await api$1.remoteTaskManager.startTask1(prototypeId);
5443
5458
  if (!success) {
5444
5459
  setStatus(api.RemoteTaskStatus.Error);
@@ -5448,30 +5463,31 @@ const usePythonTask = () => {
5448
5463
  }
5449
5464
  const newSubscriptionId = await addSubscription({
5450
5465
  tag: "python_task_progress_event",
5451
- taskId: newTaskId,
5466
+ resourceId,
5452
5467
  });
5453
5468
  setTaskId(newTaskId);
5454
5469
  setSubscriptionId(newSubscriptionId);
5455
- const onNotification = ({ data }) => {
5470
+ const onNotification = async ({ data }) => {
5456
5471
  if (data?.taskId === newTaskId) {
5472
+ const isFinished = [api.RemoteTaskStatus.Completed, api.RemoteTaskStatus.Error].includes(data.status);
5457
5473
  setStatus(data.status);
5458
5474
  setLog([logRef.current, data.log].filter(Boolean).join("\n"));
5459
5475
  setExecutionTime(Date.now() - start);
5460
5476
  setLoading(false);
5461
- setTaskId([api.RemoteTaskStatus.Completed, api.RemoteTaskStatus.Error].includes(data.status)
5462
- ? null
5463
- : newTaskId);
5464
- setSubscriptionId([api.RemoteTaskStatus.Completed, api.RemoteTaskStatus.Error].includes(data.status)
5465
- ? null
5466
- : newSubscriptionId);
5467
- if ([api.RemoteTaskStatus.Completed, api.RemoteTaskStatus.Error].includes(data.status)) {
5477
+ setTaskId(isFinished ? null : newTaskId);
5478
+ setSubscriptionId(isFinished ? null : newSubscriptionId);
5479
+ if (isFinished) {
5468
5480
  unsubscribeById(newSubscriptionId);
5469
5481
  connection.off(SERVER_NOTIFICATION_EVENT.PythonProgressNotification, onNotification);
5470
5482
  }
5483
+ if (data.status === api.RemoteTaskStatus.Completed) {
5484
+ const subTasks = await api$1.remoteTaskManager.get(newTaskId);
5485
+ setResult(subTasks?.[0]?.results?.response ?? null);
5486
+ }
5471
5487
  }
5472
5488
  };
5473
5489
  connection.on(SERVER_NOTIFICATION_EVENT.PythonProgressNotification, onNotification);
5474
- }, [api$1, connection, addSubscription, unsubscribeById, reset]);
5490
+ }, [reset, api$1, preparePythonSandbox, addSubscription, connection, t, unsubscribeById]);
5475
5491
  const stopTask = React.useCallback(async () => {
5476
5492
  await api$1.remoteTaskManager.stop(taskId);
5477
5493
  reset();
@@ -5498,6 +5514,7 @@ const usePythonTask = () => {
5498
5514
  executionTime,
5499
5515
  isLogDialogOpen,
5500
5516
  closeLog,
5517
+ result,
5501
5518
  };
5502
5519
  };
5503
5520
 
@@ -7468,14 +7485,35 @@ const StatusWaitingButton = ({ title, icon = "play", status, statusColors, isWai
7468
7485
  return (jsxRuntime.jsx(uilibGl.ThemeProvider, { theme: uilibGl.darkTheme, children: jsxRuntime.jsxs(StyledButton, { status: status, statusColors: statusColors, disabled: isDisabled, themeName: themeName, onClick: onClick, children: [renderIcon, renderTitle] }) }));
7469
7486
  };
7470
7487
 
7488
+ const buildFiltersFromResponse = (responseFilters, result) => {
7489
+ if (!responseFilters || !result)
7490
+ return null;
7491
+ const properties = result?.result?.features?.[0]?.properties;
7492
+ if (!properties)
7493
+ return null;
7494
+ const filters = Object.entries(responseFilters).reduce((acc, [filterName, token]) => {
7495
+ const attrName = typeof token === "string" && token.startsWith("%") ? token.slice(1) : token;
7496
+ const value = properties[attrName];
7497
+ if (value === undefined)
7498
+ return acc;
7499
+ return { ...acc, [filterName]: { value: value } };
7500
+ }, {});
7501
+ return Object.keys(filters).length ? filters : null;
7502
+ };
7503
+
7471
7504
  const TaskContainer = React.memo(({ type, elementConfig, renderElement }) => {
7472
7505
  const { t, ewktGeometry } = useGlobalContext();
7473
- const { dataSources, filters: selectedFilters, attributes, layerInfo } = useWidgetContext(type);
7506
+ const { dataSources, filters: selectedFilters, attributes, layerInfo, changeFilters, } = useWidgetContext(type);
7474
7507
  const { dataSources: projectDataSources } = useWidgetContext(exports.WidgetType.Dashboard);
7475
7508
  const { currentPage } = useWidgetPage(type);
7476
- const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, log } = usePythonTask();
7509
+ const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, log, result, } = usePythonTask();
7477
7510
  const { options } = elementConfig || {};
7478
- const { title, relatedResources, center, icon, statusColors } = options || {};
7511
+ const { title, relatedResources, center, icon, statusColors, responseFilters } = options || {};
7512
+ React.useEffect(() => {
7513
+ const filtersToApply = buildFiltersFromResponse(responseFilters, result);
7514
+ if (filtersToApply)
7515
+ changeFilters(filtersToApply);
7516
+ }, [result, responseFilters, changeFilters]);
7479
7517
  const onClick = React.useCallback(async () => {
7480
7518
  if (taskId) {
7481
7519
  await stopTask();
@@ -7522,6 +7560,12 @@ const EditGroupContainer = React.memo(({ type, elementConfig, renderElement }) =
7522
7560
  const getRenderContainerItem = useRenderContainerItem(type, renderElement);
7523
7561
  const { options } = elementConfig || {};
7524
7562
  const { controls } = options || {};
7563
+ const filteredAttributes = React.useMemo(() => {
7564
+ const { idAttribute } = layerInfo?.configuration?.attributesConfiguration || {};
7565
+ if (!idAttribute)
7566
+ return attributes;
7567
+ return attributes.filter(({ attributeName }) => attributeName !== idAttribute);
7568
+ }, [attributes, layerInfo?.configuration]);
7525
7569
  const renderContainer = React.useCallback((attributeName) => {
7526
7570
  const control = controls?.find(({ targetAttributeName }) => targetAttributeName === attributeName);
7527
7571
  const itemAttribute = attributes.find(item => item.attributeName === attributeName);
@@ -7554,7 +7598,7 @@ const EditGroupContainer = React.memo(({ type, elementConfig, renderElement }) =
7554
7598
  expandedContainers,
7555
7599
  ]);
7556
7600
  if (!controls?.length) {
7557
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: attributes.map(({ attributeName }) => renderContainer(attributeName)) }));
7601
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: filteredAttributes.map(({ attributeName }) => renderContainer(attributeName)) }));
7558
7602
  }
7559
7603
  return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: controls.map(({ targetAttributeName }) => renderContainer(targetAttributeName)) }));
7560
7604
  });
@@ -7585,6 +7629,16 @@ const useEditControl = (type, elementConfig) => {
7585
7629
  [attributeName]: newValue,
7586
7630
  });
7587
7631
  }, [changeControls, attributeName]);
7632
+ React.useEffect(() => {
7633
+ if (control?.defaultValue === undefined)
7634
+ return;
7635
+ if (controls[attributeName] !== undefined)
7636
+ return;
7637
+ const hasAttributeValue = attributes.some(({ attributeName: name, value: attrValue }) => name === attributeName && attrValue !== undefined && attrValue !== null);
7638
+ if (hasAttributeValue)
7639
+ return;
7640
+ changeControls({ [attributeName]: control.defaultValue });
7641
+ }, [attributeName, attributes, changeControls, control?.defaultValue, controls]);
7588
7642
  return React.useMemo(() => ({ control, value, dataSource, items, onChange }), [control, value, dataSource, items, onChange]);
7589
7643
  };
7590
7644
 
@@ -7720,7 +7774,7 @@ const DefaultHeaderContainer = styled(uilibGl.Flex) `
7720
7774
  position: relative;
7721
7775
  flex-shrink: 0;
7722
7776
  min-height: 8.175rem;
7723
- margin-bottom: -1.5rem;
7777
+ margin-bottom: -0.75rem;
7724
7778
  padding: 1.5rem 1.5rem 0;
7725
7779
  border-top-left-radius: 0.5rem;
7726
7780
  border-top-right-radius: 0.5rem;
@@ -9270,19 +9324,15 @@ const ElementUploader = React.memo(({ elementConfig, type }) => {
9270
9324
  return (jsxRuntime.jsx(UploaderContainer, { id: id, style: style, children: jsxRuntime.jsx("div", { children: jsxRuntime.jsx(uilibGl.Uploader, { currentRef: refInput, title: renderTitle, accept: fileExtensions, width: "100%", fileItems: files, isMultiple: multiSelect, onUpload: onUpload, onDelete: onDelete }) }) }));
9271
9325
  });
9272
9326
 
9273
- const ModalIcon = styled(uilibGl.Icon) `
9274
- &&& {
9275
- cursor: pointer;
9276
-
9277
- :after {
9278
- font-size: 0.75rem;
9279
- color: ${({ theme: { palette } }) => palette.iconDisabled};
9280
- transition: color ${uilibGl.transition.hover};
9281
- }
9327
+ const ModalIcon = styled(uilibGl.IconButton) `
9328
+ :after {
9329
+ font-size: 0.75rem;
9330
+ color: ${({ theme: { palette } }) => palette.iconDisabled};
9331
+ transition: color ${uilibGl.transition.hover};
9332
+ }
9282
9333
 
9283
- :hover:after {
9284
- color: ${({ theme: { palette } }) => palette.icon};
9285
- }
9334
+ :hover:after {
9335
+ color: ${({ theme: { palette } }) => palette.icon};
9286
9336
  }
9287
9337
  `;
9288
9338
 
@@ -9392,7 +9442,7 @@ const ElementModal = React.memo(({ type = exports.WidgetType.Dashboard, elementC
9392
9442
  return null;
9393
9443
  const { options: modalOptions } = modalConfig;
9394
9444
  const { title, maxWidth, minWidth, minHeight } = modalOptions || {};
9395
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ModalIcon, { kind: icon || "new_window", onClick: handleOpen }), jsxRuntime.jsxs(uilibGl.Dialog, { isOpen: isOpen, onCloseRequest: handleClose, modal: true, maxWidth: maxWidth, minWidth: minWidth, minHeight: minHeight, style: { paddingBottom: "2rem" }, children: [jsxRuntime.jsx(uilibGl.DialogTitle, { children: jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: "space-between", alignItems: "center", children: [!!title && jsxRuntime.jsx("span", { children: title }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "close", onClick: handleClose })] }) }), jsxRuntime.jsx(uilibGl.DialogContent, { children: isLoading ? (jsxRuntime.jsx(DashboardLoading, {})) : (jsxRuntime.jsx(Container, { isColumn: true, noBorders: true, children: jsxRuntime.jsx(ContainerChildren, { type: type, items: modalContent, isMain: true, renderElement: renderElement }) })) })] })] }));
9445
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ModalIcon, { kind: icon || "new_window", onClick: handleOpen, children: title }), jsxRuntime.jsxs(uilibGl.Dialog, { maxWidth: maxWidth, minWidth: minWidth, minHeight: minHeight, isOpen: isOpen, modal: true, onCloseRequest: handleClose, style: { paddingBottom: "2rem" }, children: [jsxRuntime.jsx(uilibGl.DialogTitle, { children: jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: "space-between", alignItems: "center", children: [!!title && jsxRuntime.jsx("span", { children: title }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "close", onClick: handleClose })] }) }), jsxRuntime.jsx(uilibGl.DialogContent, { children: isLoading ? (jsxRuntime.jsx(DashboardLoading, {})) : (jsxRuntime.jsx(Container, { isColumn: true, noBorders: true, children: jsxRuntime.jsx(ContainerChildren, { type: type, items: modalContent, isMain: true, renderElement: renderElement }) })) })] })] }));
9396
9446
  });
9397
9447
 
9398
9448
  const ElementLayerName = React.memo(({ type }) => {
@@ -12547,6 +12597,7 @@ exports.useMapContext = useMapContext;
12547
12597
  exports.useMapDraw = useMapDraw;
12548
12598
  exports.useMapImages = useMapImages;
12549
12599
  exports.useProjectDashboardInit = useProjectDashboardInit;
12600
+ exports.usePythonSandbox = usePythonSandbox;
12550
12601
  exports.usePythonTask = usePythonTask;
12551
12602
  exports.useRedrawLayer = useRedrawLayer;
12552
12603
  exports.useRelatedDataSourceAttributes = useRelatedDataSourceAttributes;