@evergis/react 4.0.62 → 4.0.64

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,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
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, ThemeProvider, darkTheme, DialogContent, CircularProgress, Switch, AutoComplete, Input, Slider, Dropdown, Checkbox, DatePicker, getLocale, IconToggleButton, LinearProgress, ActionsGroup, DialogActions, RaisedButton, Preview, H2, Blank, Popover, UploaderItemArea, UploaderTitleWrapper, Uploader, NumberRangeSlider, useAsyncAutocomplete, RangeNumberInput, defaultTheme, dateFormat } from '@evergis/uilib-gl';
3
- import { createContext, memo, useRef, useState, useCallback, useEffect, useContext, useMemo, isValidElement, Fragment } from 'react';
3
+ import { createContext, memo, useRef, useState, useCallback, useEffect, useContext, useMemo, isValidElement, Fragment, createElement } 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';
6
6
  import { AttributeType, generateId, STORAGE_TOKEN_KEY, parseJwt, STORAGE_REFRESH_TOKEN_KEY, RemoteTaskStatus, LayerServiceType, OgcGeometryType, StringSubType, AttributeConfigurationType } from '@evergis/api';
@@ -4215,7 +4215,7 @@ const useAttachmentItems = ({ type, elementConfig, valueOverride, }) => {
4215
4215
  };
4216
4216
 
4217
4217
  const useGlobalContext = () => {
4218
- const { t, language, themeName, api, ewktGeometry } = useContext(GlobalContext) || {};
4218
+ const { t, language, themeName, api, ewktGeometry, notification } = useContext(GlobalContext) || {};
4219
4219
  const translate = useCallback((value, options) => {
4220
4220
  if (t)
4221
4221
  return t(value, options);
@@ -4227,7 +4227,8 @@ const useGlobalContext = () => {
4227
4227
  themeName,
4228
4228
  api,
4229
4229
  ewktGeometry,
4230
- }), [language, translate, api, ewktGeometry, themeName]);
4230
+ notification,
4231
+ }), [language, translate, api, ewktGeometry, themeName, notification]);
4231
4232
  };
4232
4233
 
4233
4234
  const GRID_TILE_SIZE = "4.5rem";
