@evergis/react 3.1.67 → 3.1.69

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.
@@ -1,4 +1,6 @@
1
1
  import { RemoteTaskStatus } from '@evergis/api';
2
+ import { IconTypesKeys } from '@evergis/uilib-gl';
2
3
  export declare const STATUS_TRANSLATION_KEYS: Partial<Record<RemoteTaskStatus, string>>;
3
- export declare const STATUS_DEFAULT_VALUES: Partial<Record<RemoteTaskStatus, string>>;
4
+ export declare const STATUS_TITLES: Partial<Record<RemoteTaskStatus, string>>;
4
5
  export declare const STATUS_COLORS: Partial<Record<RemoteTaskStatus, string>>;
6
+ export declare const STATUS_ICONS: Partial<Record<RemoteTaskStatus, IconTypesKeys>>;
@@ -1,4 +1,3 @@
1
- export declare const StatusBadge: import('styled-components').StyledComponent<"div", any, import('@evergis/uilib-gl').FlexProps & {
2
- $statusColor: string;
1
+ export declare const StatusBadge: import('styled-components').StyledComponent<import('react').FC<import('@evergis/uilib-gl').IChipProps>, any, {
2
+ bgColor?: string;
3
3
  }, never>;
4
- export declare const LogContainer: import('styled-components').StyledComponent<"div", any, {}, never>;
@@ -0,0 +1,6 @@
1
+ import { FC } from 'react';
2
+ interface TaskLogTerminalProps {
3
+ log?: string | Record<string, any>;
4
+ }
5
+ export declare const LogTerminal: FC<TaskLogTerminalProps>;
6
+ export {};
@@ -0,0 +1 @@
1
+ export declare const TerminalWrapper: import('styled-components').StyledComponent<"div", any, {}, never>;
@@ -0,0 +1,12 @@
1
+ import { FC } from 'react';
2
+ import { RemoteTaskStatus } from '@evergis/api';
3
+ import { IconTypesKeys } from '@evergis/uilib-gl';
4
+ export declare const StatusWaitingButton: FC<{
5
+ title: string;
6
+ icon: IconTypesKeys;
7
+ status: RemoteTaskStatus;
8
+ statusColors: Record<RemoteTaskStatus, string>;
9
+ isWaiting: boolean;
10
+ isDisabled: boolean;
11
+ onClick: VoidFunction;
12
+ }>;
@@ -0,0 +1,5 @@
1
+ import { RemoteTaskStatus } from '@evergis/api';
2
+ export declare const StyledButton: import('styled-components').StyledComponent<"button", any, import('@evergis/uilib-gl').IButtonProps & {
3
+ status?: RemoteTaskStatus;
4
+ statusColors?: Record<RemoteTaskStatus, string>;
5
+ }, never>;
@@ -3,7 +3,7 @@ import { Projection } from 'mapbox-gl';
3
3
  import { i18n } from 'i18next';
4
4
  import { AttributeDefinitionDc, AttributeFormatDefinitionDc, AttributeType, EqlRequestDc, FeatureDc, GeometryType, PagedFeaturesListDc, PositionDc, RemoteTaskStatus, StringSubType } from '@evergis/api';
5
5
  import { PieChartData, BarChartMarker } from '@evergis/charts';
6
- import { IOption } from '@evergis/uilib-gl';
6
+ import { IconTypesKeys, IOption } from '@evergis/uilib-gl';
7
7
  import { FeatureAttributeValue, EditGeometryType, LayerInfo, ThemeName } from '../../types';
8
8
  import { InnerContainerProps } from './containers/DataSourceInnerContainer/types';
9
9
  export interface DashboardsProps {
@@ -115,7 +115,7 @@ export interface ConfigOptions {
115
115
  expanded?: boolean;
116
116
  expandLength?: number;
117
117
  wrap?: boolean;
118
- icon?: string;
118
+ icon?: IconTypesKeys;
119
119
  iconUrl?: string;
120
120
  big?: boolean;
121
121
  bigIcon?: boolean;
@@ -10,7 +10,7 @@ export declare const usePythonTask: () => {
10
10
  }) => Promise<void>;
11
11
  stopTask: () => Promise<void>;
12
12
  openLog: () => void;
13
- result: string;
13
+ log: string;
14
14
  error: Error;
15
15
  status: RemoteTaskStatus;
16
16
  loading: boolean;
package/dist/index.js CHANGED
@@ -24,6 +24,9 @@ require('mapbox-gl/dist/mapbox-gl.css');
24
24
  var react = require('swiper/react');
25
25
  var ReactMarkdown = require('react-markdown');
26
26
  var remarkGfm = require('remark-gfm');
27
+ var xterm = require('@xterm/xterm');
28
+ var addonFit = require('@xterm/addon-fit');
29
+ require('@xterm/xterm/css/xterm.css');
27
30
 
28
31
  const AddFeatureButton = ({ title, icon = "feature_add" /* , layerName, geometryType*/ }) => {
29
32
  // const [, handleAddFeature] = useFeatureCreator(layerName, geometryType);
@@ -4828,14 +4831,14 @@ const usePythonTask = () => {
4828
4831
  const { api: api$1, t } = useGlobalContext();
4829
4832
  const { addSubscription, connection, unsubscribeById } = useServerNotificationsContext();
4830
4833
  const [status, setStatus] = React.useState(api.RemoteTaskStatus.Unknown);
4831
- const [result, setResult] = React.useState(null);
4834
+ const [log, setLog] = React.useState(null);
4832
4835
  const [error, setError] = React.useState(null);
4833
4836
  const [loading, setLoading] = React.useState(false);
4834
4837
  const [executionTime, setExecutionTime] = React.useState(null);
4835
4838
  const [taskId, setTaskId] = React.useState(null);
4836
4839
  const [subscriptionId, setSubscriptionId] = React.useState(null);
4837
4840
  const [isLogDialogOpen, setIsLogDialogOpen] = React.useState(false);
4838
- const resultRef = React.useRef(null);
4841
+ const logRef = React.useRef(null);
4839
4842
  const reset = React.useCallback(() => {
4840
4843
  setStatus(api.RemoteTaskStatus.Unknown);
4841
4844
  setError(null);
@@ -4847,7 +4850,7 @@ const usePythonTask = () => {
4847
4850
  const runTask = React.useCallback(async ({ resourceId, parameters, script, fileName, methodName, }) => {
4848
4851
  reset();
4849
4852
  setStatus(api.RemoteTaskStatus.Process);
4850
- setResult(null);
4853
+ setLog(null);
4851
4854
  setLoading(true);
4852
4855
  const start = Date.now();
4853
4856
  let prototypeId = await api$1.remoteTaskManager.createTaskPrototype({
@@ -4872,7 +4875,7 @@ const usePythonTask = () => {
4872
4875
  const { id: newTaskId, success } = await api$1.remoteTaskManager.startTask1(prototypeId);
4873
4876
  if (!success) {
4874
4877
  setStatus(api.RemoteTaskStatus.Error);
4875
- setResult(t("taskRunFail", { ns: "devMode", defaultValue: "Не удалось запустить задачу" }));
4878
+ setLog(t("taskRunFail", { ns: "devMode", defaultValue: "Не удалось запустить задачу" }));
4876
4879
  setExecutionTime(Date.now() - start);
4877
4880
  setLoading(false);
4878
4881
  }
@@ -4885,15 +4888,14 @@ const usePythonTask = () => {
4885
4888
  const onNotification = ({ data }) => {
4886
4889
  if (data?.taskId === newTaskId) {
4887
4890
  setStatus(data.status);
4888
- setResult([data.log, resultRef.current].filter(Boolean).join("\n\n"));
4889
- setError(null);
4891
+ setLog([logRef.current, data.log].filter(Boolean).join("\n\n"));
4890
4892
  setExecutionTime(Date.now() - start);
4891
4893
  setLoading(false);
4892
4894
  setTaskId([api.RemoteTaskStatus.Completed, api.RemoteTaskStatus.Error].includes(data.status)
4893
- ? undefined
4895
+ ? null
4894
4896
  : newTaskId);
4895
4897
  setSubscriptionId([api.RemoteTaskStatus.Completed, api.RemoteTaskStatus.Error].includes(data.status)
4896
- ? undefined
4898
+ ? null
4897
4899
  : newSubscriptionId);
4898
4900
  if ([api.RemoteTaskStatus.Completed, api.RemoteTaskStatus.Error].includes(data.status)) {
4899
4901
  unsubscribeById(newSubscriptionId);
@@ -4915,14 +4917,14 @@ const usePythonTask = () => {
4915
4917
  setIsLogDialogOpen(false);
4916
4918
  }, []);
4917
4919
  React.useEffect(() => {
4918
- resultRef.current = result;
4919
- }, [result]);
4920
+ logRef.current = log;
4921
+ }, [log]);
4920
4922
  return {
4921
4923
  taskId,
4922
4924
  runTask,
4923
4925
  stopTask,
4924
4926
  openLog,
4925
- result,
4927
+ log,
4926
4928
  error,
4927
4929
  status,
4928
4930
  loading,
@@ -6761,36 +6763,138 @@ const UploadContainer = React.memo(({ type, elementConfig, renderElement }) => {
6761
6763
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && renderElement({ id: "uploader", wrap: false })] }));
6762
6764
  });
6763
6765
 
6764
- const StatusBadge = styled(uilibGl.Flex) `
6765
- margin-bottom: 1rem;
6766
- padding: 0.5rem 1rem;
6767
- background-color: ${({ $statusColor }) => $statusColor};
6766
+ const StatusBadge = styled(uilibGl.Chip) `
6767
+ background-color: ${({ bgColor }) => bgColor};
6768
6768
  color: ${({ theme }) => theme.palette.iconContrast};
6769
- border-radius: 0.25rem;
6770
6769
  `;
6771
- const LogContainer = styled.div `
6770
+
6771
+ const TerminalWrapper = styled.div `
6772
6772
  flex: 1;
6773
- padding: 1rem;
6774
- background-color: ${({ theme }) => theme.palette.element};
6775
- color: ${({ theme }) => theme.palette.textPrimary};
6776
- font-family: monospace;
6777
- font-size: 0.875rem;
6778
- overflow: auto;
6779
- white-space: pre-wrap;
6780
- word-break: break-word;
6781
- border-radius: 0.25rem;
6782
- max-height: 31.25rem;
6773
+ overflow: hidden;
6774
+ padding: 0;
6775
+ margin: 0;
6776
+ box-sizing: border-box;
6777
+ min-height: 0;
6778
+
6779
+ .xterm-viewport {
6780
+ overflow-y: auto;
6781
+ }
6782
+
6783
+ .xterm-screen .xterm-rows span {
6784
+ letter-spacing: 0 !important;
6785
+ }
6783
6786
  `;
6784
6787
 
6788
+ const LogTerminal = ({ log }) => {
6789
+ const terminalRef = React.useRef(null);
6790
+ const xtermRef = React.useRef(null);
6791
+ const fitAddonRef = React.useRef(null);
6792
+ const previousLogRef = React.useRef("");
6793
+ const theme = styled.useTheme();
6794
+ // Initialize terminal
6795
+ React.useEffect(() => {
6796
+ if (!terminalRef.current)
6797
+ return;
6798
+ // Create terminal instance
6799
+ const terminal = new xterm.Terminal({
6800
+ cursorBlink: false,
6801
+ fontSize: 12,
6802
+ fontFamily: '"Nunito Sans", sans-serif',
6803
+ scrollback: 10000,
6804
+ convertEol: true,
6805
+ lineHeight: 1.5,
6806
+ letterSpacing: 0,
6807
+ theme: {
6808
+ background: theme.palette.background,
6809
+ foreground: theme.palette.textPrimary,
6810
+ cursor: theme.palette.primary,
6811
+ },
6812
+ });
6813
+ // Create fit addon
6814
+ const fitAddon = new addonFit.FitAddon();
6815
+ terminal.loadAddon(fitAddon);
6816
+ // Open terminal
6817
+ terminal.open(terminalRef.current);
6818
+ fitAddon.fit();
6819
+ // Store refs
6820
+ xtermRef.current = terminal;
6821
+ fitAddonRef.current = fitAddon;
6822
+ // Handle window resize
6823
+ const handleResize = () => {
6824
+ fitAddon.fit();
6825
+ };
6826
+ window.addEventListener("resize", handleResize);
6827
+ // Cleanup
6828
+ return () => {
6829
+ window.removeEventListener("resize", handleResize);
6830
+ terminal.dispose();
6831
+ xtermRef.current = null;
6832
+ fitAddonRef.current = null;
6833
+ };
6834
+ }, [theme]);
6835
+ // Update log content
6836
+ React.useEffect(() => {
6837
+ if (!xtermRef.current)
6838
+ return;
6839
+ // Handle different log types
6840
+ if (typeof log === "string") {
6841
+ // For string logs, only write the new content (append mode)
6842
+ const previousLog = previousLogRef.current;
6843
+ if (log !== previousLog) {
6844
+ if (log.startsWith(previousLog)) {
6845
+ // Log is accumulated - write only the new part
6846
+ const newContent = log.substring(previousLog.length);
6847
+ xtermRef.current.write(`${newContent.replace(/\n/g, "\r\n")}\r\n`);
6848
+ }
6849
+ else {
6850
+ // Log was replaced completely - clear and write all
6851
+ xtermRef.current.clear();
6852
+ xtermRef.current.write(`${log.replace(/\n/g, "\r\n")}\r\n`);
6853
+ }
6854
+ previousLogRef.current = log;
6855
+ }
6856
+ }
6857
+ else if (typeof log === "object") {
6858
+ // JSON object (results) - always replace
6859
+ xtermRef.current.clear();
6860
+ const formatted = JSON.stringify(log, null, 2);
6861
+ xtermRef.current.write(formatted.replace(/\n/g, "\r\n"));
6862
+ previousLogRef.current = "";
6863
+ }
6864
+ else if (!log) {
6865
+ // No log - clear terminal
6866
+ xtermRef.current.clear();
6867
+ previousLogRef.current = "";
6868
+ }
6869
+ // Scroll to bottom
6870
+ xtermRef.current.scrollToBottom();
6871
+ }, [log]);
6872
+ // Fit terminal on container resize
6873
+ React.useEffect(() => {
6874
+ if (!fitAddonRef.current)
6875
+ return;
6876
+ const resizeObserver = new ResizeObserver(() => {
6877
+ fitAddonRef.current?.fit();
6878
+ });
6879
+ if (terminalRef.current) {
6880
+ resizeObserver.observe(terminalRef.current);
6881
+ }
6882
+ return () => {
6883
+ resizeObserver.disconnect();
6884
+ };
6885
+ }, []);
6886
+ return jsxRuntime.jsx(TerminalWrapper, { ref: terminalRef });
6887
+ };
6888
+
6785
6889
  const STATUS_TRANSLATION_KEYS = {
6786
- [api.RemoteTaskStatus.Process]: "task.status.process",
6787
- [api.RemoteTaskStatus.Completed]: "task.status.completed",
6788
- [api.RemoteTaskStatus.Error]: "task.status.error",
6789
- [api.RemoteTaskStatus.Unknown]: "task.status.unknown",
6790
- };
6791
- const STATUS_DEFAULT_VALUES = {
6792
- [api.RemoteTaskStatus.Process]: "Выполняется...",
6793
- [api.RemoteTaskStatus.Completed]: "Завершено",
6890
+ [api.RemoteTaskStatus.Process]: "taskProcess",
6891
+ [api.RemoteTaskStatus.Completed]: "taskCompleted",
6892
+ [api.RemoteTaskStatus.Error]: "taskError",
6893
+ [api.RemoteTaskStatus.Unknown]: "taskUnknown",
6894
+ };
6895
+ const STATUS_TITLES = {
6896
+ [api.RemoteTaskStatus.Process]: "В процессе",
6897
+ [api.RemoteTaskStatus.Completed]: "Выполнено",
6794
6898
  [api.RemoteTaskStatus.Error]: "Ошибка",
6795
6899
  [api.RemoteTaskStatus.Unknown]: "Неизвестно",
6796
6900
  };
@@ -6800,27 +6904,30 @@ const STATUS_COLORS = {
6800
6904
  [api.RemoteTaskStatus.Error]: "#f44336",
6801
6905
  [api.RemoteTaskStatus.Unknown]: "#757575",
6802
6906
  };
6907
+ const STATUS_ICONS = {
6908
+ [api.RemoteTaskStatus.Process]: "loading_circle",
6909
+ [api.RemoteTaskStatus.Completed]: "success",
6910
+ [api.RemoteTaskStatus.Error]: "error",
6911
+ [api.RemoteTaskStatus.Unknown]: "play",
6912
+ };
6803
6913
 
6804
6914
  const LogDialog = ({ isOpen, onClose, logs, status, statusColors }) => {
6805
6915
  const { t } = useGlobalContext();
6806
- const contentRef = React.useRef(null);
6807
- React.useEffect(() => {
6808
- if (contentRef.current) {
6809
- contentRef.current.scrollTop = 0;
6810
- }
6811
- }, [logs]);
6812
- const getStatusText = React.useCallback((status) => {
6916
+ const getStatusTitle = React.useCallback((status) => {
6813
6917
  const translationKey = STATUS_TRANSLATION_KEYS[status] || STATUS_TRANSLATION_KEYS[api.RemoteTaskStatus.Unknown];
6814
- const defaultValue = STATUS_DEFAULT_VALUES[status] || STATUS_DEFAULT_VALUES[api.RemoteTaskStatus.Unknown];
6918
+ const defaultValue = STATUS_TITLES[status] || STATUS_TITLES[api.RemoteTaskStatus.Unknown];
6815
6919
  return t(translationKey, { ns: "dashboard", defaultValue });
6816
6920
  }, [t]);
6817
6921
  const getStatusColor = React.useCallback((status) => {
6818
6922
  return statusColors?.[status] || STATUS_COLORS[status] || STATUS_COLORS[api.RemoteTaskStatus.Unknown];
6819
6923
  }, [statusColors]);
6820
- return (jsxRuntime.jsxs(uilibGl.Dialog, { isOpen: isOpen, onCloseRequest: onClose, modal: true, maxWidth: "800px", minWidth: "600px", minHeight: "400px", children: [jsxRuntime.jsx(uilibGl.DialogTitle, { children: jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsx("span", { children: t("task.logs.title", { ns: "dashboard", defaultValue: "Логи выполнения задачи" }) }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "close", onClick: onClose })] }) }), jsxRuntime.jsx(uilibGl.DialogContent, { children: jsxRuntime.jsxs(uilibGl.Flex, { flexDirection: "column", height: "100%", marginBottom: "2rem", children: [jsxRuntime.jsxs(StatusBadge, { "$statusColor": getStatusColor(status), children: [t("task.status.label", { ns: "dashboard", defaultValue: "Статус" }), ": ", getStatusText(status)] }), jsxRuntime.jsx(LogContainer, { ref: contentRef, children: logs || t("task.logs.empty", { ns: "dashboard", defaultValue: "Логи отсутствуют" }) })] }) })] }));
6924
+ return (jsxRuntime.jsxs(uilibGl.Dialog, { isOpen: isOpen, onCloseRequest: onClose, modal: true, maxWidth: "800px", minWidth: "600px", minHeight: "600px", children: [jsxRuntime.jsx(uilibGl.DialogTitle, { children: jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsxs(uilibGl.Flex, { alignItems: "center", children: [jsxRuntime.jsx(uilibGl.FlexSpan, { marginRight: "1rem", children: t("taskLogs", { ns: "dashboard", defaultValue: "Логи выполнения задачи" }) }), jsxRuntime.jsx(StatusBadge, { text: getStatusTitle(status), bgColor: getStatusColor(status) })] }), jsxRuntime.jsx(uilibGl.IconButton, { kind: "close", onClick: onClose })] }) }), jsxRuntime.jsx(uilibGl.DialogContent, { children: jsxRuntime.jsx(uilibGl.Flex, { flexDirection: "column", height: "100%", marginBottom: "2rem", children: jsxRuntime.jsx(LogTerminal, { log: logs || t("taskLogsEmpty", { ns: "dashboard", defaultValue: "Логи отсутствуют" }) }) }) })] }));
6821
6925
  };
6822
6926
 
6823
- const StatusWaitingButton = styled(uilibGl.WaitingButton) `
6927
+ const StyledButton = styled(uilibGl.FlatButton) `
6928
+ display: flex;
6929
+ align-items: center;
6930
+
6824
6931
  ${({ status = api.RemoteTaskStatus.Unknown, statusColors }) => !!statusColors?.[status] && styled.css `
6825
6932
  transition: background-color ${uilibGl.transition.toggle};
6826
6933
  background-color: ${statusColors[status]};
@@ -6831,14 +6938,33 @@ const StatusWaitingButton = styled(uilibGl.WaitingButton) `
6831
6938
  `}
6832
6939
  `;
6833
6940
 
6834
- const TaskContainer = React.memo(({ type, elementConfig }) => {
6941
+ const StatusWaitingButton = ({ title, icon = "play", status, statusColors, isWaiting, isDisabled, onClick }) => {
6942
+ const { t } = useGlobalContext();
6943
+ const renderTitle = React.useMemo(() => status === api.RemoteTaskStatus.Process
6944
+ ? t("", { ns: "dashboard", defaultValue: "Остановить" })
6945
+ : status === api.RemoteTaskStatus.Unknown ? title : STATUS_TITLES[status], [status, t, title]);
6946
+ const renderIcon = React.useMemo(() => {
6947
+ const iconComponent = isWaiting ? (jsxRuntime.jsx(uilibGl.CircularProgress, { diameter: 1, theme: uilibGl.darkTheme }))
6948
+ : status !== api.RemoteTaskStatus.Unknown
6949
+ ? jsxRuntime.jsx(uilibGl.Icon, { kind: STATUS_ICONS[status] })
6950
+ : jsxRuntime.jsx(uilibGl.Icon, { kind: icon });
6951
+ return (jsxRuntime.jsx(uilibGl.FlexSpan, { marginRight: renderTitle ? "0.5rem" : 0, children: iconComponent }));
6952
+ }, [icon, isWaiting, renderTitle, status]);
6953
+ return (jsxRuntime.jsxs(StyledButton, { status: status, statusColors: statusColors, disabled: isDisabled, onClick: onClick, children: [renderIcon, renderTitle] }));
6954
+ };
6955
+
6956
+ const TaskContainer = React.memo(({ type, elementConfig, renderElement }) => {
6835
6957
  const { t, ewktGeometry } = useGlobalContext();
6836
6958
  const { dataSources, filters: selectedFilters } = useWidgetContext(type);
6837
6959
  const { currentPage } = useWidgetPage(type);
6838
- const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, result } = usePythonTask();
6960
+ const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, log } = usePythonTask();
6839
6961
  const { options } = elementConfig || {};
6840
6962
  const { title, relatedResources, center, icon, statusColors } = options || {};
6841
6963
  const onClick = React.useCallback(async () => {
6964
+ if (taskId) {
6965
+ await stopTask();
6966
+ return;
6967
+ }
6842
6968
  await Promise.all(relatedResources.map(({ resourceId, parameters, script, fileName, methodName }) => {
6843
6969
  const newParams = applyQueryFilters({
6844
6970
  parameters,
@@ -6849,8 +6975,8 @@ const TaskContainer = React.memo(({ type, elementConfig }) => {
6849
6975
  });
6850
6976
  return runTask({ resourceId, parameters: newParams, script, fileName, methodName });
6851
6977
  }));
6852
- }, [currentPage.filters, dataSources, ewktGeometry, relatedResources, runTask, selectedFilters]);
6853
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: center ? "center" : "flex-start", children: [jsxRuntime.jsxs(StatusWaitingButton, { primary: true, status: status, statusColors: statusColors, isWaiting: loading, disabled: !relatedResources?.length, onClick: onClick, children: [icon && jsxRuntime.jsx(uilibGl.FlexSpan, { marginRight: "0.5rem", children: jsxRuntime.jsx(uilibGl.Icon, { kind: icon }) }), title || t("run", { ns: "dashboard", defaultValue: "Запуск" })] }), !!taskId && (jsxRuntime.jsx(uilibGl.IconButton, { kind: "stop", onClick: stopTask })), !!result && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(uilibGl.IconButton, { kind: "info", onClick: openLog }), jsxRuntime.jsx(LogDialog, { isOpen: isLogDialogOpen, onClose: closeLog, logs: result, status: status, statusColors: statusColors })] }))] }) }));
6978
+ }, [currentPage.filters, dataSources, ewktGeometry, relatedResources, runTask, selectedFilters, stopTask, taskId]);
6979
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), jsxRuntime.jsxs(uilibGl.Flex, { justifyContent: center ? "center" : "flex-start", children: [jsxRuntime.jsx(StatusWaitingButton, { title: title || t("run", { ns: "dashboard", defaultValue: "Запуск" }), icon: icon, status: status, statusColors: statusColors, isWaiting: loading || !!taskId, isDisabled: !relatedResources?.length, onClick: onClick }), !!(log || taskId) && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(uilibGl.IconButton, { kind: "info", onClick: openLog }), jsxRuntime.jsx(LogDialog, { logs: log, status: status, statusColors: statusColors, isOpen: isLogDialogOpen, onClose: closeLog })] }))] })] }));
6854
6980
  });
