form.markAsSaved(); applied across the application
This commit is contained in:
parent
046869510a
commit
5f03b1cccc
@ -19,6 +19,7 @@ import { renderCustomField } from "./formHelpers";
|
|||||||
import { CustomFieldValue } from "../../modules/manager/glossary/services/glossaryService";
|
import { CustomFieldValue } from "../../modules/manager/glossary/services/glossaryService";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Namespaces } from "../../i18n/i18n";
|
import { Namespaces } from "../../i18n/i18n";
|
||||||
|
import { useFormWithGuard } from "./useFormRouter";
|
||||||
|
|
||||||
interface TemplateFillerProps {
|
interface TemplateFillerProps {
|
||||||
templateId?: GeneralIdRef;
|
templateId?: GeneralIdRef;
|
||||||
@ -40,7 +41,7 @@ interface TemplateState {
|
|||||||
|
|
||||||
const TemplateFiller = forwardRef<TemplateFillerHandle, TemplateFillerProps>(
|
const TemplateFiller = forwardRef<TemplateFillerHandle, TemplateFillerProps>(
|
||||||
({ templateId, formInstanceId, onValidationChanged }, ref) => {
|
({ templateId, formInstanceId, onValidationChanged }, ref) => {
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {},
|
data: {},
|
||||||
errors: {},
|
errors: {},
|
||||||
|
|||||||
@ -91,6 +91,9 @@ interface UseFormReturn {
|
|||||||
hasUnsavedChanges: () => boolean;
|
hasUnsavedChanges: () => boolean;
|
||||||
markAsSaved: () => void;
|
markAsSaved: () => void;
|
||||||
setupNavigationGuard: (onBlock?: (location: Location) => void) => () => void;
|
setupNavigationGuard: (onBlock?: (location: Location) => void) => () => void;
|
||||||
|
enableReactRouterGuard: () => void;
|
||||||
|
disableReactRouterGuard: () => void;
|
||||||
|
routerGuardEnabledRef: React.MutableRefObject<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useForm = (initialState: FormState): UseFormReturn => {
|
export const useForm = (initialState: FormState): UseFormReturn => {
|
||||||
@ -581,6 +584,18 @@ export const useForm = (initialState: FormState): UseFormReturn => {
|
|||||||
initialDataRef.current = JSON.parse(JSON.stringify(state.data));
|
initialDataRef.current = JSON.parse(JSON.stringify(state.data));
|
||||||
}, [state.data]);
|
}, [state.data]);
|
||||||
|
|
||||||
|
// React Router navigation guard state
|
||||||
|
const routerGuardEnabledRef = useRef<boolean>(true);
|
||||||
|
|
||||||
|
// Setup React Router blocker for in-app navigation
|
||||||
|
const enableReactRouterGuard = useCallback((): void => {
|
||||||
|
routerGuardEnabledRef.current = true;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const disableReactRouterGuard = useCallback((): void => {
|
||||||
|
routerGuardEnabledRef.current = false;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const setupNavigationGuard = useCallback(
|
const setupNavigationGuard = useCallback(
|
||||||
(onBlock?: (location: Location) => void): (() => void) => {
|
(onBlock?: (location: Location) => void): (() => void) => {
|
||||||
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
|
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
|
||||||
@ -633,6 +648,9 @@ export const useForm = (initialState: FormState): UseFormReturn => {
|
|||||||
hasUnsavedChanges,
|
hasUnsavedChanges,
|
||||||
markAsSaved,
|
markAsSaved,
|
||||||
setupNavigationGuard,
|
setupNavigationGuard,
|
||||||
|
enableReactRouterGuard,
|
||||||
|
disableReactRouterGuard,
|
||||||
|
routerGuardEnabledRef,
|
||||||
};
|
};
|
||||||
Object.defineProperty(api, "schema", {
|
Object.defineProperty(api, "schema", {
|
||||||
get: () => schemaRef.current,
|
get: () => schemaRef.current,
|
||||||
@ -643,3 +661,34 @@ export const useForm = (initialState: FormState): UseFormReturn => {
|
|||||||
|
|
||||||
return api as UseFormReturn;
|
return api as UseFormReturn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to enable React Router data router navigation blocking.
|
||||||
|
*
|
||||||
|
* Call this hook in your component to enable navigation guards for React Router's data router.
|
||||||
|
* This is optional and only needed if you're using RouterProvider (not BrowserRouter).
|
||||||
|
* The browserunload guard from useForm still works regardless.
|
||||||
|
*
|
||||||
|
* @param formApi The return value from useForm
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // In your component that is inside a data router:
|
||||||
|
* import { useBlocker } from "react-router-dom";
|
||||||
|
*
|
||||||
|
* const MyEditForm = () => {
|
||||||
|
* const form = useForm(initialState);
|
||||||
|
*
|
||||||
|
* // Only call this if inside RouterProvider (data router)
|
||||||
|
* const blocker = useBlocker(({ currentLocation, nextLocation }) =>
|
||||||
|
* form.routerGuardEnabledRef.current &&
|
||||||
|
* form.hasUnsavedChanges() &&
|
||||||
|
* currentLocation.pathname !== nextLocation.pathname
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* return (...);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const useFormRouterBlocker = (formApi: UseFormReturn): void => {
|
||||||
|
// This is a documentation function - actual implementation is done in the component
|
||||||
|
// See the example above for how to properly set up router blocking with useBlocker
|
||||||
|
};
|
||||||
|
|||||||
159
src/components/common/useFormRouter.ts
Normal file
159
src/components/common/useFormRouter.ts
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
|
import { UseFormReturn, useForm, FormState } from "./useForm";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for BrowserRouter navigation blocking with unsaved changes.
|
||||||
|
*
|
||||||
|
* Works with BrowserRouter (standard routing, not data router).
|
||||||
|
* Shows a confirmation dialog when user attempts to navigate away with unsaved changes.
|
||||||
|
*
|
||||||
|
* @param formApi - The return value from useForm()
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const form = useForm(initialState);
|
||||||
|
* useBrowserRouterFormGuard(form);
|
||||||
|
*/
|
||||||
|
export const useBrowserRouterFormGuard = (formApi: UseFormReturn): void => {
|
||||||
|
const location = useLocation();
|
||||||
|
const { hasUnsavedChanges, routerGuardEnabledRef, disableReactRouterGuard } =
|
||||||
|
formApi;
|
||||||
|
const previousLocationRef = useRef(location);
|
||||||
|
const pendingNavigationRef = useRef<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// If navigation was attempted and we're at a new location
|
||||||
|
if (
|
||||||
|
location.pathname !== previousLocationRef.current.pathname &&
|
||||||
|
pendingNavigationRef.current
|
||||||
|
) {
|
||||||
|
// Navigation succeeded, reset
|
||||||
|
previousLocationRef.current = location;
|
||||||
|
pendingNavigationRef.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we need to guard against navigation
|
||||||
|
if (
|
||||||
|
hasUnsavedChanges() &&
|
||||||
|
routerGuardEnabledRef.current &&
|
||||||
|
pendingNavigationRef.current === null
|
||||||
|
) {
|
||||||
|
// Store the current location for comparison
|
||||||
|
previousLocationRef.current = location;
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
location,
|
||||||
|
hasUnsavedChanges,
|
||||||
|
routerGuardEnabledRef,
|
||||||
|
disableReactRouterGuard,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Intercept navigation attempts by wrapping navigate
|
||||||
|
useEffect(() => {
|
||||||
|
// Override the window's history behavior to catch navigation attempts
|
||||||
|
const originalPushState = window.history.pushState;
|
||||||
|
const originalReplaceState = window.history.replaceState;
|
||||||
|
|
||||||
|
const handleNavigation = (
|
||||||
|
method: (state: any, title: string, url?: string | null) => void,
|
||||||
|
state: any,
|
||||||
|
title: string,
|
||||||
|
url?: string | null,
|
||||||
|
) => {
|
||||||
|
if (
|
||||||
|
hasUnsavedChanges() &&
|
||||||
|
routerGuardEnabledRef.current &&
|
||||||
|
url &&
|
||||||
|
url !== window.location.pathname + window.location.search
|
||||||
|
) {
|
||||||
|
// Prompt user
|
||||||
|
const confirmed = window.confirm(
|
||||||
|
"You have unsaved changes. Do you want to leave without saving?",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (confirmed) {
|
||||||
|
disableReactRouterGuard();
|
||||||
|
method.call(window.history, state, title, url);
|
||||||
|
setTimeout(() => {
|
||||||
|
formApi.enableReactRouterGuard();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
method.call(window.history, state, title, url);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.history.pushState = function (state, title, url) {
|
||||||
|
handleNavigation(originalPushState, state, title, url);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.history.replaceState = function (state, title, url) {
|
||||||
|
handleNavigation(originalReplaceState, state, title, url);
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.history.pushState = originalPushState;
|
||||||
|
window.history.replaceState = originalReplaceState;
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
hasUnsavedChanges,
|
||||||
|
routerGuardEnabledRef,
|
||||||
|
disableReactRouterGuard,
|
||||||
|
formApi,
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to enable React Router data router navigation blocking.
|
||||||
|
*
|
||||||
|
* Call this hook in your component to enable navigation guards for React Router's data router.
|
||||||
|
* This is optional and only needed if you're using RouterProvider (not BrowserRouter).
|
||||||
|
* The beforeunload guard from useForm still works regardless.
|
||||||
|
*
|
||||||
|
* @param formApi The return value from useForm
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // In your component that is inside a data router:
|
||||||
|
* import { useBlocker } from "react-router-dom";
|
||||||
|
*
|
||||||
|
* const MyEditForm = () => {
|
||||||
|
* const form = useForm(initialState);
|
||||||
|
*
|
||||||
|
* // Only call this if inside RouterProvider (data router)
|
||||||
|
* const blocker = useBlocker(({ currentLocation, nextLocation }) =>
|
||||||
|
* form.routerGuardEnabledRef.current &&
|
||||||
|
* form.hasUnsavedChanges() &&
|
||||||
|
* currentLocation.pathname !== nextLocation.pathname
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* return (...);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const useFormRouterBlocker = (formApi: UseFormReturn): void => {
|
||||||
|
// This is a documentation function - actual implementation is done in the component
|
||||||
|
// See the example above for how to properly set up router blocking with useBlocker
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combined hook that creates a form with automatic unsaved changes navigation guard.
|
||||||
|
*
|
||||||
|
* This is the recommended way to create forms with navigation protection in BrowserRouter apps.
|
||||||
|
* It combines useForm() and useBrowserRouterFormGuard() into a single call.
|
||||||
|
*
|
||||||
|
* @param initialState - The initial form state
|
||||||
|
* @returns The form API with navigation guard already set up
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Instead of:
|
||||||
|
* const form = useForm(initialState);
|
||||||
|
* useBrowserRouterFormGuard(form);
|
||||||
|
*
|
||||||
|
* // Just use:
|
||||||
|
* const form = useFormWithGuard(initialState);
|
||||||
|
*/
|
||||||
|
export const useFormWithGuard = (initialState: FormState): UseFormReturn => {
|
||||||
|
const form = useForm(initialState);
|
||||||
|
useBrowserRouterFormGuard(form);
|
||||||
|
return form;
|
||||||
|
};
|
||||||
@ -4,7 +4,6 @@ import Joi from "joi";
|
|||||||
import authentication from "../services/authenticationService";
|
import authentication from "../services/authenticationService";
|
||||||
import { InputType } from "../../../components/common/Input";
|
import { InputType } from "../../../components/common/Input";
|
||||||
import { ButtonType } from "../../../components/common/Button";
|
import { ButtonType } from "../../../components/common/Button";
|
||||||
import { useForm } from "../../../components/common/useForm";
|
|
||||||
import {
|
import {
|
||||||
renderButton,
|
renderButton,
|
||||||
renderError,
|
renderError,
|
||||||
@ -12,6 +11,7 @@ import {
|
|||||||
} from "../../../components/common/formHelpers";
|
} from "../../../components/common/formHelpers";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Namespaces } from "../../../i18n/i18n";
|
import { Namespaces } from "../../../i18n/i18n";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
const InternalLoginForm: React.FC = () => {
|
const InternalLoginForm: React.FC = () => {
|
||||||
const { t } = useTranslation(Namespaces.Common);
|
const { t } = useTranslation(Namespaces.Common);
|
||||||
@ -19,7 +19,7 @@ const InternalLoginForm: React.FC = () => {
|
|||||||
const [emailSent, setEmailSent] = useState(false);
|
const [emailSent, setEmailSent] = useState(false);
|
||||||
const passwordMaxLength = 255;
|
const passwordMaxLength = 255;
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: true,
|
loaded: true,
|
||||||
data: {
|
data: {
|
||||||
username: "",
|
username: "",
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import {
|
|||||||
SystemGlossaries,
|
SystemGlossaries,
|
||||||
} from "../glossary/services/glossaryService";
|
} from "../glossary/services/glossaryService";
|
||||||
import Loading from "../../../components/common/Loading";
|
import Loading from "../../../components/common/Loading";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface CustomFieldDetailsProps {
|
interface CustomFieldDetailsProps {
|
||||||
editMode?: boolean;
|
editMode?: boolean;
|
||||||
@ -54,7 +55,7 @@ const CustomFieldDetails: React.FC<CustomFieldDetailsProps> = ({
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -318,6 +319,8 @@ const CustomFieldDetails: React.FC<CustomFieldDetailsProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buttonName === "save") form.setState({ redirect: "/customfields" });
|
if (buttonName === "save") form.setState({ redirect: "/customfields" });
|
||||||
|
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import {
|
|||||||
renderButton,
|
renderButton,
|
||||||
renderUserPicker,
|
renderUserPicker,
|
||||||
} from "../../../../components/common/formHelpers";
|
} from "../../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface LocAddUserToRoleProps {
|
interface LocAddUserToRoleProps {
|
||||||
isEditMode: boolean;
|
isEditMode: boolean;
|
||||||
@ -29,7 +30,7 @@ const AddUserToRole: React.FC<LocAddUserToRoleProps> = ({ isEditMode }) => {
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: true,
|
loaded: true,
|
||||||
data: {
|
data: {
|
||||||
userId: undefined,
|
userId: undefined,
|
||||||
@ -57,6 +58,8 @@ const AddUserToRole: React.FC<LocAddUserToRoleProps> = ({ isEditMode }) => {
|
|||||||
form.setState({
|
form.setState({
|
||||||
redirect: `/domains/edit/${domainId}#securityRoles/${roleId}/users`,
|
redirect: `/domains/edit/${domainId}#securityRoles/${roleId}/users`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
form.markAsSaved();
|
||||||
}
|
}
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import {
|
|||||||
renderInput,
|
renderInput,
|
||||||
renderTemplateEditor,
|
renderTemplateEditor,
|
||||||
} from "../../../../components/common/formHelpers";
|
} from "../../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface EmailTemplateEditorProps {
|
interface EmailTemplateEditorProps {
|
||||||
domainId?: string;
|
domainId?: string;
|
||||||
@ -33,7 +34,7 @@ const EmailTemplateEditor: React.FC<EmailTemplateEditorProps> = ({
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
currentMailType: undefined,
|
currentMailType: undefined,
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
renderInput,
|
renderInput,
|
||||||
renderSsoProviderPicker,
|
renderSsoProviderPicker,
|
||||||
} from "../../../../components/common/formHelpers";
|
} from "../../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface GeneralTabProps {
|
interface GeneralTabProps {
|
||||||
isEditMode: boolean;
|
isEditMode: boolean;
|
||||||
@ -34,7 +35,7 @@ const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -117,6 +118,7 @@ const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buttonName === "save") form.setState({ redirect: "/domains" });
|
if (buttonName === "save") form.setState({ redirect: "/domains" });
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import {
|
|||||||
renderButton,
|
renderButton,
|
||||||
renderInput,
|
renderInput,
|
||||||
} from "../../../../components/common/formHelpers";
|
} from "../../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface RolesDetailsProps {
|
interface RolesDetailsProps {
|
||||||
isEditMode: boolean;
|
isEditMode: boolean;
|
||||||
@ -30,7 +31,7 @@ const RolesDetails: React.FC<RolesDetailsProps> = ({ isEditMode }) => {
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
renderInput,
|
renderInput,
|
||||||
renderTemplateEditor,
|
renderTemplateEditor,
|
||||||
} from "../../../components/common/formHelpers";
|
} from "../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
const FormsDetails: React.FC<{ editMode?: boolean }> = ({
|
const FormsDetails: React.FC<{ editMode?: boolean }> = ({
|
||||||
editMode = false,
|
editMode = false,
|
||||||
@ -28,7 +29,7 @@ const FormsDetails: React.FC<{ editMode?: boolean }> = ({
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -93,6 +94,7 @@ const FormsDetails: React.FC<{ editMode?: boolean }> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buttonName === "save") form.setState({ redirect: "/forms" });
|
if (buttonName === "save") form.setState({ redirect: "/forms" });
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import {
|
|||||||
renderCustomFields,
|
renderCustomFields,
|
||||||
renderCustomFieldsEditor,
|
renderCustomFieldsEditor,
|
||||||
} from "../../../components/common/formHelpers";
|
} from "../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface GlossariesDetailsProps {
|
interface GlossariesDetailsProps {
|
||||||
editMode?: boolean;
|
editMode?: boolean;
|
||||||
@ -38,7 +39,7 @@ const GlossariesDetails: React.FC<GlossariesDetailsProps> = ({
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
@ -182,6 +183,7 @@ const GlossariesDetails: React.FC<GlossariesDetailsProps> = ({
|
|||||||
const navigateId = parentGlossary ? parentGlossary.id.toString() : "";
|
const navigateId = parentGlossary ? parentGlossary.id.toString() : "";
|
||||||
if (buttonName === "save")
|
if (buttonName === "save")
|
||||||
form.setState({ redirect: "/glossaries/" + navigateId });
|
form.setState({ redirect: "/glossaries/" + navigateId });
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
renderInput,
|
renderInput,
|
||||||
renderSelect,
|
renderSelect,
|
||||||
} from "../../../components/common/formHelpers";
|
} from "../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
const OrganisationsDetails: React.FC<{ editMode?: boolean }> = ({
|
const OrganisationsDetails: React.FC<{ editMode?: boolean }> = ({
|
||||||
editMode = false,
|
editMode = false,
|
||||||
@ -36,7 +37,7 @@ const OrganisationsDetails: React.FC<{ editMode?: boolean }> = ({
|
|||||||
{ _id: "Blocked", name: t("Blocked") },
|
{ _id: "Blocked", name: t("Blocked") },
|
||||||
];
|
];
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -112,6 +113,7 @@ const OrganisationsDetails: React.FC<{ editMode?: boolean }> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buttonName === "save") form.setState({ redirect: "/organisations" });
|
if (buttonName === "save") form.setState({ redirect: "/organisations" });
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import sequenceService from "./services/sequenceService";
|
|||||||
import Option from "../../../components/common/option";
|
import Option from "../../../components/common/option";
|
||||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import Loading from "../../../components/common/Loading";
|
import Loading from "../../../components/common/Loading";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface SequenceDetailsProps {
|
interface SequenceDetailsProps {
|
||||||
editMode?: boolean;
|
editMode?: boolean;
|
||||||
@ -37,7 +38,7 @@ const SequenceDetails: React.FC<SequenceDetailsProps> = ({
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -131,6 +132,7 @@ const SequenceDetails: React.FC<SequenceDetailsProps> = ({
|
|||||||
if (buttonName === "save") {
|
if (buttonName === "save") {
|
||||||
form.setState({ redirect: "/sequence" });
|
form.setState({ redirect: "/sequence" });
|
||||||
}
|
}
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
|||||||
import Option from "../../../components/common/option";
|
import Option from "../../../components/common/option";
|
||||||
import siteService from "./services/sitessService";
|
import siteService from "./services/sitessService";
|
||||||
import Loading from "../../../components/common/Loading";
|
import Loading from "../../../components/common/Loading";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface SiteDetailsProps {
|
interface SiteDetailsProps {
|
||||||
editMode?: boolean;
|
editMode?: boolean;
|
||||||
@ -35,7 +36,7 @@ const SiteDetails: React.FC<SiteDetailsProps> = ({ editMode = false }) => {
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -118,6 +119,7 @@ const SiteDetails: React.FC<SiteDetailsProps> = ({ editMode = false }) => {
|
|||||||
if (buttonName === "save") {
|
if (buttonName === "save") {
|
||||||
form.setState({ redirect: "/site/" + organisationId });
|
form.setState({ redirect: "/site/" + organisationId });
|
||||||
}
|
}
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import {
|
|||||||
renderError,
|
renderError,
|
||||||
renderGlossaryPicker,
|
renderGlossaryPicker,
|
||||||
} from "../../../components/common/formHelpers";
|
} from "../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface SpecificationsDetailsProps {
|
interface SpecificationsDetailsProps {
|
||||||
editMode?: boolean;
|
editMode?: boolean;
|
||||||
@ -44,7 +45,7 @@ const SpecificationsDetails: React.FC<SpecificationsDetailsProps> = ({
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -193,6 +194,7 @@ const SpecificationsDetails: React.FC<SpecificationsDetailsProps> = ({
|
|||||||
redirect: "/Specifications/" + organisationId + "/" + siteId,
|
redirect: "/Specifications/" + organisationId + "/" + siteId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { Navigate, useParams, useLocation } from "react-router-dom";
|
|||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Namespaces } from "../../../i18n/i18n";
|
import { Namespaces } from "../../../i18n/i18n";
|
||||||
import { useForm } from "../../../components/common/useForm";
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
import { InputType } from "../../../components/common/Input";
|
import { InputType } from "../../../components/common/Input";
|
||||||
import {
|
import {
|
||||||
renderInput,
|
renderInput,
|
||||||
@ -37,7 +37,7 @@ const SsoProviderDetails: React.FC<SsoProviderDetailsProps> = ({
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -155,6 +155,8 @@ const SsoProviderDetails: React.FC<SsoProviderDetailsProps> = ({
|
|||||||
if (buttonName === "save") {
|
if (buttonName === "save") {
|
||||||
form.setState({ redirect: "/ssoManager" });
|
form.setState({ redirect: "/ssoManager" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
@ -286,7 +288,7 @@ const SsoProviderDetails: React.FC<SsoProviderDetailsProps> = ({
|
|||||||
|
|
||||||
{editMode && <div>Redirect URL: {redirectUrl}</div>}
|
{editMode && <div>Redirect URL: {redirectUrl}</div>}
|
||||||
|
|
||||||
{editMode && renderButton(labelApply, form.state.errors, "save")}
|
{editMode && renderButton(labelApply, form.state.errors, "apply")}
|
||||||
{renderButton(labelSave, form.state.errors, "save")}
|
{renderButton(labelSave, form.state.errors, "save")}
|
||||||
</form>
|
</form>
|
||||||
</Loading>
|
</Loading>
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
renderError,
|
renderError,
|
||||||
renderDomainPicker,
|
renderDomainPicker,
|
||||||
} from "../../../../components/common/formHelpers";
|
} from "../../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../../components/common/useFormRouter";
|
||||||
|
|
||||||
interface GeneralTabProps {
|
interface GeneralTabProps {
|
||||||
isEditMode: boolean;
|
isEditMode: boolean;
|
||||||
@ -35,7 +36,7 @@ const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
|
|||||||
const labelApply = t("Save");
|
const labelApply = t("Save");
|
||||||
const labelSave = t("SaveAndClose");
|
const labelSave = t("SaveAndClose");
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
firstName: "",
|
firstName: "",
|
||||||
@ -131,6 +132,7 @@ const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
|
|||||||
if (buttonName === "save") {
|
if (buttonName === "save") {
|
||||||
form.setState({ redirect: "/users" });
|
form.setState({ redirect: "/users" });
|
||||||
}
|
}
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,12 +16,12 @@ import {
|
|||||||
renderButton,
|
renderButton,
|
||||||
renderError,
|
renderError,
|
||||||
} from "../../../components/common/formHelpers";
|
} from "../../../components/common/formHelpers";
|
||||||
import { useForm } from "../../../components/common/useForm";
|
|
||||||
import ErrorBlock from "../../../components/common/ErrorBlock";
|
import ErrorBlock from "../../../components/common/ErrorBlock";
|
||||||
import authentication from "../../frame/services/authenticationService";
|
import authentication from "../../frame/services/authenticationService";
|
||||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import { CustomFieldValue } from "../glossary/services/glossaryService";
|
import { CustomFieldValue } from "../glossary/services/glossaryService";
|
||||||
import TasksTab from "./components/TasksTab";
|
import TasksTab from "./components/TasksTab";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
|
const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
|
||||||
editMode,
|
editMode,
|
||||||
@ -31,7 +31,7 @@ const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
|
|||||||
const [activeTab, setActiveTab] = React.useState("general");
|
const [activeTab, setActiveTab] = React.useState("general");
|
||||||
|
|
||||||
// useForm promoted to the parent
|
// useForm promoted to the parent
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -112,6 +112,8 @@ const WorkflowTemplateDetails: React.FC<{ editMode: boolean }> = ({
|
|||||||
if (buttonName === "save") {
|
if (buttonName === "save") {
|
||||||
form.setState({ ...form.state, redirect: "/workflowTemplates" });
|
form.setState({ ...form.state, redirect: "/workflowTemplates" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form.markAsSaved();
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
form.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {
|
|||||||
} from "../services/WorkflowTemplateService";
|
} from "../services/WorkflowTemplateService";
|
||||||
import AddTaskButton from "./AddTaskButton";
|
import AddTaskButton from "./AddTaskButton";
|
||||||
import { Namespaces } from "../../../../i18n/i18n";
|
import { Namespaces } from "../../../../i18n/i18n";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
interface TaskListProps {
|
interface TaskListProps {
|
||||||
tasks: TaskDefinition[];
|
tasks: TaskDefinition[];
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
renderToggle,
|
renderToggle,
|
||||||
renderDropSection,
|
renderDropSection,
|
||||||
} from "../../../components/common/formHelpers";
|
} from "../../../components/common/formHelpers";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
|
||||||
const InternalProfile: React.FC = () => {
|
const InternalProfile: React.FC = () => {
|
||||||
const { t } = useTranslation(Namespaces.Common);
|
const { t } = useTranslation(Namespaces.Common);
|
||||||
@ -35,7 +36,7 @@ const InternalProfile: React.FC = () => {
|
|||||||
qrCodeImageUrl: "",
|
qrCodeImageUrl: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const form = useForm({
|
const form = useFormWithGuard({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
firstName: "",
|
firstName: "",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user