From 64084679e8ac921bf5006018c89c939c83cf8307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Sat, 6 Jun 2026 21:31:03 +0300 Subject: [PATCH] Workflow problemleri --- .../ListForms/ListFormWizardAppService.cs | 2 +- .../Seeds/LanguagesData.json | 6 ++ .../Seeds/ListFormSeeder_Administration.cs | 2 +- .../Seeds/WizardDataSeeder.cs | 2 +- .../WizardConsts.cs | 4 +- ui/src/utils/workflow/workflowHelpers.ts | 5 +- .../admin/listForm/edit/FormTabWorkflow.tsx | 12 ++-- .../admin/listForm/wizard/WizardStep2.tsx | 14 +++- .../admin/listForm/wizard/WizardStep6.tsx | 3 +- .../admin/listForm/wizard/WizardStep7.tsx | 9 ++- .../listForm/workflow/WorkflowCriteria.tsx | 24 ++++--- .../developerKit/SqlTableDesignerDialog.tsx | 68 ++++++++++++++++++- ui/src/views/list/Grid.tsx | 10 +-- ui/src/views/list/Tree.tsx | 10 +-- ui/src/views/list/useToolbar.tsx | 7 +- 15 files changed, 132 insertions(+), 46 deletions(-) diff --git a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs index 2322385..e787a2d 100644 --- a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs +++ b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs @@ -305,7 +305,7 @@ public class ListFormWizardAppService( HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson, SearchPanelJson = WizardConsts.DefaultSearchPanelJson, GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), - SelectionJson = WizardConsts.DefaultSelectionSingleJson, + SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.Widgets.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone), ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(), PermissionJson = WizardConsts.DefaultPermissionJson(code), DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null, diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json index c767f9d..413716c 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json @@ -18038,6 +18038,12 @@ "en": "Add Multi-Tenant Column", "tr": "MultiTenant Sütunları Ekle" }, + { + "resourceName": "Platform", + "key": "App.SqlQueryManager.AddWorkflowColumns", + "en": "Add Workflow Column", + "tr": "Workflow Sütunları Ekle" + }, { "resourceName": "Platform", "key": "App.SqlQueryManager.ClearAllColumns", diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs index d4280d9..7e7a06f 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs @@ -797,7 +797,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, listFormName, PlatformConsts.IdentityPermissions.Users.Update, PlatformConsts.IdentityPermissions.Users.Delete, PlatformConsts.IdentityPermissions.Users.Export, PlatformConsts.IdentityPermissions.Users.Import, PlatformConsts.IdentityPermissions.Users.Note), DeleteCommand = $"UPDATE \"AbpUsers\" SET \"DeleterId\"=@DeleterId, \"DeletionTime\"=CURRENT_TIMESTAMP, \"IsDeleted\"='true' WHERE \"Id\"=@Id", DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(), - EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 730, true, true, true, true, false), + EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 710, true, true, true, true, false), EditingFormJson = JsonSerializer.Serialize(new List() { new () { Order=1,ColCount=1,ColSpan=1,ItemType="group",Items=[ new EditingFormItemDto { Order=1, DataField="Email", ColSpan=1, IsRequired=true, EditorType2=EditorTypes.dxTextBox }, diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs index 7fe2dc2..228b72b 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs @@ -352,7 +352,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson, SearchPanelJson = WizardConsts.DefaultSearchPanelJson, GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), - SelectionJson = WizardConsts.DefaultSelectionSingleJson, + SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.Widgets.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone), ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(), PermissionJson = WizardConsts.DefaultPermissionJson(code), DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null, diff --git a/api/src/Sozsoft.Platform.Domain.Shared/WizardConsts.cs b/api/src/Sozsoft.Platform.Domain.Shared/WizardConsts.cs index 384b78f..41d5e40 100644 --- a/api/src/Sozsoft.Platform.Domain.Shared/WizardConsts.cs +++ b/api/src/Sozsoft.Platform.Domain.Shared/WizardConsts.cs @@ -95,9 +95,9 @@ public static class WizardConsts public static readonly string DefaultSearchPanelJson = JsonSerializer.Serialize(new { Visible = true }); public static readonly string DefaultGroupPanelJson = JsonSerializer.Serialize(new { Visible = true }); - public static readonly string DefaultSelectionSingleJson = JsonSerializer.Serialize(new + public static string DefaultSelectionSingleJson(string Mode = "none") => JsonSerializer.Serialize(new { - Mode = GridOptions.SelectionModeNone, + Mode = Mode, AllowSelectAll = false }); diff --git a/ui/src/utils/workflow/workflowHelpers.ts b/ui/src/utils/workflow/workflowHelpers.ts index 3cd8971..1e3d0da 100644 --- a/ui/src/utils/workflow/workflowHelpers.ts +++ b/ui/src/utils/workflow/workflowHelpers.ts @@ -347,7 +347,8 @@ export function toCriteriaForm(item: WorkflowCriteriaDto): WorkflowCriteriaForm } export function normalizeCriteria(item: WorkflowCriteriaForm): SaveCriteriaInput { - const sharedPerson = item.approver || '' + const sharedPerson = + item.kind === 'Approval' || item.kind === 'Inform' ? item.approver || '' : '' const compareOutcomes = (item.compareOutcomes || []) .slice(0, 4) .filter((outcome) => outcome.label?.trim()) @@ -504,7 +505,7 @@ export function criteriaSummary(item: WorkflowCriteriaDto) { if (item.kind === 'Approval' || item.kind === 'Inform') { return `${item.title} ${item.approver ? `- ${item.approver}` : ''}` } - return `${item.title} ${item.approver ? `- ${item.approver}` : ''}` + return item.title } export function targetTitle(criteria: WorkflowCriteriaDto[], id?: string | null) { diff --git a/ui/src/views/admin/listForm/edit/FormTabWorkflow.tsx b/ui/src/views/admin/listForm/edit/FormTabWorkflow.tsx index 0396129..b74df42 100644 --- a/ui/src/views/admin/listForm/edit/FormTabWorkflow.tsx +++ b/ui/src/views/admin/listForm/edit/FormTabWorkflow.tsx @@ -296,10 +296,12 @@ export function FormTabWorkflow( } const schema = object().shape({ - approvalUserFieldName: string().required(), - approvalStatusFieldName: string().required(), - approvalDateFieldName: string(), - approvalDescriptionFieldName: string(), + workflowDto: object().shape({ + approvalUserFieldName: string().required(), + approvalStatusFieldName: string().required(), + approvalDateFieldName: string(), + approvalDescriptionFieldName: string(), + }), }) const initialValues = useStoreState((s) => s.admin.lists.values) @@ -423,7 +425,7 @@ export function FormTabWorkflow( - diff --git a/ui/src/views/admin/listForm/wizard/WizardStep2.tsx b/ui/src/views/admin/listForm/wizard/WizardStep2.tsx index 18b9dd5..689a337 100644 --- a/ui/src/views/admin/listForm/wizard/WizardStep2.tsx +++ b/ui/src/views/admin/listForm/wizard/WizardStep2.tsx @@ -2,7 +2,7 @@ import { Button, Checkbox, FormItem, Input, Select } from '@/components/ui' import { SelectCommandTypeEnum } from '@/proxy/form/models' import type { DatabaseColumnDto, SqlObjectExplorerDto } from '@/proxy/sql-query-manager/models' import { SelectBoxOption } from '@/types/shared' -import { Field, FieldProps, FormikErrors, FormikTouched } from 'formik' +import { Field, FieldProps, FormikErrors, FormikTouched, useFormikContext } from 'formik' import { useState } from 'react' import CreatableSelect from 'react-select/creatable' import { FaArrowLeft, FaArrowRight, FaPlus } from 'react-icons/fa' @@ -68,6 +68,16 @@ const WizardStep2 = ({ onNext, }: WizardStep2Props) => { const [showTableDesignerDialog, setShowTableDesignerDialog] = useState(false) + const formik = useFormikContext() + + const handleTableDeployed = async (table: { schemaName: string; tableName: string }) => { + await onDbObjectsRefresh(values.dataSourceCode) + formik.setFieldValue('selectCommand', table.tableName) + formik.setFieldValue('selectCommandType', SelectCommandTypeEnum.Table) + formik.setFieldValue('keyFieldName', '') + formik.setFieldTouched('keyFieldName', false) + onLoadColumns(values.dataSourceCode, table.schemaName || 'dbo', table.tableName) + } const step2Missing = [ !values.listFormCode && translate('::App.Listform.ListformField.ListFormCode'), @@ -825,7 +835,7 @@ const WizardStep2 = ({ onClose={() => setShowTableDesignerDialog(false)} dataSource={values.dataSourceCode} initialTableData={null} - onDeployed={() => onDbObjectsRefresh(values.dataSourceCode)} + onDeployed={handleTableDeployed} /> ) diff --git a/ui/src/views/admin/listForm/wizard/WizardStep6.tsx b/ui/src/views/admin/listForm/wizard/WizardStep6.tsx index 07a8090..dd7ab27 100644 --- a/ui/src/views/admin/listForm/wizard/WizardStep6.tsx +++ b/ui/src/views/admin/listForm/wizard/WizardStep6.tsx @@ -16,6 +16,7 @@ import { useEffect, useMemo, useRef, useState } from 'react' import type { FormEvent } from 'react' import { FaArrowLeft, FaArrowRight } from 'react-icons/fa' import { WorkflowDesigner } from '../workflow/WorkflowDesigner' +import { IdentityUserDto } from '@/proxy/admin/models' type Props = { listFormCode: string @@ -77,7 +78,7 @@ function WizardStep6({ useEffect(() => { getUsers(0, 1000).then((response) => { setUserList( - (response.data?.items ?? []).map((user: any) => ({ + (response.data?.items ?? []).map((user: IdentityUserDto) => ({ value: user.userName, label: `${user.userName} (${user.name} ${user.surname})`, })), diff --git a/ui/src/views/admin/listForm/wizard/WizardStep7.tsx b/ui/src/views/admin/listForm/wizard/WizardStep7.tsx index af70057..f00db37 100644 --- a/ui/src/views/admin/listForm/wizard/WizardStep7.tsx +++ b/ui/src/views/admin/listForm/wizard/WizardStep7.tsx @@ -476,9 +476,12 @@ const WizardStep7 = ({ {criteria.compareColumn} {criteria.compareOperator} {criteria.compareValue} )} -
- Approver: {criteria.approver} -
+ {(criteria.kind === 'Approval' || criteria.kind === 'Inform') && + criteria.approver && ( +
+ Approver: {criteria.approver} +
+ )} ))} diff --git a/ui/src/views/admin/listForm/workflow/WorkflowCriteria.tsx b/ui/src/views/admin/listForm/workflow/WorkflowCriteria.tsx index a587318..477e196 100644 --- a/ui/src/views/admin/listForm/workflow/WorkflowCriteria.tsx +++ b/ui/src/views/admin/listForm/workflow/WorkflowCriteria.tsx @@ -257,17 +257,19 @@ export function WorkflowCriteria({ onChange={(event) => setField('title', event.target.value)} /> - - setField('approver', value)} - /> - + {(formValues.kind === 'Approval' || formValues.kind === 'Inform') && ( + + setField('approver', value)} + /> + + )} {(formValues.kind === 'Start' || formValues.kind === 'Inform') && ( void dataSource: string | null - onDeployed?: () => void + onDeployed?: (table: { schemaName: string; tableName: string }) => void | Promise initialTableData?: { schemaName: string; tableName: string } | null } @@ -98,6 +99,7 @@ const DATA_TYPES: { value: SqlDataType; label: string }[] = [ { value: 'decimal', label: 'Decimal (decimal 18,4)' }, { value: 'float', label: 'Float (float)' }, { value: 'bit', label: 'Bool (bit)' }, + { value: 'datetime', label: 'DateTime (datetime)' }, { value: 'datetime2', label: 'DateTime (datetime2)' }, { value: 'date', label: 'Date (date)' }, { value: 'uniqueidentifier', label: 'Guid (uniqueidentifier)' }, @@ -226,6 +228,45 @@ const TENANT_COLUMN: ColumnDefinition = { description: 'Tenant ID for multi-tenancy', } +const WORKFLOW_COLUMNS: ColumnDefinition[] = [ + { + id: '__ApprovalUserId', + columnName: 'ApprovalUserName', + dataType: 'nvarchar', + maxLength: '256', + isNullable: true, + defaultValue: '', + description: 'Workflow approval user name', + }, + { + id: '__ApprovalStatus', + columnName: 'ApprovalStatus', + dataType: 'nvarchar', + maxLength: '50', + isNullable: true, + defaultValue: '', + description: 'Workflow approval status', + }, + { + id: '__ApprovalDate', + columnName: 'ApprovalDate', + dataType: 'datetime', + maxLength: '', + isNullable: true, + defaultValue: '', + description: 'Workflow approval date', + }, + { + id: '__ApprovalDescription', + columnName: 'ApprovalDescription', + dataType: 'nvarchar', + maxLength: '200', + isNullable: true, + defaultValue: '', + description: 'Workflow approval description', + }, +] + const CREATE_TABLE_SCRIPT_STORAGE_KEY = 'sqlQueryManager.lastCreateTableScript' // ─── T-SQL Generator ────────────────────────────────────────────────────────── @@ -405,6 +446,8 @@ function dbColToColumnDef(col: { dataType = 'float' } else if (dt === 'bit') { dataType = 'bit' + } else if (dt === 'datetime') { + dataType = 'datetime' } else if (dt.startsWith('datetime') || dt === 'smalldatetime') { dataType = 'datetime2' } else if (dt === 'date') { @@ -476,6 +519,7 @@ function mapSqlTypeToDesigner(dataTypeRaw: string, lengthRaw: string): { if (dt === 'decimal' || dt === 'numeric') return { dataType: 'decimal', maxLength: '' } if (dt === 'float' || dt === 'real') return { dataType: 'float', maxLength: '' } if (dt === 'bit') return { dataType: 'bit', maxLength: '' } + if (dt === 'datetime') return { dataType: 'datetime', maxLength: '' } if (dt.startsWith('datetime') || dt === 'smalldatetime' || dt === 'time') { return { dataType: 'datetime2', maxLength: '' } } @@ -1224,6 +1268,18 @@ const SqlTableDesignerDialog = ({ } } + const addWorkflowColumns = () => { + const existingNames = new Set(columns.map((c) => c.columnName.trim().toLowerCase())) + const toAdd = WORKFLOW_COLUMNS.filter((c) => !existingNames.has(c.columnName.toLowerCase())) + + if (toAdd.length > 0) { + setColumns((prev) => { + const nonEmpty = prev.filter((c) => c.columnName.trim() !== '') + return [...nonEmpty, ...toAdd.map((c) => ({ ...c })), createEmptyColumn()] + }) + } + } + const importColumnsFromRememberedCreateTable = async () => { let script = '' @@ -1591,7 +1647,10 @@ const SqlTableDesignerDialog = ({ } catch { // Non-blocking: seed file save failure does not affect deploy success } - onDeployed?.() + await onDeployed?.({ + schemaName: initialTableData?.schemaName || 'dbo', + tableName: deployedTable, + }) handleClose() } else { toast.push( @@ -1690,6 +1749,9 @@ const SqlTableDesignerDialog = ({ +