@@ -5620,6 +5621,7 @@ const usePythonTask = () => {
5620
5621
  const { preparePythonSandbox } = usePythonSandbox();
5621
5622
  const [status, setStatus] = useState(RemoteTaskStatus.Unknown);
5622
5623
  const [log, setLog] = useState(null);
5624
+ const [lastMessage, setLastMessage] = useState(null);
5623
5625
  const [error, setError] = useState(null);
5624
5626
  const [loading, setLoading] = useState(false);
5625
5627
  const [executionTime, setExecutionTime] = useState(null);
@@ -5627,7 +5629,6 @@ const usePythonTask = () => {
5627
5629
  const [subscriptionId, setSubscriptionId] = useState(null);
5628
5630
  const [isLogDialogOpen, setIsLogDialogOpen] = useState(false);
5629
5631
  const [result, setResult] = useState(null);
5630
- const logRef = useRef(null);
5631
5632
  const reset = useCallback(() => {
5632
5633
  setStatus(RemoteTaskStatus.Unknown);
5633
5634
  setError(null);
@@ -5641,6 +5642,7 @@ const usePythonTask = () => {
5641
5642
  reset();
5642
5643
  setStatus(RemoteTaskStatus.Process);
5643
5644
  setLog(null);
5645
+ setLastMessage(null);
5644
5646
  setLoading(true);
5645
5647
  const start = Date.now();
5646
5648
  let prototypeId = await api.remoteTaskManager.createTaskPrototype({
@@ -5680,7 +5682,9 @@ const usePythonTask = () => {
5680
5682
  if (data?.taskId === newTaskId) {
5681
5683
  const isFinished = [RemoteTaskStatus.Completed, RemoteTaskStatus.Error].includes(data.status);
5682
5684
  setStatus(data.status);
5683
- setLog([logRef.current, data.log].filter(Boolean).join("\n"));
5685
+ setLog(prev => [prev, data.log].filter(Boolean).join(""));
5686
+ if (data.log)
5687
+ setLastMessage(data.log);
5684
5688
  setExecutionTime(Date.now() - start);
5685
5689
  setLoading(false);
5686
5690
  setTaskId(isFinished ? null : newTaskId);
@@ -5724,15 +5728,13 @@ const usePythonTask = () => {
5724
5728
  const closeLog = useCallback(() => {
5725
5729
  setIsLogDialogOpen(false);
5726
5730
  }, []);
5727
- useEffect(() => {
5728
- logRef.current = log;
5729
- }, [log]);
5730
5731
  return {
5731
5732
  taskId,
5732
5733
  runTask,
5733
5734
  stopTask,
5734
5735
  openLog,
5735
5736
  log,
5737
+ lastMessage,
5736
5738
  error,
5737
5739
  status,
5738
5740
  loading,
@@ -7633,17 +7635,17 @@ const STATUS_ICONS = {
7633
7635
  [RemoteTaskStatus.Unknown]: "play",
7634
7636
  };
7635
7637
 
7636
- const LogDialog = ({ isOpen, onClose, logs, status, statusColors }) => {
7638
+ const LogDialog = ({ isOpen, onClose, onMinimize, logs, status, statusColors }) => {
7637
7639
  const { t } = useGlobalContext();
7638
- const getStatusTitle = useCallback((status) => {
7639
- const translationKey = STATUS_TRANSLATION_KEYS[status] || STATUS_TRANSLATION_KEYS[RemoteTaskStatus.Unknown];
7640
- const defaultValue = STATUS_TITLES[status] || STATUS_TITLES[RemoteTaskStatus.Unknown];
7640
+ const getStatusTitle = useCallback((currentStatus) => {
7641
+ const translationKey = STATUS_TRANSLATION_KEYS[currentStatus] || STATUS_TRANSLATION_KEYS[RemoteTaskStatus.Unknown];
7642
+ const defaultValue = STATUS_TITLES[currentStatus] || STATUS_TITLES[RemoteTaskStatus.Unknown];
7641
7643
  return t(translationKey, { ns: "dashboard", defaultValue });
7642
7644
  }, [t]);
7643
- const getStatusColor = useCallback((status) => {
7644
- return statusColors?.[status] || STATUS_COLORS[status] || STATUS_COLORS[RemoteTaskStatus.Unknown];
7645
+ const getStatusColor = useCallback((currentStatus) => {
7646
+ return statusColors?.[currentStatus] || STATUS_COLORS[currentStatus] || STATUS_COLORS[RemoteTaskStatus.Unknown];
7645
7647
  }, [statusColors]);
7646
- return (jsxs(Dialog, { isOpen: isOpen, onCloseRequest: onClose, modal: true, maxWidth: "800px", minWidth: "600px", minHeight: "600px", children: [jsx(DialogTitle, { children: jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxs(Flex, { alignItems: "center", children: [jsx(FlexSpan, { marginRight: "1rem", children: t("taskLogs", { ns: "dashboard", defaultValue: "Логи выполнения задачи" }) }), jsx(ThemeProvider, { theme: darkTheme, children: jsx(StatusBadge, { text: getStatusTitle(status), bgColor: getStatusColor(status) }) })] }), jsx(IconButton, { kind: "close", onClick: onClose })] }) }), jsx(DialogContent, { children: jsx(Flex, { flexDirection: "column", height: "100%", marginBottom: "2rem", children: jsx(LogTerminal, { log: logs || t("taskLogsEmpty", { ns: "dashboard", defaultValue: "Логи отсутствуют" }) }) }) })] }));
7648
+ return (jsxs(Dialog, { isOpen: isOpen, onCloseRequest: onClose, modal: true, maxWidth: "800px", minWidth: "600px", minHeight: "600px", children: [jsx(DialogTitle, { children: jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxs(Flex, { alignItems: "center", children: [jsx(FlexSpan, { marginRight: "1rem", children: t("taskLogs", { ns: "dashboard", defaultValue: "Логи выполнения задачи" }) }), jsx(ThemeProvider, { theme: darkTheme, children: jsx(StatusBadge, { text: getStatusTitle(status), bgColor: getStatusColor(status) }) })] }), jsxs(Flex, { alignItems: "center", width: "auto", children: [onMinimize && jsx(IconButton, { kind: "change_geom", onClick: onMinimize }), jsx(IconButton, { kind: "close", onClick: onClose })] })] }) }), jsx(DialogContent, { children: jsx(Flex, { flexDirection: "column", height: "100%", marginBottom: "2rem", children: jsx(LogTerminal, { log: logs || t("taskLogsEmpty", { ns: "dashboard", defaultValue: "Логи отсутствуют" }) }) }) })] }));
7647
7649
  };
7648
7650
 
7649
7651
  var ThemeName;
@@ -7706,14 +7708,131 @@ const buildFiltersFromResponse = (responseFilters, result) => {
7706
7708
  return Object.keys(filters).length ? filters : null;
7707
7709
  };
7708
7710
 
7711
+ const ClampedText = styled.div `
7712
+ display: -webkit-box;
7713
+ -webkit-line-clamp: 2;
7714
+ -webkit-box-orient: vertical;
7715
+ overflow: hidden;
7716
+ text-overflow: ellipsis;
7717
+ word-break: break-word;
7718
+ `;
7719
+ const clampDescription = (text) => createElement(ClampedText, null, text);
7720
+
7721
+ const RUN_ID_RADIX = 36;
7722
+ const RUN_ID_LENGTH = 8;
7723
+ const generateRunId = () => `task-${Date.now()}-${Math.random().toString(RUN_ID_RADIX).slice(2, RUN_ID_LENGTH)}`;
7724
+ const useTaskNotifications = ({ enabled, suppressed, status, lastMessage, openLog, }) => {
7725
+ const { t, notification } = useGlobalContext();
7726
+ const runIdRef = useRef(null);
7727
+ const prevStatusRef = useRef(RemoteTaskStatus.Unknown);
7728
+ const isVisibleRef = useRef(false);
7729
+ const [dismissed, setDismissed] = useState(false);
7730
+ useEffect(() => {
7731
+ if (!enabled) {
7732
+ if (runIdRef.current) {
7733
+ notification?.close(runIdRef.current);
7734
+ runIdRef.current = null;
7735
+ }
7736
+ isVisibleRef.current = false;
7737
+ prevStatusRef.current = status;
7738
+ return;
7739
+ }
7740
+ if (status === RemoteTaskStatus.Unknown) {
7741
+ prevStatusRef.current = status;
7742
+ return;
7743
+ }
7744
+ const isFreshRun = status === RemoteTaskStatus.Process && prevStatusRef.current !== RemoteTaskStatus.Process;
7745
+ if (isFreshRun) {
7746
+ runIdRef.current = generateRunId();
7747
+ isVisibleRef.current = false;
7748
+ setDismissed(false);
7749
+ }
7750
+ if (!runIdRef.current) {
7751
+ runIdRef.current = generateRunId();
7752
+ }
7753
+ const id = runIdRef.current;
7754
+ const description = clampDescription(lastMessage || t("taskStarted", { ns: "dashboard", defaultValue: "Запуск задачи…" }));
7755
+ const base = {
7756
+ id,
7757
+ title: "",
7758
+ description,
7759
+ duration: Number.MAX_SAFE_INTEGER,
7760
+ ...(lastMessage ? {
7761
+ button: t("details", { ns: "dashboard", defaultValue: "Подробнее" }),
7762
+ buttonIcon: "info",
7763
+ buttonColor: "primary",
7764
+ onButtonClick: openLog,
7765
+ } : {}),
7766
+ };
7767
+ let item = null;
7768
+ if (status === RemoteTaskStatus.Process) {
7769
+ item = {
7770
+ ...base,
7771
+ title: t("taskInProgress", { ns: "dashboard", defaultValue: "Выполняется" }),
7772
+ progress: true,
7773
+ };
7774
+ }
7775
+ else if (status === RemoteTaskStatus.Completed) {
7776
+ item = {
7777
+ ...base,
7778
+ title: t("taskCompleted", { ns: "dashboard", defaultValue: "Выполнено" }),
7779
+ success: true,
7780
+ progress: false,
7781
+ };
7782
+ }
7783
+ else if (status === RemoteTaskStatus.Error) {
7784
+ item = {
7785
+ ...base,
7786
+ title: t("taskError", { ns: "dashboard", defaultValue: "Ошибка" }),
7787
+ error: true,
7788
+ progress: false,
7789
+ };
7790
+ }
7791
+ if (!item) {
7792
+ prevStatusRef.current = status;
7793
+ return;
7794
+ }
7795
+ if (suppressed || dismissed) {
7796
+ if (isVisibleRef.current) {
7797
+ notification?.close(id);
7798
+ isVisibleRef.current = false;
7799
+ }
7800
+ }
7801
+ else if (isVisibleRef.current) {
7802
+ notification?.update(item);
7803
+ }
7804
+ else {
7805
+ notification?.add(item);
7806
+ isVisibleRef.current = true;
7807
+ }
7808
+ prevStatusRef.current = status;
7809
+ }, [enabled, suppressed, dismissed, status, lastMessage, openLog, t, notification]);
7810
+ return { setNotificationDismissed: setDismissed };
7811
+ };
7812
+
7709
7813
  const TaskContainer = memo(({ type, elementConfig, renderElement }) => {
7710
7814
  const { t, ewktGeometry } = useGlobalContext();
7711
7815
  const { dataSources, filters: selectedFilters, attributes, layerInfo, changeFilters, } = useWidgetContext(type);
7712
7816
  const { dataSources: projectDataSources } = useWidgetContext(WidgetType.Dashboard);
7713
7817
  const { currentPage } = useWidgetPage(type);
7714
- const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, log, result, } = usePythonTask();
7818
+ const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, log, lastMessage, result, } = usePythonTask();
7715
7819
  const { options } = elementConfig || {};
7716
- const { title, relatedResources, center, icon, statusColors, responseFilters } = options || {};
7820
+ const { title, relatedResources, center, icon, statusColors, responseFilters, useNotifications, } = options || {};
7821
+ const { setNotificationDismissed } = useTaskNotifications({
7822
+ enabled: !!useNotifications,
7823
+ suppressed: isLogDialogOpen,
7824
+ status,
7825
+ lastMessage,
7826
+ openLog,
7827
+ });
7828
+ const onCloseLog = useCallback(() => {
7829
+ setNotificationDismissed(true);
7830
+ closeLog();
7831
+ }, [closeLog, setNotificationDismissed]);
7832
+ const onMinimizeLog = useCallback(() => {
7833
+ setNotificationDismissed(false);
7834
+ closeLog();
7835
+ }, [closeLog, setNotificationDismissed]);
7717
7836
  useEffect(() => {
7718
7837
  const filtersToApply = buildFiltersFromResponse(responseFilters, result);
7719
7838
  if (filtersToApply)
@@ -7738,7 +7857,7 @@ const TaskContainer = memo(({ type, elementConfig, renderElement }) => {
7738
7857
  return runTask({ resourceId, parameters: newParams, script, fileName, methodName });
7739
7858
  }));
7740
7859
  }, [attributes, currentPage.filters, dataSources, ewktGeometry, layerInfo, projectDataSources, relatedResources, runTask, selectedFilters, stopTask, taskId]);
7741
- return (jsxs(Fragment$1, { children: [jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), jsxs(Flex, { justifyContent: center ? "center" : "flex-start", children: [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) && (jsxs(Fragment$1, { children: [jsx(IconButton, { kind: "info", onClick: openLog }), jsx(LogDialog, { logs: log, status: status, statusColors: statusColors, isOpen: isLogDialogOpen, onClose: closeLog })] }))] })] }));
7860
+ return (jsxs(Fragment$1, { children: [jsx(ExpandableTitle, { elementConfig: elementConfig, type: type, renderElement: renderElement }), jsxs(Flex, { justifyContent: center ? "center" : "flex-start", children: [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) && (jsxs(Fragment$1, { children: [jsx(IconButton, { kind: "info", onClick: openLog }), jsx(LogDialog, { logs: log, status: status, statusColors: statusColors, isOpen: isLogDialogOpen, onClose: onCloseLog, onMinimize: useNotifications ? onMinimizeLog : undefined })] }))] })] }));
7742
7861
  });
7743
7862
 
7744
7863
  const EditContainer = ({ type, elementConfig, renderElement }) => {