diff --git a/judo-ui-react/src/main/resources/actor/src/components/dialog/StackableDialogProvider.tsx.hbs b/judo-ui-react/src/main/resources/actor/src/components/dialog/StackableDialogProvider.tsx.hbs index 9809567a..c1567583 100644 --- a/judo-ui-react/src/main/resources/actor/src/components/dialog/StackableDialogProvider.tsx.hbs +++ b/judo-ui-react/src/main/resources/actor/src/components/dialog/StackableDialogProvider.tsx.hbs @@ -5,71 +5,79 @@ import { useRef, createContext, useContext, useState } from 'react'; import Dialog from '@mui/material/Dialog'; import type { DialogProps } from '@mui/material'; import { SlideUpTransition } from '~/theme/animations'; +import { dialogStackCloseDelay } from '~/config'; export type DialogOption = Omit; -type ProviderContext = readonly [(option: DialogOption) => void, () => void, () => void]; +type ProviderContext = readonly [(option: DialogOption) => void, () => Promise, () => Promise]; -const EMPTY_FUNC = () => {}; -const DialogContext = createContext([ - EMPTY_FUNC, - EMPTY_FUNC, - EMPTY_FUNC, -]); +const EMPTY_FUNC = () => undefined; +const EMPTY_ASYNC_FUNC = () => Promise.resolve(); +const DialogContext = createContext([EMPTY_FUNC, EMPTY_ASYNC_FUNC, EMPTY_ASYNC_FUNC]); export const useDialog = () => useContext(DialogContext); export function StackableDialogProvider({ children }: { children: ReactNode }) { - const [dialogs, setDialogs] = useState([]); - const createDialog = (option: DialogOption) => { - const dialog = { ...option, open: true }; - setDialogs((d) => [...d, dialog]); - }; - const closeDialog = () => { - setDialogs((d) => { - // const tmp = d[d.length - 1]; - // - // if (tmp && tmp.disableBackdropClick && reason === 'backdropClick') { - // return d; - // } + const [dialogs, setDialogs] = useState([]); + const createDialog = (option: DialogOption) => { + const dialog = { ...option, open: true }; + setDialogs((d) => [...d, dialog]); + }; + const closeDialog: () => Promise = async () => { + return new Promise((resolve, reject) => { + setDialogs((d) => { + // const tmp = d[d.length - 1]; + // + // if (tmp && tmp.disableBackdropClick && reason === 'backdropClick') { + // return d; + // } - const latestDialog = d.pop(); - if (!latestDialog) return d; - // if (latestDialog.onClose) latestDialog.onClose({}, undefined); - latestDialog.open = false - return [...d]; - // return [...d].concat({ ...latestDialog, open: false }); - }); - }; - const closeAllDialogs = () => { - setDialogs((d) => { - for (const dialog of d) { - dialog.open = false; - } - return []; - }); - }; - const contextValue = useRef([createDialog, closeDialog, closeAllDialogs] as const); + const latestDialog = d.pop(); + if (!latestDialog) return d; + // if (latestDialog.onClose) latestDialog.onClose({}, undefined); + latestDialog.open = false + return [...d]; + // return [...d].concat({ ...latestDialog, open: false }); + }); + window.setTimeout(() => { + resolve(undefined); + }, dialogStackCloseDelay); + }); + }; + const closeAllDialogs: () => Promise = async () => { + return new Promise((resolve, reject) => { + setDialogs((d) => { + for (const dialog of d) { + dialog.open = false; + } + return []; + }); + window.setTimeout(() => { + resolve(undefined); + }, dialogStackCloseDelay); + }); + }; + const contextValue = useRef([createDialog, closeDialog, closeAllDialogs] as const); - return ( - - {children} - {dialogs.map((dialog, i) => { - const { ...dialogParams } = dialog; - // const handleKill = () => { - // if (dialog.onExited) dialog.onExited(); - // setDialogs((dialogs) => dialogs.slice(0, dialogs.length - 1)); - // }; + return ( + + {children} + {dialogs.map((dialog, i) => { + const { ...dialogParams } = dialog; + // const handleKill = () => { + // if (dialog.onExited) dialog.onExited(); + // setDialogs((dialogs) => dialogs.slice(0, dialogs.length - 1)); + // }; - return ( - - ); - })} - - ); + return ( + + ); + })} + + ); } diff --git a/judo-ui-react/src/main/resources/actor/src/config/general.ts.hbs b/judo-ui-react/src/main/resources/actor/src/config/general.ts.hbs index 7b554592..af03c981 100644 --- a/judo-ui-react/src/main/resources/actor/src/config/general.ts.hbs +++ b/judo-ui-react/src/main/resources/actor/src/config/general.ts.hbs @@ -34,3 +34,5 @@ export const debounceInputs: number = 500; export const animationDuration: number = 0.8; export const delayDuration: number = 0.2; + +export const dialogStackCloseDelay: number = 50; diff --git a/judo-ui-react/src/main/resources/actor/src/containers/dialog.tsx.hbs b/judo-ui-react/src/main/resources/actor/src/containers/dialog.tsx.hbs index 142e70ec..7d09e4a7 100644 --- a/judo-ui-react/src/main/resources/actor/src/containers/dialog.tsx.hbs +++ b/judo-ui-react/src/main/resources/actor/src/containers/dialog.tsx.hbs @@ -37,7 +37,7 @@ import { useConfirmDialog } from '~/components/dialog'; export interface {{ containerComponentName container }}DialogProps { ownerData: any; title: string; - onClose: () => void; + onClose: () => Promise; {{# unless (containerIsEmptyDashboard container) }} actions: {{ containerComponentName container }}DialogActions; isLoading: boolean; diff --git a/judo-ui-react/src/main/resources/actor/src/dialogs/index.tsx.hbs b/judo-ui-react/src/main/resources/actor/src/dialogs/index.tsx.hbs index 2a0b58ef..b3d6701d 100644 --- a/judo-ui-react/src/main/resources/actor/src/dialogs/index.tsx.hbs +++ b/judo-ui-react/src/main/resources/actor/src/dialogs/index.tsx.hbs @@ -42,16 +42,18 @@ import { useCallback, useEffect, useRef, useState, lazy, Suspense } from 'react' {{/ unless }} {{# unless (containerIsEmptyDashboard page.container) }} - export const {{ camelCaseNameToInterfaceKey (pageName page) }}_ACTIONS_HOOK_INTERFACE_KEY = '{{ containerComponentName page.container }}ActionsHook'; export type {{ containerComponentName page.container }}DialogActionsExtended = {{ containerComponentName page.container }}DialogActions & { {{# each (getAllCallOperationActions page) as |action| }} post{{ firstToUpper (simpleActionDefinitionName action.actionDefinition) }}?: ( {{# if action.actionDefinition.targetType }}target: {{ classDataName action.actionDefinition.targetType 'Stored' }},{{/ if }} {{# if action.actionDefinition.operation.output }}output: {{ classDataName action.actionDefinition.operation.output.target '' }},{{/ if }} - {{# if page.container.form }}onSubmit: (result?: {{# if (pageHasOutputTarget page) }}{{ classDataName (getPageOutputTarget page) 'Stored' }}{{ else }}{{ dialogDataType page }}{{# if page.container.table }}[]{{/ if }}{{/ if }}) => void{{/ if }} + {{# if page.container.form }}onSubmit: (result?: {{# if (pageHasOutputTarget page) }}{{ classDataName (getPageOutputTarget page) 'Stored' }}{{ else }}{{ dialogDataType page }}{{# if page.container.table }}[]{{/ if }}{{/ if }}) => Promise,{{/ if }} + onClose: () => Promise ) => Promise; {{/ each }} }; + + export const {{ camelCaseNameToInterfaceKey (pageName page) }}_ACTIONS_HOOK_INTERFACE_KEY = '{{ containerComponentName page.container }}ActionsHook'; export type {{ containerComponentName page.container }}ActionsHook = ( ownerData: any, data: {{ dialogDataType page }}{{# if page.container.table }}[]{{/ if }}, @@ -77,9 +79,9 @@ import { useCallback, useEffect, useRef, useState, lazy, Suspense } from 'react' fullWidth: true, maxWidth: '{{ toLower page.dialogSize.name }}', {{/ if }} - onClose: (event: object, reason: string) => { + onClose: async (event: object, reason: string) => { if (reason !== 'backdropClick') { - closeDialog(); + await closeDialog(); resolve({ result: 'close', }); @@ -91,14 +93,14 @@ import { useCallback, useEffect, useRef, useState, lazy, Suspense } from 'react' {{# if page.container.isRelationSelector}} alreadySelected={alreadySelected} {{/ if }} - onClose={() => { - closeDialog(); + onClose={async () => { + await closeDialog(); resolve({ result: 'close', }); }} - onSubmit={({{# if (dialogHasResult page) }}result{{/ if }}) => { - closeDialog(); + onSubmit={async ({{# if (dialogHasResult page) }}result{{/ if }}) => { + await closeDialog(); resolve({ result: 'submit', {{# if (dialogHasResult page) }} @@ -123,11 +125,11 @@ import { useCallback, useEffect, useRef, useState, lazy, Suspense } from 'react' export interface {{ pageName page }}Props { ownerData: any; {{# if page.container.isRelationSelector }}alreadySelected: {{ classDataName (getReferenceClassType page) 'Stored' }}[]{{/ if }} - onClose: () => void; + onClose: () => Promise; {{# if (pageHasOutputTarget page) }} - onSubmit: (result?: {{ classDataName (getPageOutputTarget page) 'Stored' }}) => void; + onSubmit: (result?: {{ classDataName (getPageOutputTarget page) 'Stored' }}) => Promise; {{ else }} - onSubmit: (result?: {{ dialogDataType page }}{{# if page.container.table }}[]{{/ if }}) => void; + onSubmit: (result?: {{ dialogDataType page }}{{# if page.container.table }}[]{{/ if }}) => Promise; {{/ if }} } diff --git a/judo-ui-react/src/main/resources/actor/src/pages/actions/CallOperationAction.fragment.hbs b/judo-ui-react/src/main/resources/actor/src/pages/actions/CallOperationAction.fragment.hbs index 429554cb..be582901 100644 --- a/judo-ui-react/src/main/resources/actor/src/pages/actions/CallOperationAction.fragment.hbs +++ b/judo-ui-react/src/main/resources/actor/src/pages/actions/CallOperationAction.fragment.hbs @@ -34,7 +34,8 @@ const {{ simpleActionDefinitionName action.actionDefinition }} = async ({{# if a await customActions.post{{ firstToUpper (simpleActionDefinitionName action.actionDefinition) }}( {{# if action.actionDefinition.targetType }}target!,{{/ if }} {{# if operation.output }}result,{{/ if }} - {{# if page.container.form }}onSubmit{{/ if }} + {{# if page.container.form }}onSubmit,{{/ if }} + {{# if page.openInDialog }}onClose{{/ if }} ); } else { enqueueSnackbar(t('judo.action.operation.success', { defaultValue: 'Operation executed successfully' }) as string, { diff --git a/judo-ui-react/src/main/resources/actor/src/pages/actions/OpenFormAction.fragment.hbs b/judo-ui-react/src/main/resources/actor/src/pages/actions/OpenFormAction.fragment.hbs index da3a7d3e..764884e8 100644 --- a/judo-ui-react/src/main/resources/actor/src/pages/actions/OpenFormAction.fragment.hbs +++ b/judo-ui-react/src/main/resources/actor/src/pages/actions/OpenFormAction.fragment.hbs @@ -2,12 +2,14 @@ const {{ simpleActionDefinitionName action.actionDefinition }} = async ({{# if a const { result, data: returnedData } = await open{{ pageName action.targetPageDefinition }}({{# if action.actionDefinition.targetType }}target{{ else }}data{{/ if }}); {{# with (getRefreshActionDefinitionForContainer page.container) as |actionDefinition| }} {{# if page.container.view }} - if (!editMode) { + if (result === 'submit' && !editMode) { await actions.{{ simpleActionDefinitionName actionDefinition }}!(processQueryCustomizer(pageQueryCustomizer)); } {{/ if }} {{# if page.container.table }} - setRefreshCounter((prev) => prev + 1); + if (result === 'submit') { + setRefreshCounter((prev) => prev + 1); + } {{/ if }} {{/ with }} }; diff --git a/judo-ui-react/src/main/resources/actor/src/pages/index.tsx.hbs b/judo-ui-react/src/main/resources/actor/src/pages/index.tsx.hbs index c5d08fe2..55d53b23 100644 --- a/judo-ui-react/src/main/resources/actor/src/pages/index.tsx.hbs +++ b/judo-ui-react/src/main/resources/actor/src/pages/index.tsx.hbs @@ -43,12 +43,13 @@ import { useCallback, useEffect, useRef, useState, lazy, Suspense } from 'react' {{/ unless }} {{# unless (containerIsEmptyDashboard page.container) }} - export const {{ camelCaseNameToInterfaceKey (pageName page) }}_ACTIONS_HOOK_INTERFACE_KEY = '{{ containerComponentName page.container }}ActionsHook'; export type {{ containerComponentName page.container }}PageActionsExtended = {{ containerComponentName page.container }}PageActions & { {{# each (getAllCallOperationActions page) as |action| }} post{{ firstToUpper (simpleActionDefinitionName action.actionDefinition) }}?: ({{# if action.actionDefinition.targetType }}target: {{ classDataName action.actionDefinition.targetType 'Stored' }}{{/ if }}{{# if action.actionDefinition.operation.output }}{{# if action.actionDefinition.targetType }},{{/ if }}output: {{ classDataName action.actionDefinition.operation.output.target '' }}{{/ if }}) => Promise; {{/ each }} }; + + export const {{ camelCaseNameToInterfaceKey (pageName page) }}_ACTIONS_HOOK_INTERFACE_KEY = '{{ containerComponentName page.container }}ActionsHook'; export type {{ containerComponentName page.container }}ActionsHook = ( data: {{ classDataName (getReferenceClassType page) 'Stored' }}{{# if page.container.table }}[]{{/ if }}, editMode: boolean,