@evergis/react 4.0.62 → 4.0.63

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.
@@ -416,7 +416,7 @@ export interface TabsContainerConfig extends Omit<ConfigContainerChild, "options
416
416
  export interface TabsContainerProps extends Omit<ContainerProps, "elementConfig"> {
417
417
  elementConfig?: TabsContainerConfig;
418
418
  }
419
- export type TaskContainerOptions = Pick<ConfigOptions, "title" | "relatedResources" | "center" | "icon" | "statusColors" | "responseFilters">;
419
+ export type TaskContainerOptions = Pick<ConfigOptions, "title" | "relatedResources" | "center" | "icon" | "statusColors" | "responseFilters" | "useNotifications">;
420
420
  export interface TaskContainerConfig extends Omit<ConfigContainerChild, "options" | "templateName"> {
421
421
  templateName?: ContainerTemplate.Task;
422
422
  options?: TaskContainerOptions;
@@ -0,0 +1,9 @@
1
+ import { RemoteTaskStatus } from '@evergis/api';
2
+ interface UseTaskNotificationsParams {
3
+ enabled: boolean;
4
+ status: RemoteTaskStatus;
5
+ lastMessage: string | null;
6
+ openLog: () => void;
7
+ }
8
+ export declare const useTaskNotifications: ({ enabled, status, lastMessage, openLog, }: UseTaskNotificationsParams) => void;
9
+ export {};
@@ -5,4 +5,11 @@ export declare const useGlobalContext: () => {
5
5
  themeName: import('../../..').ThemeName;
6
6
  api: import('@evergis/api').Api;
7
7
  ewktGeometry: string;
8
+ notification: {
9
+ add: (item: import('@evergis/uilib-gl').INotificationItem) => void;
10
+ update: (patch: Partial<import('@evergis/uilib-gl').INotificationItem> & {
11
+ id: string;
12
+ }) => void;
13
+ close: (id: string) => void;
14
+ };
8
15
  };
@@ -262,6 +262,7 @@ export interface ConfigMiscOptions {
262
262
  tabId?: string;
263
263
  downloadById?: string;
264
264
  parentResourceId?: string;
265
+ useNotifications?: boolean;
265
266
  }
266
267
  /**
267
268
  * Flat-объединение всех доменных миксинов. Существующие места, использующие
@@ -1,6 +1,7 @@
1
1
  import { PropsWithChildren } from 'react';
2
2
  import { i18n } from 'i18next';
3
3
  import { Api } from '@evergis/api';
4
+ import { INotificationItem } from '@evergis/uilib-gl';
4
5
  import { ThemeName } from '../../types';
5
6
  export type GlobalContextProps = PropsWithChildren<{
6
7
  t?: i18n["t"];
@@ -8,4 +9,11 @@ export type GlobalContextProps = PropsWithChildren<{
8
9
  ewktGeometry?: string;
9
10
  themeName?: ThemeName;
10
11
  api?: Api;
12
+ notification?: {
13
+ add: (item: INotificationItem) => void;
14
+ update: (patch: Partial<INotificationItem> & {
15
+ id: string;
16
+ }) => void;
17
+ close: (id: string) => void;
18
+ };
11
19
  }>;
@@ -11,6 +11,7 @@ export declare const usePythonTask: () => {
11
11
  stopTask: () => Promise<void>;
12
12
  openLog: () => void;
13
13
  log: string;
14
+ lastMessage: string;
14
15
  error: Error;
15
16
  status: RemoteTaskStatus;
16
17
  loading: boolean;
package/dist/index.js CHANGED
@@ -4217,7 +4217,7 @@ const useAttachmentItems = ({ type, elementConfig, valueOverride, }) => {
4217
4217
  };
4218
4218
 
4219
4219
  const useGlobalContext = () => {
4220
- const { t, language, themeName, api, ewktGeometry } = React.useContext(GlobalContext) || {};
4220
+ const { t, language, themeName, api, ewktGeometry, notification } = React.useContext(GlobalContext) || {};
4221
4221
  const translate = React.useCallback((value, options) => {
4222
4222
  if (t)
4223
4223
  return t(value, options);
@@ -4229,7 +4229,8 @@ const useGlobalContext = () => {
4229
4229
  themeName,
4230
4230
  api,
4231
4231
  ewktGeometry,
4232
- }), [language, translate, api, ewktGeometry, themeName]);
4232
+ notification,
4233
+ }), [language, translate, api, ewktGeometry, themeName, notification]);
4233
4234
  };
4234
4235
 
4235
4236
  const GRID_TILE_SIZE = "4.5rem";
@@ -5622,6 +5623,7 @@ const usePythonTask = () => {
5622
5623
  const { preparePythonSandbox } = usePythonSandbox();
5623
5624
  const [status, setStatus] = React.useState(api.RemoteTaskStatus.Unknown);
5624
5625
  const [log, setLog] = React.useState(null);
5626
+ const [lastMessage, setLastMessage] = React.useState(null);
5625
5627
  const [error, setError] = React.useState(null);
5626
5628
  const [loading, setLoading] = React.useState(false);
5627
5629
  const [executionTime, setExecutionTime] = React.useState(null);
@@ -5643,6 +5645,7 @@ const usePythonTask = () => {
5643
5645
  reset();
5644
5646
  setStatus(api.RemoteTaskStatus.Process);
5645
5647
  setLog(null);
5648
+ setLastMessage(null);
5646
5649
  setLoading(true);
5647
5650
  const start = Date.now();
5648
5651
  let prototypeId = await api$1.remoteTaskManager.createTaskPrototype({
@@ -5683,6 +5686,8 @@ const usePythonTask = () => {
5683
5686
  const isFinished = [api.RemoteTaskStatus.Completed, api.RemoteTaskStatus.Error].includes(data.status);
5684
5687
  setStatus(data.status);
5685
5688
  setLog([logRef.current, data.log].filter(Boolean).join("\n"));
5689
+ if (data.log)
5690
+ setLastMessage(data.log);
5686
5691
  setExecutionTime(Date.now() - start);
5687
5692
  setLoading(false);
5688
5693
  setTaskId(isFinished ? null : newTaskId);
@@ -5735,6 +5740,7 @@ const usePythonTask = () => {
5735
5740
  stopTask,
5736
5741
  openLog,
5737
5742
  log,
5743
+ lastMessage,
5738
5744
  error,
5739
5745
  status,
5740
5746
  loading,
@@ -7708,14 +7714,93 @@ const buildFiltersFromResponse = (responseFilters, result) => {
7708
7714
  return Object.keys(filters).length ? filters : null;
7709
7715
  };
7710
7716
 
7717
+ const RUN_ID_RADIX = 36;
7718
+ const RUN_ID_LENGTH = 8;
7719
+ const generateRunId = () => `task-${Date.now()}-${Math.random().toString(RUN_ID_RADIX).slice(2, RUN_ID_LENGTH)}`;
7720
+ const useTaskNotifications = ({ enabled, status, lastMessage, openLog, }) => {
7721
+ const { t, notification } = useGlobalContext();
7722
+ const runIdRef = React.useRef(null);
7723
+ const prevStatusRef = React.useRef(api.RemoteTaskStatus.Unknown);
7724
+ React.useEffect(() => {
7725
+ if (!enabled) {
7726
+ if (runIdRef.current) {
7727
+ notification?.close(runIdRef.current);
7728
+ runIdRef.current = null;
7729
+ }
7730
+ prevStatusRef.current = status;
7731
+ return;
7732
+ }
7733
+ if (status === api.RemoteTaskStatus.Unknown) {
7734
+ prevStatusRef.current = status;
7735
+ return;
7736
+ }
7737
+ const isFreshRun = status === api.RemoteTaskStatus.Process && prevStatusRef.current !== api.RemoteTaskStatus.Process;
7738
+ if (isFreshRun) {
7739
+ runIdRef.current = generateRunId();
7740
+ }
7741
+ if (!runIdRef.current) {
7742
+ runIdRef.current = generateRunId();
7743
+ }
7744
+ const id = runIdRef.current;
7745
+ const description = lastMessage || t("taskStarted", { ns: "dashboard", defaultValue: "Запуск задачи…" });
7746
+ const button = t("details", { ns: "dashboard", defaultValue: "Подробнее" });
7747
+ const base = {
7748
+ id,
7749
+ title: "",
7750
+ description,
7751
+ duration: Number.MAX_SAFE_INTEGER,
7752
+ button,
7753
+ buttonIcon: "info",
7754
+ buttonColor: "primary",
7755
+ onButtonClick: openLog,
7756
+ };
7757
+ if (status === api.RemoteTaskStatus.Process) {
7758
+ const item = {
7759
+ ...base,
7760
+ title: t("taskInProgress", { ns: "dashboard", defaultValue: "Выполняется" }),
7761
+ progress: true,
7762
+ };
7763
+ if (isFreshRun) {
7764
+ notification?.add(item);
7765
+ }
7766
+ else {
7767
+ notification?.update(item);
7768
+ }
7769
+ }
7770
+ else if (status === api.RemoteTaskStatus.Completed) {
7771
+ notification?.update({
7772
+ ...base,
7773
+ title: t("taskCompleted", { ns: "dashboard", defaultValue: "Выполнено" }),
7774
+ success: true,
7775
+ progress: false,
7776
+ });
7777
+ }
7778
+ else if (status === api.RemoteTaskStatus.Error) {
7779
+ notification?.update({
7780
+ ...base,
7781
+ title: t("taskError", { ns: "dashboard", defaultValue: "Ошибка" }),
7782
+ error: true,
7783
+ progress: false,
7784
+ });
7785
+ }
7786
+ prevStatusRef.current = status;
7787
+ }, [enabled, status, lastMessage, openLog, t, notification]);
7788
+ };
7789
+
7711
7790
  const TaskContainer = React.memo(({ type, elementConfig, renderElement }) => {
7712
7791
  const { t, ewktGeometry } = useGlobalContext();
7713
7792
  const { dataSources, filters: selectedFilters, attributes, layerInfo, changeFilters, } = useWidgetContext(type);
7714
7793
  const { dataSources: projectDataSources } = useWidgetContext(exports.WidgetType.Dashboard);
7715
7794
  const { currentPage } = useWidgetPage(type);
7716
- const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, log, result, } = usePythonTask();
7795
+ const { taskId, runTask, stopTask, status, openLog, loading, isLogDialogOpen, closeLog, log, lastMessage, result, } = usePythonTask();
7717
7796
  const { options } = elementConfig || {};
7718
- const { title, relatedResources, center, icon, statusColors, responseFilters } = options || {};
7797
+ const { title, relatedResources, center, icon, statusColors, responseFilters, useNotifications, } = options || {};
7798
+ useTaskNotifications({
7799
+ enabled: !!useNotifications,
7800
+ status,
7801
+ lastMessage,
7802
+ openLog,
7803
+ });
7719
7804
  React.useEffect(() => {
7720
7805
  const filtersToApply = buildFiltersFromResponse(responseFilters, result);
7721
7806
  if (filtersToApply)