From 262832bfff90ba4f7517bf6d825ad9a9a0cd89db Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Mon, 12 May 2025 13:51:38 -0700 Subject: [PATCH] UI: Warn before saving script contents (#29026) ## For #28699 auxiliary feature ![ezgif-28c6ba4048c004](https://github.com/user-attachments/assets/2631286a-b4bd-431a-8ea1-5b962af933dd) - [x] Changes file added for user-visible changes in `changes/` - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling --- changes/warn-on-save-script | 1 + frontend/components/Modal/Modal.tsx | 1 + .../EditScriptModal/EditScriptModal.tsx | 91 +++++++++++++++++-- .../components/EditScriptModal/_styles.scss | 10 ++ 4 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 changes/warn-on-save-script create mode 100644 frontend/pages/ManageControlsPage/Scripts/components/EditScriptModal/_styles.scss diff --git a/changes/warn-on-save-script b/changes/warn-on-save-script new file mode 100644 index 0000000000..fdd4e12898 --- /dev/null +++ b/changes/warn-on-save-script @@ -0,0 +1 @@ +- Warn users of consequences when updating script contents diff --git a/frontend/components/Modal/Modal.tsx b/frontend/components/Modal/Modal.tsx index 9fc43231cb..9aefe5fda4 100644 --- a/frontend/components/Modal/Modal.tsx +++ b/frontend/components/Modal/Modal.tsx @@ -6,6 +6,7 @@ import Icon from "components/Icon/Icon"; const baseClass = "modal"; type ModalWidth = "medium" | "large" | "xlarge" | "auto"; +// 650px 800px 850px auto export interface IModalProps { title: string | JSX.Element; diff --git a/frontend/pages/ManageControlsPage/Scripts/components/EditScriptModal/EditScriptModal.tsx b/frontend/pages/ManageControlsPage/Scripts/components/EditScriptModal/EditScriptModal.tsx index 4f8329a1b7..c91d3a145e 100644 --- a/frontend/pages/ManageControlsPage/Scripts/components/EditScriptModal/EditScriptModal.tsx +++ b/frontend/pages/ManageControlsPage/Scripts/components/EditScriptModal/EditScriptModal.tsx @@ -1,6 +1,8 @@ import React, { useContext, useState } from "react"; import { useQuery } from "react-query"; +import classnames from "classnames"; + import { NotificationContext } from "context/notification"; import { AppContext } from "context/app"; import { getPathWithQueryParams } from "utilities/url"; @@ -21,6 +23,52 @@ import { getErrorMessage } from "../ScriptUploader/helpers"; const baseClass = "edit-script-modal"; +interface IWarningModal { + onExit: () => void; + onSave: () => void; + scriptName: string; + isSubmitting: boolean; +} +const WarningModal = ({ + onExit, + onSave, + scriptName, + isSubmitting, +}: IWarningModal) => { + return ( + + <> +

+ The changes you are making will cancel any pending script runs for{" "} + {scriptName}.
+
+ If this script is currently running on a host, it will complete, but + results won't appear in Fleet.
+
+ You cannot undo this action. +

+
+ + +
+ +
+ ); +}; + interface IEditScriptModal { onExit: () => void; scriptId: number; @@ -47,7 +95,10 @@ const EditScriptModal = ({ const [isSubmitting, setIsSubmitting] = useState(false); const [formError, setFormError] = useState(null); + const [showConfirmChanges, setShowConfirmChanges] = useState(false); + const { + data: curScriptContent, error: isSelectedScriptContentError, isLoading: isLoadingSelectedScriptContent, } = useQuery( @@ -55,8 +106,8 @@ const EditScriptModal = ({ () => scriptAPI.downloadScript(scriptId), { ...DEFAULT_USE_QUERY_OPTIONS, - onSuccess: (scriptContent) => { - setScriptFormData(scriptContent); + onSuccess: (curScriptContent_) => { + setScriptFormData(curScriptContent_); }, } ); @@ -79,6 +130,12 @@ const EditScriptModal = ({ if (err || isSubmitting) { return; } + // if contents have changed and not already showing the warning modal + if (curScriptContent !== scriptFormData && !showConfirmChanges) { + setShowConfirmChanges(true); + return; + } + // show warning modal and abort this call try { setIsSubmitting(true); await scriptAPI.updateScript(scriptId, scriptFormData, scriptName); @@ -88,6 +145,7 @@ const EditScriptModal = ({ renderFlash("error", getErrorMessage(e)); } finally { setIsSubmitting(false); + setShowConfirmChanges(false); } }; @@ -161,15 +219,28 @@ const EditScriptModal = ({ ); }; + const classes = classnames(baseClass, { + [`${baseClass}__hide-main`]: !!showConfirmChanges, + }); return ( - - {renderContent()} - + <> + + {renderContent()} + + {!!showConfirmChanges && ( + setShowConfirmChanges(false)} + onSave={onSave} + scriptName={scriptName} + isSubmitting={isSubmitting} + /> + )} + ); }; diff --git a/frontend/pages/ManageControlsPage/Scripts/components/EditScriptModal/_styles.scss b/frontend/pages/ManageControlsPage/Scripts/components/EditScriptModal/_styles.scss new file mode 100644 index 0000000000..932b535ab2 --- /dev/null +++ b/frontend/pages/ManageControlsPage/Scripts/components/EditScriptModal/_styles.scss @@ -0,0 +1,10 @@ +.edit-script-modal { + &__hide-main { + visibility: hidden; + } +} +// since this modal shows only while anotheris also showing, suppress background for one of them to +// prevent "double-darkening" +.modal__background:has(.edit-script-modal.edit-script-modal__hide-main) { + visibility: hidden; +}