From 1d05d24e4178186d0b25833df16861c9134c0ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Mon, 13 Jul 2026 20:29:53 +0300 Subject: [PATCH] =?UTF-8?q?Form=20i=C3=A7erisindeki=20Workflow=20custom=20?= =?UTF-8?q?butonlar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/src/views/form/FormButtons.tsx | 79 ++++++++++++++++++++++++------- ui/src/views/form/FormView.tsx | 2 +- ui/src/views/list/useToolbar.tsx | 47 ++++++++++++++++++ ui/src/views/menu/MenuManager.tsx | 8 +++- ui/vite.config.ts | 9 ++-- 5 files changed, 122 insertions(+), 23 deletions(-) diff --git a/ui/src/views/form/FormButtons.tsx b/ui/src/views/form/FormButtons.tsx index 4aa3045..f0da2f3 100644 --- a/ui/src/views/form/FormButtons.tsx +++ b/ui/src/views/form/FormButtons.tsx @@ -15,13 +15,14 @@ import { } from 'react-icons/fa' import { useNavigate } from 'react-router-dom' import { GridColumnData } from '../list/GridColumnData' -import { useToolbar } from '../list/useToolbar' +import { isWorkflowToolbarItemDisabled, useToolbar } from '../list/useToolbar' import { PermissionResults, RowMode } from './types' import { GridDto } from '@/proxy/form/models' import { ROUTES_ENUM } from '@/routes/route.constant' import { usePermission } from '@/utils/hooks/usePermission' import { usePWA } from '@/utils/hooks/usePWA' import { layoutTypes } from '../admin/listForm/edit/types' +import { useStoreState } from '@/store' const FormButtons = (props: { isSubForm?: boolean @@ -68,7 +69,7 @@ const FormButtons = (props: { const { translate } = useLocalization() const layout = layoutTypes.grid - const { toolbarData } = useToolbar({ + const { toolbarData, toolbarModalData, setToolbarModalData } = useToolbar({ gridDto, listFormCode, getSelectedRowKeys, @@ -78,6 +79,52 @@ const FormButtons = (props: { layout, }) + const currentUser = useStoreState((state) => state.auth.user) + const selectedRowData = getSelectedRowsData()?.[0] + const rowEvent = { + row: { + data: selectedRowData, + key: id, + rowType: 'data', + isEditing: mode === 'edit', + }, + } + + const resolveVisible = (visible: unknown) => { + if (typeof visible !== 'function') { + return visible !== false + } + + try { + return Boolean(visible(rowEvent)) + } catch (error) { + console.error('Button visibility evaluation error:', error) + return false + } + } + + const isToolbarButtonVisible = (item: any) => + item.widget === 'dxButton' && + !toolbarExcludedNames.includes(item.name) && + resolveVisible(item.visible) && + resolveVisible(item.options?.visible) + + const isCommandButtonVisible = (item: any) => + typeof item !== 'string' && + !commandExcludedNames.includes(item.name) && + resolveVisible(item.visible) + + const isToolbarButtonDisabled = (item: any) => { + const workflowDisabled = isWorkflowToolbarItemDisabled( + item.name, + gridDto.gridOptions.workflowDto, + selectedRowData ? [selectedRowData] : [], + currentUser, + ) + + return workflowDisabled ?? Boolean(item.options?.disabled) + } + const openDynamicGridReport = () => { if (!id) return @@ -116,22 +163,16 @@ const FormButtons = (props: { } const toolbarExcludedNames = ['deleteAllRecords', 'deleteSelectedRecords', 'refreshButton'] - const hasVisibleToolbarButtons = toolbarData?.some( - (item) => item.widget == 'dxButton' && !toolbarExcludedNames.includes(item.name!), - ) + const hasVisibleToolbarButtons = toolbarData?.some(isToolbarButtonVisible) const commandExcludedNames = ['edit', 'delete', 'detail'] - const hasVisibleCommandButtons = commandColumnData?.buttons?.some( - (item) => typeof item !== 'string' && !commandExcludedNames.includes(item.name!), - ) + const hasVisibleCommandButtons = commandColumnData?.buttons?.some(isCommandButtonVisible) return ( <>
{toolbarData - ?.filter( - (item) => item.widget == 'dxButton' && !toolbarExcludedNames.includes(item.name!), - ) + ?.filter(isToolbarButtonVisible) .map((item, i) => { const IconComp = navigationIcon[item.options?.icon] const hasValidIcon = @@ -145,7 +186,8 @@ const FormButtons = (props: { variant="default" size="sm" icon={hasValidIcon ? : null} - onClick={item.options?.onClick} + disabled={isToolbarButtonDisabled(item)} + onClick={(e) => item.options?.onClick?.({ ...e, ...rowEvent })} > {item.options?.text} @@ -155,7 +197,7 @@ const FormButtons = (props: { {hasVisibleToolbarButtons && } {commandColumnData?.buttons - ?.filter((item) => typeof item !== 'string' && !commandExcludedNames.includes(item.name!)) + ?.filter(isCommandButtonVisible) .map((item: any, i) => { return ( )}
+ setToolbarModalData(undefined)} + onRequestClose={() => setToolbarModalData(undefined)} + > + {toolbarModalData?.content} + {}} - refreshData={() => {}} + refreshData={fetchData} getSelectedRowKeys={() => [id]} getSelectedRowsData={() => [formData]} getFilter={() => filter} diff --git a/ui/src/views/list/useToolbar.tsx b/ui/src/views/list/useToolbar.tsx index 5f4828f..4480fda 100644 --- a/ui/src/views/list/useToolbar.tsx +++ b/ui/src/views/list/useToolbar.tsx @@ -655,6 +655,53 @@ function getCurrentUserWorkflowIdentities(currentUser?: { return [currentUser?.email, currentUser?.userName, currentUser?.name].filter(Boolean) as string[] } +export function isWorkflowToolbarItemDisabled( + itemName: string | undefined, + workflowOptions: WorkflowDto | undefined, + selectedRowsData: Record[] = [], + currentUser?: { + userName?: string + email?: string + name?: string + }, +) { + if (!itemName || !workflowOptions?.approvalStatusFieldName) { + return undefined + } + + if (itemName === 'workflowStart') { + return ( + selectedRowsData.length === 0 || + !selectedRowsData.every((row) => isWorkflowNotStarted(row, workflowOptions)) + ) + } + + if (!itemName.startsWith('workflowApproval_')) { + return undefined + } + + const criteriaId = itemName.replace('workflowApproval_', '') + const criteria = workflowOptions.criteria?.find( + (item) => item.kind === 'Approval' && item.id === criteriaId, + ) + if (!criteria) { + return true + } + + const currentUserIdentities = getCurrentUserWorkflowIdentities(currentUser) + return ( + selectedRowsData.length === 0 || + !selectedRowsData.every((row) => + isWorkflowApprovalCriteriaActive( + row, + workflowOptions, + criteria.title, + currentUserIdentities, + ), + ) + ) +} + export function updateWorkflowApprovalToolbarItems( component: any, workflowOptions: WorkflowDto | undefined, diff --git a/ui/src/views/menu/MenuManager.tsx b/ui/src/views/menu/MenuManager.tsx index 4500435..df5ead4 100644 --- a/ui/src/views/menu/MenuManager.tsx +++ b/ui/src/views/menu/MenuManager.tsx @@ -108,11 +108,15 @@ export const MenuManager = () => { Design Mode