diff --git a/designer/client/src/actions/notificationActions.tsx b/designer/client/src/actions/notificationActions.tsx
index bfb48dc396a..c11b61d8c37 100644
--- a/designer/client/src/actions/notificationActions.tsx
+++ b/designer/client/src/actions/notificationActions.tsx
@@ -2,6 +2,7 @@ import React from "react";
import Notifications from "react-notification-system-redux";
import CheckCircleOutlinedIcon from "@mui/icons-material/CheckCircleOutlined";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
+import WarningAmberOutlinedIcon from "@mui/icons-material/WarningAmberOutlined";
import Notification from "../components/notifications/Notification";
import { Action } from "./reduxTypes";
@@ -26,3 +27,10 @@ export function info(message: string): Action {
children: } message={message} />,
});
}
+
+export function warn(message: string): Action {
+ return Notifications.warning({
+ autoDismiss: 10,
+ children: } message={message} />,
+ });
+}
diff --git a/designer/client/src/components/graph/Graph.tsx b/designer/client/src/components/graph/Graph.tsx
index 124a608f173..427958552f2 100644
--- a/designer/client/src/components/graph/Graph.tsx
+++ b/designer/client/src/components/graph/Graph.tsx
@@ -49,6 +49,8 @@ import { handleGraphEvent } from "./utils/graphUtils";
import { StickyNote } from "../../common/StickyNote";
import { StickyNoteElement, StickyNoteElementView } from "./StickyNoteElement";
import { STICKY_NOTE_CONSTRAINTS } from "./EspNode/stickyNote";
+import { NotificationActions } from "../../http/HttpService";
+import i18next from "i18next";
function clamp(number: number, max: number) {
return Math.round(Math.min(max, Math.max(-max, number)));
@@ -65,6 +67,7 @@ type Props = GraphProps & {
theme: Theme;
translation: UseTranslationResponse;
handleStatisticsEvent: (event: TrackEventParams) => void;
+ notifications: NotificationActions;
};
export const nuGraphNamespace = {
@@ -233,6 +236,15 @@ export class Graph extends React.Component {
}
if (isStickyNoteElement(cell.model)) {
this.processGraphPaper.hideTools();
+ if (!this.props.isPristine) {
+ this.props.notifications.warn(
+ i18next.t(
+ "notification.warn.cannotDeleteOnUnsavedVersion",
+ "Save scenario before making any changes to sticky notes",
+ ),
+ );
+ return;
+ }
cell.showTools();
const updatedStickyNote = getStickyNoteCopyFromCell(this.props.stickyNotes, cell.model);
if (!updatedStickyNote) return;
@@ -382,6 +394,7 @@ export class Graph extends React.Component {
if (this.props.isFragment === true) return;
this.processGraphPaper.hideTools();
if (isStickyNoteElement(cellView.model)) {
+ if (!this.props.isPristine) return;
showStickyNoteTools(cellView);
}
if (this.props.nodeSelectionEnabled) {
@@ -469,6 +482,12 @@ export class Graph extends React.Component {
this.graph.on(Events.CELL_RESIZED, (cell: dia.Element) => {
if (isStickyNoteElement(cell)) {
+ if (!this.props.isPristine) {
+ this.props.notifications.warn(
+ i18next.t("notification.warn.cannotDeleteOnUnsavedVersion", "Save scenario before resizing sticky note"),
+ );
+ return;
+ }
const updatedStickyNote = getStickyNoteCopyFromCell(this.props.stickyNotes, cell);
if (!updatedStickyNote) return;
const position = cell.get("position");
@@ -490,6 +509,12 @@ export class Graph extends React.Component {
this.graph.on(Events.CELL_CONTENT_UPDATED, (cell: dia.Element, content: string) => {
if (isStickyNoteElement(cell)) {
+ if (!this.props.isPristine) {
+ this.props.notifications.warn(
+ i18next.t("notification.warn.cannotDeleteOnUnsavedVersion", "Save scenario before updating sticky note"),
+ );
+ return;
+ }
const updatedStickyNote = getStickyNoteCopyFromCell(this.props.stickyNotes, cell);
if (!updatedStickyNote) return;
if (updatedStickyNote.content == content) return;
@@ -500,6 +525,12 @@ export class Graph extends React.Component {
this.graph.on(Events.CELL_DELETED, (cell: dia.Element) => {
if (isStickyNoteElement(cell)) {
+ if (!this.props.isPristine) {
+ this.props.notifications.warn(
+ i18next.t("notification.warn.cannotDeleteOnUnsavedVersion", "Save scenario before deleting sticky note"),
+ );
+ return;
+ }
const noteId = Number(cell.get("noteId"));
this.deleteStickyNote(this.props.scenario.name, noteId);
}
diff --git a/designer/client/src/components/graph/GraphWrapped.tsx b/designer/client/src/components/graph/GraphWrapped.tsx
index d9b5351e844..4847d6123d7 100644
--- a/designer/client/src/components/graph/GraphWrapped.tsx
+++ b/designer/client/src/components/graph/GraphWrapped.tsx
@@ -1,7 +1,7 @@
import { useTheme } from "@mui/material";
import React, { forwardRef, useRef } from "react";
import { useTranslation } from "react-i18next";
-import { useSelector } from "react-redux";
+import { useDispatch, useSelector } from "react-redux";
import { useForkRef } from "rooks";
import { useEventTracking } from "../../containers/event-tracking";
import { getProcessCategory, getSelectionState, isPristine } from "../../reducers/selectors/graph";
@@ -12,10 +12,13 @@ import { Graph } from "./Graph";
import { GraphStyledWrapper } from "./graphStyledWrapper";
import { NodeDescriptionPopover } from "./NodeDescriptionPopover";
import { GraphProps } from "./types";
+import { bindActionCreators } from "redux";
+import * as NotificationActions from "../../actions/notificationActions";
// Graph wrapped to make partial (for now) refactor to TS and hooks
export default forwardRef(function GraphWrapped(props, forwardedRef): JSX.Element {
const { openNodeWindow } = useWindows();
+ const dispatch = useDispatch();
const userSettings = useSelector(getUserSettings);
const pristine = useSelector(isPristine);
const processCategory = useSelector(getProcessCategory);
@@ -25,7 +28,7 @@ export default forwardRef(function GraphWrapped(props, forwar
const theme = useTheme();
const translation = useTranslation();
const { trackEvent } = useEventTracking();
-
+ const notifications = bindActionCreators(NotificationActions, dispatch);
const graphRef = useRef();
const ref = useForkRef(graphRef, forwardedRef);
@@ -45,6 +48,7 @@ export default forwardRef(function GraphWrapped(props, forwar
theme={theme}
translation={translation}
handleStatisticsEvent={trackEvent}
+ notifications={notifications}
/>
diff --git a/designer/client/src/components/graph/StickyNoteElement.ts b/designer/client/src/components/graph/StickyNoteElement.ts
index 9dcdcbad2dd..a9a1d7d5ef3 100644
--- a/designer/client/src/components/graph/StickyNoteElement.ts
+++ b/designer/client/src/components/graph/StickyNoteElement.ts
@@ -21,6 +21,7 @@ export const StickyNoteElementView = dia.ElementView.extend({
events: {
"click textarea": "stopPropagation",
"keydown textarea": "selectAll",
+ "blur textarea": "onChange",
"focusout textarea": "onChange",
"dblclick .sticky-note-content": "showEditor",
},
@@ -46,6 +47,7 @@ export const StickyNoteElementView = dia.ElementView.extend({
onChange: function (evt) {
this.model.trigger(Events.CELL_CONTENT_UPDATED, this.model, evt.target.value);
+ console.log(evt);
this.model.attr(`${MARKDOWN_EDITOR_NAME}/props/value`, evt.target.value);
this.model.attr(`${MARKDOWN_EDITOR_NAME}/props/disabled`, true);
},
diff --git a/designer/client/src/http/HttpService.ts b/designer/client/src/http/HttpService.ts
index bf5caa14a17..66a7b1d6fd2 100644
--- a/designer/client/src/http/HttpService.ts
+++ b/designer/client/src/http/HttpService.ts
@@ -125,9 +125,10 @@ export type ComponentUsageType = {
lastAction: ProcessActionType;
};
-type NotificationActions = {
+export type NotificationActions = {
success(message: string): void;
error(message: string, error: string, showErrorText: boolean): void;
+ warn(message: string): void;
};
export interface TestProcessResponse {