@evergis/react 3.1.65 → 3.1.67

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/react.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
- import { IconButton, Flex, transition, Chip, Icon, Description, FlexSpan, IconToggle, Popup, Menu, DraggableTree, shadows, Divider, LegendToggler, Tooltip as Tooltip$1, DropdownField, MultiSelectContainer, IconButtonButton, FlatButton, DraggableTreeContainer, WaitingButton, LinearProgress, H2, ThemeProvider, defaultTheme, Preview, Blank, Popover, Expander, darkTheme, UploaderItemArea, UploaderTitleWrapper, Uploader, NumberRangeSlider, useAsyncAutocomplete, AutoComplete, Dropdown, Checkbox, CircularProgress, RangeNumberInput, dateFormat } from '@evergis/uilib-gl';
2
+ import { IconButton, Flex, transition, Chip, Icon, Description, FlexSpan, IconToggle, Popup, Menu, DraggableTree, shadows, Divider, LegendToggler, Tooltip as Tooltip$1, DropdownField, MultiSelectContainer, IconButtonButton, FlatButton, DraggableTreeContainer, Dialog, DialogTitle, DialogContent, WaitingButton, LinearProgress, H2, ThemeProvider, defaultTheme, Preview, Blank, Popover, Expander, darkTheme, UploaderItemArea, UploaderTitleWrapper, Uploader, NumberRangeSlider, useAsyncAutocomplete, AutoComplete, Dropdown, Checkbox, CircularProgress, RangeNumberInput, dateFormat } from '@evergis/uilib-gl';
3
3
  import { createContext, memo, useRef, useState, useEffect, useCallback, useContext, useMemo, Fragment } from 'react';
4
4
  import styled, { createGlobalStyle, css, useTheme } from 'styled-components';
5
5
  import { lineChartClassNames, BarChart as BarChart$1, barChartClassNames, LineChart, PieChart } from '@evergis/charts';