6855
6981
 
6856
6982
  const containerComponents = {
@@ -7680,27 +7806,30 @@ const StyledIcon = styled(uilibGl.Icon) `
7680
7806
 
7681
7807
  const ElementIcon = React.memo(({ type, elementConfig }) => {
7682
7808
  const { attributes } = useWidgetContext(type);
7683
- const { value, attributeName, options } = elementConfig || {};
7809
+ const { value, attributeName, options, style } = elementConfig || {};
7684
7810
  const { fontSize, fontColor } = options || {};
7685
7811
  const iconValue = React.useMemo(() => (attributeName ? attributes?.find(item => item.name === attributeName)?.value : value), [attributeName, attributes, value]);
7686
- return jsxRuntime.jsx(StyledIcon, { kind: iconValue, fontSize: fontSize, fontColor: fontColor });
7812
+ return jsxRuntime.jsx(StyledIcon, { kind: iconValue, fontSize: fontSize, fontColor: fontColor, style: style });
7687
7813
  });
7688
7814
 
7689
7815
  const ElementImage = React.memo(({ type, elementConfig }) => {
7690
7816
  const { attributes } = useWidgetContext(type);
7691
- const { value, attributeName, options } = elementConfig || {};
7817
+ const { value, attributeName, options, style } = elementConfig || {};
7692
7818
  const { width } = options || {};
7693
7819
  const firstImage = React.useMemo(() => {
7694
7820
  if (value) {
7695
- return value.toString();
7821
+ return getResourceUrl(value.toString());
7696
7822
  }
7697
7823
  if (!attributeName || Array.isArray(attributeName)) {
7698
7824
  return null;
7699
7825
  }
7700
7826
  const attribute = attributes?.find(item => item.name === attributeName);
7701
- return attribute?.value?.split(";")?.[0];
7827
+ const imageUrl = attribute?.value?.split(";")?.[0];
7828
+ if (!imageUrl)
7829
+ return null;
7830
+ return getResourceUrl(imageUrl);
7702
7831
  }, [attributeName, attributes, value]);
7703
- return firstImage ? jsxRuntime.jsx("img", { src: firstImage, alt: firstImage, width: width }) : null;
7832
+ return firstImage ? jsxRuntime.jsx("img", { src: firstImage, alt: firstImage, width: width, style: style }) : null;
7704
7833
  });
7705
7834
 
7706
7835
  const ElementLegend = React.memo(({ type, element, elementConfig }) => {