@@ -4825,22 +4825,28 @@ const SERVER_NOTIFICATION_EVENT = {
4825
4825
  const usePythonTask = () => {
4826
4826
  const { api, t } = useGlobalContext();
4827
4827
  const { addSubscription, connection, unsubscribeById } = useServerNotificationsContext();
4828
+ const [status, setStatus] = useState(RemoteTaskStatus.Unknown);
4828
4829
  const [result, setResult] = useState(null);
4829
4830
  const [error, setError] = useState(null);
4830
4831
  const [loading, setLoading] = useState(false);
4831
4832
  const [executionTime, setExecutionTime] = useState(null);
4832
4833
  const [taskId, setTaskId] = useState(null);
4833
4834
  const [subscriptionId, setSubscriptionId] = useState(null);
4835
+ const [isLogDialogOpen, setIsLogDialogOpen] = useState(false);
4836
+ const resultRef = useRef(null);
4834
4837
  const reset = useCallback(() => {
4835
- setResult(null);
4838
+ setStatus(RemoteTaskStatus.Unknown);
4836
4839
  setError(null);
4837
- setLoading(true);
4840
+ setLoading(false);
4838
4841
  setExecutionTime(null);
4839
4842
  setTaskId(null);
4840
4843
  setSubscriptionId(null);
4841
4844
  }, []);
4842
4845
  const runTask = useCallback(async ({ resourceId, parameters, script, fileName, methodName, }) => {
4843
4846
  reset();
4847
+ setStatus(RemoteTaskStatus.Process);
4848
+ setResult(null);
4849
+ setLoading(true);
4844
4850
  const start = Date.now();
4845
4851
  let prototypeId = await api.remoteTaskManager.createTaskPrototype({
4846
4852
  enabled: true,
@@ -4863,6 +4869,7 @@ const usePythonTask = () => {
4863
4869
  prototypeId = prototypeId.replace(/["']+/g, "");
4864
4870
  const { id: newTaskId, success } = await api.remoteTaskManager.startTask1(prototypeId);
4865
4871
  if (!success) {
4872
+ setStatus(RemoteTaskStatus.Error);
4866
4873
  setResult(t("taskRunFail", { ns: "devMode", defaultValue: "Не удалось запустить задачу" }));
4867
4874
  setExecutionTime(Date.now() - start);
4868
4875
  setLoading(false);
@@ -4875,7 +4882,8 @@ const usePythonTask = () => {
4875
4882
  setSubscriptionId(newSubscriptionId);
4876
4883
  const onNotification = ({ data }) => {
4877
4884
  if (data?.taskId === newTaskId) {
4878
- setResult(`${data ? `${data}\n` : ""}${data.log || ""}`);
4885
+ setStatus(data.status);
4886
+ setResult([data.log, resultRef.current].filter(Boolean).join("\n\n"));
4879
4887
  setError(null);
4880
4888
  setExecutionTime(Date.now() - start);
4881
4889
  setLoading(false);
@@ -4898,7 +4906,28 @@ const usePythonTask = () => {
4898
4906
  reset();
4899
4907
  unsubscribeById(subscriptionId);
4900
4908
  }, [api, reset, unsubscribeById, taskId, subscriptionId]);
4901
- return { runTask, stopTask, result, error, loading, executionTime };
4909
+ const openLog = useCallback(() => {
4910
+ setIsLogDialogOpen(true);
4911
+ }, []);
4912
+ const closeLog = useCallback(() => {
4913
+ setIsLogDialogOpen(false);
4914
+ }, []);
4915
+ useEffect(() => {
4916
+ resultRef.current = result;
4917
+ }, [result]);
4918
+ return {
4919
+ taskId,
4920
+ runTask,
4921
+ stopTask,
4922
+ openLog,
4923
+ result,
4924
+ error,
4925
+ status,
4926
+ loading,
4927
+ executionTime,
4928
+ isLogDialogOpen,
4929
+ closeLog,
4930
+ };
4902
4931
  };
4903
4932
 
4904
4933
  const useAppHeight = () => {
@@ -6730,13 +6759,83 @@ const UploadContainer = memo(({ type, elementConfig, renderElement }) => {
6730
6759
  return (jsxs(Fragment$1, { children: [jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), isVisible && renderElement({ id: "uploader", wrap: false })] }));
6731
6760
  });
6732
6761
 
6762
+ const StatusBadge = styled(Flex) `
6763
+ margin-bottom: 1rem;
6764
+ padding: 0.5rem 1rem;
6765
+ background-color: ${({ $statusColor }) => $statusColor};
6766
+ color: ${({ theme }) => theme.palette.iconContrast};
6767
+ border-radius: 0.25rem;
6768
+ `;
6769
+ const LogContainer = styled.div `
6770
+ flex: 1;
6771
+ padding: 1rem;
6772
+ background-color: ${({ theme }) => theme.palette.element};
6773
+ color: ${({ theme }) => theme.palette.textPrimary};
6774
+ font-family: monospace;
6775
+ font-size: 0.875rem;
6776
+ overflow: auto;
6777
+ white-space: pre-wrap;
6778
+ word-break: break-word;
6779
+ border-radius: 0.25rem;
6780
+ max-height: 31.25rem;
6781
+ `;
6782
+
6783
+ const STATUS_TRANSLATION_KEYS = {
6784
+ [RemoteTaskStatus.Process]: "task.status.process",
6785
+ [RemoteTaskStatus.Completed]: "task.status.completed",
6786
+ [RemoteTaskStatus.Error]: "task.status.error",
6787
+ [RemoteTaskStatus.Unknown]: "task.status.unknown",
6788
+ };
6789
+ const STATUS_DEFAULT_VALUES = {
6790
+ [RemoteTaskStatus.Process]: "Выполняется...",
6791
+ [RemoteTaskStatus.Completed]: "Завершено",
6792
+ [RemoteTaskStatus.Error]: "Ошибка",
6793
+ [RemoteTaskStatus.Unknown]: "Неизвестно",
6794
+ };
6795
+ const STATUS_COLORS = {
6796
+ [RemoteTaskStatus.Process]: "#2196f3",
6797
+ [RemoteTaskStatus.Completed]: "#4caf50",
6798
+ [RemoteTaskStatus.Error]: "#f44336",
6799
+ [RemoteTaskStatus.Unknown]: "#757575",
6800
+ };
6801
+
6802
+ const LogDialog = ({ isOpen, onClose, logs, status, statusColors }) => {
6803
+ const { t } = useGlobalContext();
6804
+ const contentRef = useRef(null);
6805
+ useEffect(() => {
6806
+ if (contentRef.current) {
6807
+ contentRef.current.scrollTop = 0;
6808
+ }
6809
+ }, [logs]);
6810
+ const getStatusText = useCallback((status) => {
6811
+ const translationKey = STATUS_TRANSLATION_KEYS[status] || STATUS_TRANSLATION_KEYS[RemoteTaskStatus.Unknown];
6812
+ const defaultValue = STATUS_DEFAULT_VALUES[status] || STATUS_DEFAULT_VALUES[RemoteTaskStatus.Unknown];
6813
+ return t(translationKey, { ns: "dashboard", defaultValue });
6814
+ }, [t]);
6815
+ const getStatusColor = useCallback((status) => {
6816
+ return statusColors?.[status] || STATUS_COLORS[status] || STATUS_COLORS[RemoteTaskStatus.Unknown];
6817
+ }, [statusColors]);
6818
+ return (jsxs(Dialog, { isOpen: isOpen, onCloseRequest: onClose, modal: true, maxWidth: "800px", minWidth: "600px", minHeight: "400px", children: [jsx(DialogTitle, { children: jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [jsx("span", { children: t("task.logs.title", { ns: "dashboard", defaultValue: "Логи выполнения задачи" }) }), jsx(IconButton, { kind: "close", onClick: onClose })] }) }), jsx(DialogContent, { children: jsxs(Flex, { flexDirection: "column", height: "100%", marginBottom: "2rem", children: [jsxs(StatusBadge, { "$statusColor": getStatusColor(status), children: [t("task.status.label", { ns: "dashboard", defaultValue: "Статус" }), ": ", getStatusText(status)] }), jsx(LogContainer, { ref: contentRef, children: logs || t("task.logs.empty", { ns: "dashboard", defaultValue: "Логи отсутствуют" }) })] }) })] }));
6819
+ };
6820
+
6821
+ const StatusWaitingButton = styled(WaitingButton) `
6822
+ ${({ status = RemoteTaskStatus.Unknown, statusColors }) => !!statusColors?.[status] && css `
6823
+ transition: background-color ${transition.toggle};
6824
+ background-color: ${statusColors[status]};
6825
+
6826
+ :hover {
6827
+ background-color: ${statusColors[status]};
6828
+ }
6829
+ `}
6830
+ `;
6831
+
6733
6832
  const TaskContainer = memo(({ type, elementConfig }) => {
6734
6833
  const { t, ewktGeometry } = useGlobalContext();
6735
6834
  const { dataSources, filters: selectedFilters } = useWidgetContext(type);
6736
6835
  const { currentPage } = useWidgetPage(type);
6737
- const { runTask, loading } = usePythonTask();
6836
+ const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, result } = usePythonTask();
6738
6837
  const { options } = elementConfig || {};
6739
- const { title, relatedResources, center, icon } = options || {};
6838
+ const { title, relatedResources, center, icon, statusColors } = options || {};
6740
6839
  const onClick = useCallback(async () => {
6741
6840
  await Promise.all(relatedResources.map(({ resourceId, parameters, script, fileName, methodName }) => {
6742
6841
  const newParams = applyQueryFilters({
@@ -6749,7 +6848,7 @@ const TaskContainer = memo(({ type, elementConfig }) => {
6749
6848
  return runTask({ resourceId, parameters: newParams, script, fileName, methodName });
6750
6849
  }));
6751
6850
  }, [currentPage.filters, dataSources, ewktGeometry, relatedResources, runTask, selectedFilters]);
6752
- return (jsx(Flex, { justifyContent: center ? "center" : "flex-start", children: jsxs(WaitingButton, { primary: true, isWaiting: loading, disabled: !relatedResources?.length, onClick: onClick, children: [icon && jsx(FlexSpan, { marginRight: "0.5rem", children: jsx(Icon, { kind: icon }) }), title || t("run", { ns: "dashboard", defaultValue: "Запуск" })] }) }));
6851
+ return (jsx(Fragment$1, { children: jsxs(Flex, { justifyContent: center ? "center" : "flex-start", children: [jsxs(StatusWaitingButton, { primary: true, status: status, statusColors: statusColors, isWaiting: loading, disabled: !relatedResources?.length, onClick: onClick, children: [icon && jsx(FlexSpan, { marginRight: "0.5rem", children: jsx(Icon, { kind: icon }) }), title || t("run", { ns: "dashboard", defaultValue: "Запуск" })] }), !!taskId && (jsx(IconButton, { kind: "stop", onClick: stopTask })), !!result && (jsxs(Fragment$1, { children: [jsx(IconButton, { kind: "info", onClick: openLog }), jsx(LogDialog, { isOpen: isLogDialogOpen, onClose: closeLog, logs: result, status: status, statusColors: statusColors })] }))] }) }));
6753
6852
  });
6754
6853
 
6755
6854
  const containerComponents = {