diff --git a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/ListFormWizardDto.cs b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/ListFormWizardDto.cs index 44d6f6b..2d0234d 100644 --- a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/ListFormWizardDto.cs +++ b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/ListFormWizardDto.cs @@ -68,5 +68,8 @@ public class ListFormWizardDto public string SchedulerEndDateExpr { get; set; } public List Groups { get; set; } = new(); + public List SubForms { get; set; } = new(); + public List Widgets { get; set; } = new(); + public WorkflowDto Workflow { get; set; } = new(); + public List WorkflowCriteria { get; set; } = new(); } - diff --git a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs index 1bf184d..262c059 100644 --- a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs +++ b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs @@ -27,6 +27,7 @@ public class ListFormWizardAppService( IRepository repoListForm, IRepository repoListFormField, IRepository repoDataSource, + IRepository repoListFormWorkflow, IRepository repoLangKey, IRepository repoLangText, IRepository repoPerm, @@ -42,6 +43,7 @@ public class ListFormWizardAppService( private readonly IRepository repoListForm = repoListForm; private readonly IRepository repoListFormField = repoListFormField; private readonly IRepository repoDataSource = repoDataSource; + private readonly IRepository repoListFormWorkflow = repoListFormWorkflow; private readonly IRepository repoLangKey = repoLangKey; private readonly IRepository repoLangText = repoLangText; private readonly IRepository repoPerm = repoPerm; @@ -244,9 +246,17 @@ public class ListFormWizardAppService( await repoListFormField.DeleteManyAsync(existingListFormFields, autoSave: true); } + var existingWorkflowCriteria = await repoListFormWorkflow.GetListAsync(a => a.ListFormCode == input.ListFormCode); + if (existingWorkflowCriteria.Count > 0) + { + await repoListFormWorkflow.DeleteManyAsync(existingWorkflowCriteria, autoSave: true); + } + var tableColumns = await GetTableColumnNamesAsync(input.DataSourceCode, input.SelectCommandType, input.SelectCommand); var isDeleted = tableColumns.Contains("IsDeleted"); var isCreated = tableColumns.Contains("CreatorId"); + input.Workflow ??= new WorkflowDto(); + input.Workflow.Criteria = input.WorkflowCriteria; var listForm = await repoListForm.InsertAsync(new ListForm { @@ -254,7 +264,7 @@ public class ListFormWizardAppService( PageSize = 10, ExportJson = WizardConsts.DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = input.SubForms.Count > 0, LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler), CultureName = LanguageCodes.En, ListFormCode = input.ListFormCode, @@ -284,6 +294,9 @@ public class ListFormWizardAppService( PagerOptionJson = WizardConsts.DefaultPagerOptionJson, EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail), EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null, + SubFormsJson = input.SubForms.Count > 0 ? JsonSerializer.Serialize(input.SubForms) : null, + WidgetsJson = input.Widgets.Count > 0 ? JsonSerializer.Serialize(input.Widgets) : null, + WorkflowJson = HasWorkflow(input.Workflow, input.WorkflowCriteria) ? JsonSerializer.Serialize(input.Workflow) : null, TreeOptionJson = (input.Tree || input.DefaultLayout == "tree") && !string.IsNullOrEmpty(input.TreeParentIdExpr) ? JsonSerializer.Serialize(new TreeOptionDto { @@ -329,6 +342,7 @@ public class ListFormWizardAppService( Visible = item.DataField != input.KeyFieldName, IsActive = true, AllowSearch = true, + Width = 0, ListOrderNo = fieldOrder, SourceDbType = item.DbSourceType, CultureName = PlatformConsts.DefaultLanguage, @@ -343,6 +357,33 @@ public class ListFormWizardAppService( } } + foreach (var criteria in input.WorkflowCriteria) + { + if (string.IsNullOrWhiteSpace(criteria.Id)) + { + continue; + } + + await repoListFormWorkflow.InsertAsync(new ListFormWorkflow(criteria.Id) + { + ListFormCode = input.ListFormCode, + Kind = criteria.Kind, + Title = criteria.Title, + CompareColumn = criteria.CompareColumn, + CompareOperator = criteria.CompareOperator, + CompareValue = criteria.CompareValue, + Approver = criteria.Approver, + NextOnStart = criteria.NextOnStart, + NextOnTrue = criteria.NextOnTrue, + NextOnFalse = criteria.NextOnFalse, + NextOnApprove = criteria.NextOnApprove, + NextOnReject = criteria.NextOnReject, + PositionX = criteria.PositionX, + PositionY = criteria.PositionY, + CompareOutcomesJson = JsonSerializer.Serialize(criteria.CompareOutcomes ?? []), + }, autoSave: true); + } + // Clear Redis Cache await _languageTextAppService.ClearRedisCacheAsync(); @@ -350,6 +391,17 @@ public class ListFormWizardAppService( await SaveWizardSeedFileAsync(input, isDeleted, isCreated, inserted); } + private static bool HasWorkflow(WorkflowDto workflow, List criteria) + { + return workflow != null && ( + !string.IsNullOrWhiteSpace(workflow.ApprovalUserFieldName) || + !string.IsNullOrWhiteSpace(workflow.ApprovalDateFieldName) || + !string.IsNullOrWhiteSpace(workflow.ApprovalStatusFieldName) || + !string.IsNullOrWhiteSpace(workflow.ApprovalDescriptionFieldName) || + criteria.Count > 0 + ); + } + /// /// Wizard konfigürasyonunu JSON dosyası olarak kaydeder. /// Önce ContentRootPath'ten yukarı çıkarak Sozsoft.Platform.DbMigrator/Seeds/WizardData dizinini arar. diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json index 95680ab..a2fc82d 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json @@ -17803,12 +17803,6 @@ "key": "App.SqlQueryManager.NoIndexesDefined", "en": "No indexes defined", "tr": "Dizin tanımlanmamış" - }, - { - "resourceName": "Platform", - "key": "App.SqlQueryManager.NoIndexesDefined", - "en": "No indexes defined", - "tr": "Dizin tanımlanmamış" }, { "resourceName": "Platform", diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs index dd00645..1d550c8 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs @@ -60,7 +60,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -183,7 +183,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson("tree"), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -417,7 +417,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -635,7 +635,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -771,7 +771,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1171,7 +1171,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1370,7 +1370,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1498,7 +1498,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1695,7 +1695,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1789,7 +1789,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -2046,7 +2046,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -2190,7 +2190,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -2383,7 +2383,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson("tree"), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -2499,7 +2499,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson("tree"), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -2643,7 +2643,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -3268,7 +3268,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = true, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -3548,7 +3548,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = true, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -3856,7 +3856,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -3961,7 +3961,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -4049,7 +4049,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -4444,7 +4444,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs index 31edef7..2b9707e 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs @@ -560,7 +560,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = true, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1018,7 +1018,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1178,7 +1178,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1323,7 +1323,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1436,7 +1436,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1581,7 +1581,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1671,7 +1671,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -1867,7 +1867,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -2003,7 +2003,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -2274,7 +2274,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = true, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -2477,7 +2477,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -2894,7 +2894,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = true, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -3040,7 +3040,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = true, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -3147,7 +3147,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -3694,7 +3694,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = true, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -3868,7 +3868,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -4005,7 +4005,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -4496,7 +4496,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -4586,7 +4586,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -4828,7 +4828,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -5029,7 +5029,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -5267,7 +5267,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -5442,7 +5442,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -5624,7 +5624,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -5713,7 +5713,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson("tree"), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -6029,7 +6029,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -6258,7 +6258,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -6493,7 +6493,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -6627,7 +6627,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -7291,7 +7291,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = true, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -7459,7 +7459,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -7660,7 +7660,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, @@ -8015,7 +8015,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = false, LayoutJson = DefaultLayoutJson(), CultureName = LanguageCodes.En, ListFormCode = listFormName, diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/PermissionsData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/PermissionsData.json index c836c28..d27534c 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/PermissionsData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/PermissionsData.json @@ -82,6 +82,15 @@ "MultiTenancySide": 2, "MenuGroup": "Erp|Kurs" }, + { + "GroupName": "App.Saas", + "Name": "AbpTenantManagement.Tenants.Note", + "ParentName": "AbpTenantManagement.Tenants", + "DisplayName": "Note", + "IsEnabled": true, + "MultiTenancySide": 2, + "MenuGroup": "Erp|Kurs" + }, { "GroupName": "App.Saas", "Name": "App.Branches", @@ -1765,6 +1774,15 @@ "MultiTenancySide": 2, "MenuGroup": "Erp|Kurs" }, + { + "GroupName": "App.Saas", + "Name": "App.Orders.SalesOrders.Note", + "ParentName": "App.Orders.SalesOrders", + "DisplayName": "Note", + "IsEnabled": true, + "MultiTenancySide": 2, + "MenuGroup": "Erp|Kurs" + }, { "GroupName": "App.Saas", "Name": "App.Orders.SalesOrderItem", @@ -3556,15 +3574,6 @@ "MultiTenancySide": 3, "MenuGroup": "Erp|Kurs" }, - { - "GroupName": "App.Administration", - "Name": "App.Intranet.Events.EventType.Note", - "ParentName": "App.Intranet.Events.EventType", - "DisplayName": "Note", - "IsEnabled": true, - "MultiTenancySide": 3, - "MenuGroup": "Erp|Kurs" - }, { "GroupName": "App.Administration", "Name": "App.Intranet.Events.EventCategory", @@ -3619,15 +3628,6 @@ "MultiTenancySide": 3, "MenuGroup": "Erp|Kurs" }, - { - "GroupName": "App.Administration", - "Name": "App.Intranet.Events.EventCategory.Note", - "ParentName": "App.Intranet.Events.EventCategory", - "DisplayName": "Note", - "IsEnabled": true, - "MultiTenancySide": 3, - "MenuGroup": "Erp|Kurs" - }, { "GroupName": "App.Administration", "Name": "App.Intranet.Events.Event", @@ -3754,15 +3754,6 @@ "MultiTenancySide": 3, "MenuGroup": "Erp|Kurs" }, - { - "GroupName": "App.Administration", - "Name": "App.Intranet.Events.EventLike.Note", - "ParentName": "App.Intranet.Events.EventLike", - "DisplayName": "Note", - "IsEnabled": true, - "MultiTenancySide": 3, - "MenuGroup": "Erp|Kurs" - }, { "GroupName": "App.Administration", "Name": "App.Intranet.Announcement", @@ -3817,15 +3808,6 @@ "MultiTenancySide": 3, "MenuGroup": "Erp|Kurs" }, - { - "GroupName": "App.Administration", - "Name": "App.Intranet.Announcement.Note", - "ParentName": "App.Intranet.Announcement", - "DisplayName": "Note", - "IsEnabled": true, - "MultiTenancySide": 3, - "MenuGroup": "Erp|Kurs" - }, { "GroupName": "App.Administration", "Name": "App.Intranet.Announcement.Widget", @@ -3961,15 +3943,6 @@ "MultiTenancySide": 3, "MenuGroup": "Erp|Kurs" }, - { - "GroupName": "App.Administration", - "Name": "App.Intranet.SocialComment.Note", - "ParentName": "App.Intranet.SocialComment", - "DisplayName": "Note", - "IsEnabled": true, - "MultiTenancySide": 3, - "MenuGroup": "Erp|Kurs" - }, { "GroupName": "App.Administration", "Name": "App.Intranet.Survey", @@ -4159,15 +4132,6 @@ "MultiTenancySide": 3, "MenuGroup": "Erp" }, - { - "GroupName": "App.Administration", - "Name": "App.Intranet.SurveyQuestionOption.Note", - "ParentName": "App.Intranet.SurveyQuestionOption", - "DisplayName": "Note", - "IsEnabled": true, - "MultiTenancySide": 3, - "MenuGroup": "Erp" - }, { "GroupName": "App.Administration", "Name": "App.Intranet.SurveyResponse", @@ -4285,15 +4249,6 @@ "MultiTenancySide": 3, "MenuGroup": "Erp" }, - { - "GroupName": "App.Administration", - "Name": "App.Intranet.SurveyAnswer.Note", - "ParentName": "App.Intranet.SurveyAnswer", - "DisplayName": "Note", - "IsEnabled": true, - "MultiTenancySide": 3, - "MenuGroup": "Erp" - }, { "GroupName": "App.Administration", "Name": "App.Videoroom", diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs index 2962b7b..4b9bd05 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs @@ -130,6 +130,11 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency var input = seedFile.Wizard; var isDeleted = seedFile.IsDeletedField; var isCreated = seedFile.IsCreatedField; + input.SubForms ??= new List(); + input.Widgets ??= new List(); + input.Workflow ??= new WorkflowDto(); + input.WorkflowCriteria ??= new List(); + input.Workflow.Criteria = input.WorkflowCriteria; var wizardName = input.WizardName.Trim(); var titleLangKey = WizardConsts.WizardKeyTitle(wizardName); @@ -306,7 +311,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency PageSize = 10, ExportJson = WizardConsts.DefaultExportJson, IsSubForm = false, - ShowNote = true, + ShowNote = input.SubForms.Count > 0, LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler), CultureName = LanguageCodes.En, ListFormCode = input.ListFormCode, @@ -340,6 +345,9 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency PagerOptionJson = WizardConsts.DefaultPagerOptionJson, EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail), EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null, + SubFormsJson = input.SubForms.Count > 0 ? JsonSerializer.Serialize(input.SubForms) : null, + WidgetsJson = input.Widgets.Count > 0 ? JsonSerializer.Serialize(input.Widgets) : null, + WorkflowJson = HasWorkflow(input.Workflow, input.WorkflowCriteria) ? JsonSerializer.Serialize(input.Workflow) : null, }, autoSave: true); // ListFormFields @@ -375,6 +383,17 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency } } + private static bool HasWorkflow(WorkflowDto workflow, List criteria) + { + return workflow != null && ( + !string.IsNullOrWhiteSpace(workflow.ApprovalUserFieldName) || + !string.IsNullOrWhiteSpace(workflow.ApprovalDateFieldName) || + !string.IsNullOrWhiteSpace(workflow.ApprovalStatusFieldName) || + !string.IsNullOrWhiteSpace(workflow.ApprovalDescriptionFieldName) || + (criteria?.Count ?? 0) > 0 + ); + } + private async Task CreateLangKeyAsync(string key, string textEn, string textTr) { if (string.IsNullOrWhiteSpace(key)) return; diff --git a/ui/src/proxy/admin/wizard/models.ts b/ui/src/proxy/admin/wizard/models.ts index b1e3b27..962e319 100644 --- a/ui/src/proxy/admin/wizard/models.ts +++ b/ui/src/proxy/admin/wizard/models.ts @@ -1,5 +1,11 @@ -import { SelectCommandTypeEnum } from "@/proxy/form/models" -import { ListViewLayoutType } from "@/views/admin/listForm/edit/types" +import { SelectCommandTypeEnum } from '@/proxy/form/models' +import { + ListFormWorkflowCriteriaDto, + SubFormDto, + WidgetEditDto, + WorkflowDto, +} from '@/proxy/form/models' +import { ListViewLayoutType } from '@/views/admin/listForm/edit/types' export interface ListFormWizardColumnItemDto { dataField: string @@ -76,6 +82,10 @@ export interface ListFormWizardDto { schedulerEndDateExpr?: string groups?: ListFormWizardColumnGroupDto[] + subForms?: SubFormDto[] + widgets?: WidgetEditDto[] + workflow?: WorkflowDto + workflowCriteria?: ListFormWorkflowCriteriaDto[] } export interface WizardFileInfoDto { @@ -128,4 +138,4 @@ export interface WizardSeedFileDto { isDeletedField: boolean isCreatedField: boolean insertedRecords: WizardInsertedRecordsDto -} \ No newline at end of file +} diff --git a/ui/src/views/admin/listForm/edit/FormTabPermissions.tsx b/ui/src/views/admin/listForm/edit/FormTabPermissions.tsx index 9b2f095..85bc33c 100644 --- a/ui/src/views/admin/listForm/edit/FormTabPermissions.tsx +++ b/ui/src/views/admin/listForm/edit/FormTabPermissions.tsx @@ -18,7 +18,7 @@ const schema = object().shape({ d: string(), e: string(), i: string(), - a: string(), + n: string(), }) function FormTabPermissions(props: FormEditProps) { @@ -210,31 +210,34 @@ function FormTabPermissions(props: FormEditProps) { )} - - - {({ field, form }: FieldProps) => ( - option.value === values.permissionDto.n, + )} + onChange={(option) => form.setFieldValue(field.name, option?.value)} + /> + )} + + + )} - - - - )} - + + )} + /> + + + + + + + + + )} + )} {data.operation === 'delete' && ( { - setSubmitting(true) - try { - await deleteListFormJsonRow(data.id, data.tabName, values.index) - toast.push(Kayıt silindi ) - handleClose() - } catch (error: any) { - toast.push( - - Hata - {error} - , - { placement: 'top-end' }, - ) - } finally { - setSubmitting(false) - } - // getListFormJsonRow() - }} - > - {({ isSubmitting }) => ( -
- -
Delete
-

Silmek istediğinize emin misiniz?

-
- - - - -
- )} -
+ initialValues={data} + onSubmit={async (values, { setSubmitting }) => { + setSubmitting(true) + try { + await deleteListFormJsonRow(data.id, data.tabName, values.index) + toast.push(Kayıt silindi ) + handleClose() + } catch (error: any) { + toast.push( + + Hata + {error} + , + { placement: 'top-end' }, + ) + } finally { + setSubmitting(false) + } + // getListFormJsonRow() + }} + > + {({ isSubmitting }) => ( +
+ +
Delete
+

Silmek istediğinize emin misiniz?

+
+ + + + +
+ )} + )} ) diff --git a/ui/src/views/admin/listForm/wizard/Wizard.tsx b/ui/src/views/admin/listForm/wizard/Wizard.tsx index 2d8e345..67e3701 100644 --- a/ui/src/views/admin/listForm/wizard/Wizard.tsx +++ b/ui/src/views/admin/listForm/wizard/Wizard.tsx @@ -23,13 +23,22 @@ import WizardStep1, { } from './WizardStep1' import WizardStep2 from './WizardStep2' import WizardStep3, { WizardGroup, WizardGroupItem } from './WizardStep3' +import WizardStep7 from './WizardStep7' import WizardStep4 from './WizardStep4' +import WizardStep5 from './WizardStep5' +import WizardStep6 from './WizardStep6' import { Container } from '@/components/shared' import { sqlDataTypeToDbType } from '../edit/options' import { useStoreActions } from '@/store/store' import { deleteWizardFile, getWizardFile, postListFormWizard } from '@/services/wizard.service' import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models' import { ListFormWizardDto } from '@/proxy/admin/wizard/models' +import { + ListFormWorkflowCriteriaDto, + SubFormDto, + WidgetEditDto, + WorkflowDto, +} from '@/proxy/form/models' // ─── Formik initial values & validation ────────────────────────────────────── const initialValues: ListFormWizardDto = { @@ -81,6 +90,16 @@ const initialValues: ListFormWizardDto = { schedulerTextExpr: '', schedulerStartDateExpr: '', schedulerEndDateExpr: '', + subForms: [], + widgets: [], + workflow: { + approvalUserFieldName: '', + approvalDateFieldName: '', + approvalStatusFieldName: '', + approvalDescriptionFieldName: '', + criteria: [], + }, + workflowCriteria: [], } const step1ValidationSchema = Yup.object().shape({ @@ -136,7 +155,11 @@ const Wizard = () => { const [isLoadingDbObjects, setIsLoadingDbObjects] = useState(false) const [currentDataSource, setCurrentDataSource] = useState('') // In edit mode, stores the selectCommand to load columns for once dbObjects is ready - const pendingEditColumnsRef = useRef<{ dsCode: string; selectCommand: string; selectCommandType: SelectCommandTypeEnum } | null>(null) + const pendingEditColumnsRef = useRef<{ + dsCode: string + selectCommand: string + selectCommandType: SelectCommandTypeEnum + } | null>(null) const loadDbObjects = async (dsCode: string) => { if (!dsCode) { @@ -194,6 +217,16 @@ const Wizard = () => { // ── Editing Form Groups (Step 3) ── const [editingGroups, setEditingGroups] = useState([]) + const [subForms, setSubForms] = useState([]) + const [widgets, setWidgets] = useState([]) + const [workflow, setWorkflow] = useState({ + approvalUserFieldName: '', + approvalDateFieldName: '', + approvalStatusFieldName: '', + approvalDescriptionFieldName: '', + criteria: [], + }) + const [workflowCriteria, setWorkflowCriteria] = useState([]) // Audit columns that should not be selected by default const AUDIT_COLUMNS = new Set([ @@ -378,6 +411,16 @@ const Wizard = () => { schedulerTextExpr: w.schedulerTextExpr ?? '', schedulerStartDateExpr: w.schedulerStartDateExpr ?? '', schedulerEndDateExpr: w.schedulerEndDateExpr ?? '', + subForms: w.subForms ?? [], + widgets: w.widgets ?? [], + workflow: w.workflow ?? { + approvalUserFieldName: '', + approvalDateFieldName: '', + approvalStatusFieldName: '', + approvalDescriptionFieldName: '', + criteria: [], + }, + workflowCriteria: w.workflowCriteria ?? w.workflow?.criteria ?? [], }) // Queue column load to run once dbObjects is available @@ -428,6 +471,19 @@ const Wizard = () => { const allFields = new Set(restoredGroups.flatMap((g) => g.items.map((i) => i.dataField))) setSelectedColumns(allFields) } + + setSubForms(w.subForms ?? []) + setWidgets(w.widgets ?? []) + setWorkflow( + w.workflow ?? { + approvalUserFieldName: '', + approvalDateFieldName: '', + approvalStatusFieldName: '', + approvalDescriptionFieldName: '', + criteria: [], + }, + ) + setWorkflowCriteria(w.workflowCriteria ?? w.workflow?.criteria ?? []) } catch { toast.push( @@ -582,6 +638,13 @@ const Wizard = () => { } }), })), + subForms, + widgets, + workflow: { + ...workflow, + criteria: workflowCriteria, + }, + workflowCriteria, }) // ✅ sonra config çek @@ -621,6 +684,9 @@ const Wizard = () => { + + + @@ -635,128 +701,166 @@ const Wizard = () => { innerRef={formikRef} initialValues={{ ...initialValues }} validationSchema={listFormValidationSchema} - onSubmit={async (values, { setSubmitting }) => { - setSubmitting(true) + onSubmit={async (values, { setSubmitting }) => { + setSubmitting(true) - try { - // 🔴 1. Kaydet (bekle) - await postListFormWizard({ ...values }) + try { + // 🔴 1. Kaydet (bekle) + await postListFormWizard({ ...values }) - // 🔴 2. Config güncelle (bekle) - await getConfig(true) + // 🔴 2. Config güncelle (bekle) + await getConfig(true) - // 🔴 3. Navigate - navigate( - ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode), - { replace: true }, - ) + // 🔴 3. Navigate + navigate( + ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode), + { replace: true }, + ) - // 🔴 4. Toast (istersen navigate öncesi de olabilir) - toast.push( - - {translate('::ListForms.FormBilgileriKaydedildi')} - , - { placement: 'top-end' }, - ) - } catch (error: any) { - toast.push(, { - placement: 'top-end', - }) - } finally { - setSubmitting(false) - } - }} - > - {({ touched, errors, isSubmitting, values }) => ( -
- - {/* ─── Step 1: Basic Info ─────────────────────────────── */} - {currentStep === 0 && ( - - formikRef.current?.setFieldValue('menuParentCode', '') - } - onReloadMenu={getMenuList} - permissionGroupList={permissionGroupList} - isLoadingPermissionGroup={isLoadingPermissionGroup} - onNext={handleNext} - translate={translate} - /> - )} + // 🔴 4. Toast (istersen navigate öncesi de olabilir) + toast.push( + + {translate('::ListForms.FormBilgileriKaydedildi')} + , + { placement: 'top-end' }, + ) + } catch (error: any) { + toast.push(, { + placement: 'top-end', + }) + } finally { + setSubmitting(false) + } + }} + > + {({ touched, errors, isSubmitting, values }) => ( + + = 2 ? undefined : 'sm'}> + {/* ─── Step 1: Basic Info ─────────────────────────────── */} + {currentStep === 0 && ( + formikRef.current?.setFieldValue('menuParentCode', '')} + onReloadMenu={getMenuList} + permissionGroupList={permissionGroupList} + isLoadingPermissionGroup={isLoadingPermissionGroup} + onNext={handleNext} + translate={translate} + /> + )} - {/* ─── Step 2: Data Settings ───────────────────────────── */} - {currentStep === 1 && ( - { - setSelectCommandColumns([]) - setSelectedColumns(new Set()) - }} - onToggleColumn={toggleColumn} - onToggleAllColumns={toggleAllColumns} - translate={translate} - onBack={handleBack} - onNext={handleNext2} - /> - )} + {/* ─── Step 2: Data Settings ───────────────────────────── */} + {currentStep === 1 && ( + { + setSelectCommandColumns([]) + setSelectedColumns(new Set()) + }} + onToggleColumn={toggleColumn} + onToggleAllColumns={toggleAllColumns} + translate={translate} + onBack={handleBack} + onNext={handleNext2} + /> + )} - {/* ─── Step 3: List Form Fields ───────────────────────────── */} - {currentStep === 2 && ( - setCurrentStep(1)} - onNext={() => setCurrentStep(3)} - /> - )} + {/* ─── Step 3: List Form Fields ───────────────────────────── */} + {currentStep === 2 && ( + setCurrentStep(1)} + onNext={() => setCurrentStep(3)} + /> + )} - {/* ─── Step 4: Deploy ───────────────────────────── */} - {currentStep === 3 && ( - setCurrentStep(2)} - onSubmit={handleDeploy} - /> - )} - - - )} - + {/* ─── Step 4: Sub Forms ───────────────────────────── */} + {currentStep === 3 && ( + setCurrentStep(2)} + onNext={() => setCurrentStep(4)} + /> + )} + + {/* ─── Step 5: Widgets ───────────────────────────── */} + {currentStep === 4 && ( + setCurrentStep(3)} + onNext={() => setCurrentStep(5)} + /> + )} + + {/* ─── Step 6: Workflow ───────────────────────────── */} + {currentStep === 5 && ( + setCurrentStep(4)} + onNext={() => setCurrentStep(6)} + /> + )} + + {/* ─── Step 7: Deploy ───────────────────────────── */} + {currentStep === 6 && ( + setCurrentStep(5)} + onSubmit={handleDeploy} + /> + )} +
+ + )} + ) } diff --git a/ui/src/views/admin/listForm/wizard/WizardStep4.tsx b/ui/src/views/admin/listForm/wizard/WizardStep4.tsx index 3c43618..0c8ac7c 100644 --- a/ui/src/views/admin/listForm/wizard/WizardStep4.tsx +++ b/ui/src/views/admin/listForm/wizard/WizardStep4.tsx @@ -1,421 +1,475 @@ -import { Button } from '@/components/ui' +import { Button, Card, Checkbox, Dialog, FormItem, Input, Select, Table } from '@/components/ui' +import TBody from '@/components/ui/Table/TBody' +import THead from '@/components/ui/Table/THead' +import Td from '@/components/ui/Table/Td' +import Th from '@/components/ui/Table/Th' +import Tr from '@/components/ui/Table/Tr' +import type { ColumnFormatEditDto } from '@/proxy/admin/list-form-field/models' +import { DbTypeEnum, SubFormDto, SubFormRelationDto, SubFormTabTypeEnum } from '@/proxy/form/models' +import { getListFormFields } from '@/services/admin/list-form-field.service' +import { getListForms } from '@/services/admin/list-form.service' import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models' -import { useState } from 'react' +import type { SelectBoxOption } from '@/types/shared' +import { Field, FieldArray, FieldProps, Form, Formik } from 'formik' +import { useEffect, useState } from 'react' import { FaArrowLeft, - FaCheckCircle, - FaChevronDown, - FaChevronRight, - FaCircle, - FaExclamationCircle, - FaRocket, - FaSpinner, + FaArrowRight, + FaCalendarMinus, + FaCalendarPlus, + FaEdit, + FaFileMedical, + FaTrash, } from 'react-icons/fa' -import { WizardGroup } from './WizardStep3' -import { dbSourceTypeOptions, selectCommandTypeOptions } from '../edit/options' -import { ListFormWizardDto } from '@/proxy/admin/wizard/models' +import { object, string } from 'yup' +import { dbSourceTypeOptions, sqlDataTypeToDbType, tabTypeOptions } from '../edit/options' -// ─── Types ──────────────────────────────────────────────────────────────────── - -export interface WizardStep4Props { - values: ListFormWizardDto - wizardName: string - selectedColumns: Set +type Props = { + subForms: SubFormDto[] selectCommandColumns: DatabaseColumnDto[] - groups: WizardGroup[] translate: (key: string) => string + onChange: (subForms: SubFormDto[]) => void onBack: () => void - onSubmit: () => Promise + onNext: () => void } -type LogStatus = 'pending' | 'running' | 'success' | 'error' +const schema = object().shape({ + tabTitle: string().required(), + tabType: string().required(), + code: string().required(), +}) -interface LogEntry { - id: number - label: string - status: LogStatus - detail?: string +const emptySubForm: SubFormDto = { + tabTitle: '', + tabType: SubFormTabTypeEnum.List, + code: '', + isRefresh: false, + relation: [], + tabMode: 'edit', + searchParams: new URLSearchParams(), } -// ─── Deploy log steps ───────────────────────────────────────────────────────── - -function buildLogSteps( - values: ListFormWizardDto, - groups: WizardGroup[], - translate: (key: string, params?: Record) => string, -): Omit[] { - const totalFields = groups.reduce((acc, g) => acc + g.items.length, 0) - return [ - { id: 1, label: translate('::ListForms.Wizard.Step4.Log.ValidatingConfig') }, - { - id: 2, - label: translate('::ListForms.Wizard.Step4.Log.CreatingMenu', { 0: values.menuCode }), - detail: `Parent: ${values.menuParentCode}`, - }, - { - id: 3, - label: translate('::ListForms.Wizard.Step4.Log.SavingLanguageTexts'), - detail: `EN: ${values.languageTextMenuEn} / TR: ${values.languageTextMenuTr}`, - }, - { id: 4, label: translate('::ListForms.Wizard.Step4.Log.ConfiguringPermission', { 0: values.permissionGroupName }) }, - { id: 5, label: translate('::ListForms.Wizard.Step4.Log.ConnectingDataSource', { 0: values.dataSourceCode }) }, - { - id: 6, - label: translate('::ListForms.Wizard.Step4.Log.CreatingListForm', { 0: values.listFormCode }), - detail: `Key: ${values.keyFieldName}`, - }, - { id: 7, label: translate('::ListForms.Wizard.Step4.Log.SavingFormGroups', { 0: groups.length, 1: totalFields }) }, - { id: 8, label: translate('::ListForms.Wizard.Step4.Log.Deploying') }, - { id: 9, label: translate('::ListForms.Wizard.Step4.Log.Completed') }, - ] -} - -// ─── Mini-components ────────────────────────────────────────────────────────── - -function LogIcon({ status }: { status: LogStatus }) { - if (status === 'running') return - if (status === 'success') return - if (status === 'error') return - return -} - -interface SectionProps { - title: string - badge?: string | number - children: React.ReactNode - defaultOpen?: boolean -} - -function Section({ title, badge, children, defaultOpen = true }: SectionProps) { - const [open, setOpen] = useState(defaultOpen) - return ( -
- - {open &&
{children}
} -
- ) -} - -function Row({ label, value }: { label: string; value?: string | number }) { - if (!value && value !== 0) return null - return ( -
- {label} - - {value} - -
- ) -} - -// ─── WizardStep4 ────────────────────────────────────────────────────────────── -const WizardStep4 = ({ - values, - wizardName, - selectedColumns, +function WizardStep4({ + subForms, selectCommandColumns, - groups, translate, + onChange, onBack, - onSubmit, -}: WizardStep4Props) => { - const [logs, setLogs] = useState([]) - const [isDeploying, setIsDeploying] = useState(false) - const [isDone, setIsDone] = useState(false) - const [hasError, setHasError] = useState(false) + onNext, +}: Props) { + const [dialogIndex, setDialogIndex] = useState(null) + const [deleteIndex, setDeleteIndex] = useState(null) + const [listFormOptions, setListFormOptions] = useState([]) + const [childFields, setChildFields] = useState([]) + const [isLoadingListForms, setIsLoadingListForms] = useState(false) + const [isLoadingChildFields, setIsLoadingChildFields] = useState(false) - const steps = buildLogSteps(values, groups, translate) + const parentFieldOptions = selectCommandColumns.map((column) => ({ + value: column.columnName, + label: `${column.columnName} (${column.dataType})`, + })) - const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)) + const childFieldOptions = childFields + .filter((field) => field.fieldName) + .map((field) => ({ + value: field.fieldName, + label: `${field.fieldName} (${field.dataType})`, + })) - const runDeploy = async () => { - if (isDeploying) return - setIsDeploying(true) - setHasError(false) - setIsDone(false) - - // Initialize all as pending - setLogs(steps.map((s) => ({ ...s, status: 'pending' }))) - - const setStatus = (id: number, status: LogStatus) => - setLogs((prev) => prev.map((l) => (l.id === id ? { ...l, status } : l))) - - // Steps 1-7: pre-deploy simulation (fast) - for (let i = 0; i < steps.length - 2; i++) { - const step = steps[i] - setStatus(step.id, 'running') - await sleep(300 + Math.random() * 200) - setStatus(step.id, 'success') + const loadChildFields = async (listFormCode?: string) => { + if (!listFormCode) { + setChildFields([]) + return } - // Step 8: actual API call - const deployStep = steps[steps.length - 2] - setStatus(deployStep.id, 'running') + setIsLoadingChildFields(true) try { - await onSubmit() - setStatus(deployStep.id, 'success') - await sleep(200) - // Step 9: done - const doneStep = steps[steps.length - 1] - setStatus(doneStep.id, 'running') - await sleep(300) - setStatus(doneStep.id, 'success') - setIsDone(true) - } catch (err: any) { - setStatus(deployStep.id, 'error') - setLogs((prev) => [ - ...prev, - { - id: 999, - label: `Hata: ${err?.message ?? 'Bilinmeyen hata'}`, - status: 'error', - }, - ]) - setHasError(true) + const resp = await getListFormFields({ + listFormCode, + sorting: 'ListOrderNo', + maxResultCount: 1000, + }) + setChildFields(resp.data?.items ?? []) + } catch { + setChildFields([]) } finally { - setIsDeploying(false) + setIsLoadingChildFields(false) } } - const totalFields = groups.reduce((acc, g) => acc + g.items.length, 0) + useEffect(() => { + if (dialogIndex === null) return + + const loadListForms = async () => { + setIsLoadingListForms(true) + try { + const resp = await getListForms({ sorting: 'ListFormCode', maxResultCount: 1000 }) + setListFormOptions( + (resp.data?.items ?? []) + .filter((item) => item.listFormCode) + .map((item) => ({ + value: item.listFormCode, + label: `${item.listFormCode}${item.title ? ` - ${translate(`::${item.title}`)}` : ''}`, + })), + ) + } catch { + setListFormOptions([]) + } finally { + setIsLoadingListForms(false) + } + } + + loadListForms() + + if (dialogIndex !== -1) { + loadChildFields(subForms[dialogIndex]?.code) + } else { + setChildFields([]) + } + }, [dialogIndex]) + + const upsertSubForm = (values: SubFormDto) => { + const next = [...subForms] + if (dialogIndex === -1) next.push(values) + else if (dialogIndex !== null) next[dialogIndex] = values + onChange(next) + setDialogIndex(null) + } + + const removeSubForm = () => { + if (deleteIndex === null) return + onChange(subForms.filter((_, index) => index !== deleteIndex)) + setDeleteIndex(null) + } return ( -
- {/* ── Left: Summary ──────────────────────────────────────────── */} -
-
-
- - - - - - - - - -
- -
- - - - - - - - o.value === values.selectCommandType)?.label || - values.selectCommandType - } - /> - - - o.value === values.keyFieldDbSourceType) - ?.label ?? String(values.keyFieldDbSourceType) - } - /> -
-
- -
-
- {[...selectedColumns].map((col) => { - const meta = selectCommandColumns.find((c) => c.columnName === col) - return ( - - {col} - {meta?.dataType && ( - {meta.dataType} - )} - - ) - })} -
-
- -
-
- {groups.map((g) => ( -
-
- {g.items.length === 0 ? ( - {translate('::ListForms.Wizard.Step4.NoFields') || 'Alan yok'} - ) : ( - g.items.map((item) => ( -
- - {item.dataField} - - - {item.editorType} - - - col-span-{item.colSpan} - {item.isRequired && ( - * - )} - -
- )) - )} -
-
- ))} -
-
-
- - {/* ── Right: Deploy ──────────────────────────────────────────── */} -
- {/* Stats */} -
- {[ - { label: translate('::ListForms.Wizard.Step4.StatGroup'), value: groups.length }, - { label: translate('::ListForms.Wizard.Step4.StatField'), value: totalFields }, - { label: translate('::App.Listform.ListformField.Column'), value: selectedColumns.size }, - ].map((s) => ( -
-
- {s.value} -
-
{s.label}
-
- ))} -
- - {/* Log panel — grows to fill remaining height */} -
-
- - - {translate('::ListForms.Wizard.Step4.DeployLog') || 'Deploy Log'} - - {isDone && ( - - {translate('::ListForms.Wizard.Step4.Success') || 'Başarılı'} - - )} - {hasError && ( - - {translate('::ListForms.Wizard.Step4.Error') || 'Hata'} - - )} -
- -
- {logs.length === 0 ? ( -
- - - {translate('::ListForms.Wizard.Step4.AllInfoReady') || 'Tüm bilgiler hazır.'} -
- {translate('::ListForms.Wizard.Step4.DeployStartHint')} -
-
- ) : ( -
- {logs.map((log) => ( -
- - - -
- - {log.label} - - {log.detail && ( -
{log.detail}
- )} +
+
+ + + + + + + + + + + + + + {subForms.map((row, index) => ( + + + + + + + + + ))} + +
+ {translate('::ListForms.ListFormEdit.SubFormsTabTitle')}{translate('::ListForms.ListFormEdit.SubFormsTabType')}{translate('::App.Listform.ListformField.ListFormCode')}{translate('::ListForms.ListFormEdit.SubFormsIsRefresh')}{translate('::ListForms.ListFormEdit.SubFormsRelation')}
+
+
- - ))} - {isDone && ( -
- 🎉 {translate('::ListForms.Wizard.Step4.DeploySuccess')} -
- )} - - )} - - +
{row.tabTitle}{row.tabType}{row.code}{row.isRefresh ? 'Active' : 'Inactive'} + {(row.relation || []).map((item) => ( +
+ {item.parentFieldName} : {item.childFieldName} +
+ ))} +
+
- {/* ── Fixed Footer ─────────────────────────────────────────────── */} -
-
- -
+
+ + setDialogIndex(null)} + onRequestClose={() => setDialogIndex(null)} + > + {dialogIndex !== null && ( + + {({ values, errors, touched }) => ( +
+ +
{dialogIndex === -1 ? 'Add' : 'Update'}
+
+ + + + + + {({ field, form }: FieldProps) => ( + option.value === values.tabType)} + onChange={(option: any) => + form.setFieldValue(field.name, option?.value) + } + /> + )} + + + + + +
+ + + ( +
+
+
Parent Field Name
+
Child Field Name
+
Db Type
+
+
+ {values.relation && values.relation.length > 0 ? ( + values.relation.map((item: SubFormRelationDto, index) => ( +
+
+ + {({ field, form }: FieldProps) => ( + option.value === item.childFieldName, + )} + onChange={(option) => + form.setFieldValue(field.name, option?.value ?? '') + } + /> + )} + +
+ +
+ + {({ field, form }: FieldProps) => ( + option.value === values.colSpan, + )} + onChange={(option: any) => + form.setFieldValue(field.name, option?.value) + } + /> + )} + + + +
Widget Container CSS Classes
+
Examples: mb-3, mt-2, p-4, rounded-lg, shadow-md
+
+ } + > + + + + + +
Value Display CSS Classes
+
Examples: text-3xl, text-2xl, font-bold, text-sm
+
+ } + > + + + + + + + +
+ + +
SQL Query Examples:
+ + SELECT 'Aktif' as title, COUNT(Id) as value, 'blue' as color, 'FaChartBar' + as icon, 'Aktif kayitlar' as subTitle FROM YourTable + +
+ } + > + + Sql Query + + + + +
+ setFieldValue('sqlQuery', value || '')} + /> +
+
+ +
+ + + + + + + +
blue
+
green
+
purple
+
gray
+
red
+
yellow
+
teal
+
orange
+
+ } + > + + + + + +
Popular Font Awesome icons
+
FaChartBar, FaChartLine, FaUsers, FaShoppingCart, FaBell
+
+ } + > + + + + + + + +
+ + + + + + + + + + )} + + )} + + + setDeleteIndex(null)} + onRequestClose={() => setDeleteIndex(null)} + > + +
Delete
+

Silmek istediğinize emin misiniz?

+
+ + + + +
+
+ ) +} + +export default WizardStep5 diff --git a/ui/src/views/admin/listForm/wizard/WizardStep6.tsx b/ui/src/views/admin/listForm/wizard/WizardStep6.tsx new file mode 100644 index 0000000..07a8090 --- /dev/null +++ b/ui/src/views/admin/listForm/wizard/WizardStep6.tsx @@ -0,0 +1,368 @@ +import { Button, Card, FormContainer, FormItem, Select } from '@/components/ui' +import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models' +import { ListFormWorkflowCriteriaDto, WorkflowDto } from '@/proxy/form/models' +import { getUsers } from '@/services/identity.service' +import type { WorkflowCriteriaDto } from '@/services/workflow.service' +import { SelectBoxOption } from '@/types/shared' +import { + buildFitLayout, + emptyCriteria, + normalizeCriteria, + toCriteriaForm, + type WorkflowCriteriaForm, +} from '@/utils/workflow/workflowHelpers' +import { Field, FieldProps, Form, Formik } from 'formik' +import { useEffect, useMemo, useRef, useState } from 'react' +import type { FormEvent } from 'react' +import { FaArrowLeft, FaArrowRight } from 'react-icons/fa' +import { WorkflowDesigner } from '../workflow/WorkflowDesigner' + +type Props = { + listFormCode: string + workflow: WorkflowDto + criteria: ListFormWorkflowCriteriaDto[] + selectCommandColumns: DatabaseColumnDto[] + translate: (key: string) => string + onWorkflowChange: (workflow: WorkflowDto) => void + onCriteriaChange: (criteria: ListFormWorkflowCriteriaDto[]) => void + onBack: () => void + onNext: () => void +} + +type PendingLink = { + sourceId: string + outcome: string +} | null + +const toDesignerCriteria = (items: ListFormWorkflowCriteriaDto[]): WorkflowCriteriaDto[] => + items.map((item) => ({ + ...item, + nodeId: item.id, + compareOutcomes: item.compareOutcomes || [], + })) + +const toWizardCriteria = (items: WorkflowCriteriaDto[]): ListFormWorkflowCriteriaDto[] => + items.map(({ nodeId: _nodeId, ...item }) => item) + +const nextId = () => `WF${Date.now()}${Math.floor(Math.random() * 1000)}` + +function WizardStep6({ + listFormCode, + workflow, + criteria, + selectCommandColumns, + translate, + onWorkflowChange, + onCriteriaChange, + onBack, + onNext, +}: Props) { + const [userList, setUserList] = useState([]) + const [selectedId, setSelectedId] = useState('') + const [pendingLink, setPendingLink] = useState(null) + const [criteriaForm, setCriteriaForm] = useState( + emptyCriteria('Start', listFormCode), + ) + const [dragPreview, setDragPreview] = useState(null) + const [canvasZoom, setCanvasZoom] = useState(1) + const [designerTab, setDesignerTab] = useState('flow') + const canvasRef = useRef(null) + + const currentCriteria = useMemo(() => toDesignerCriteria(criteria), [criteria]) + const columnOptions: SelectBoxOption[] = selectCommandColumns.map((column) => ({ + value: column.columnName, + label: `${column.columnName} (${column.dataType})`, + })) + + useEffect(() => { + getUsers(0, 1000).then((response) => { + setUserList( + (response.data?.items ?? []).map((user: any) => ({ + value: user.userName, + label: `${user.userName} (${user.name} ${user.surname})`, + })), + ) + }) + }, []) + + useEffect(() => { + const selected = currentCriteria.find((item) => item.id === selectedId) + setCriteriaForm(selected ? toCriteriaForm(selected) : emptyCriteria('Start', listFormCode)) + }, [currentCriteria, listFormCode, selectedId]) + + const updateCriteria = (next: WorkflowCriteriaDto[]) => onCriteriaChange(toWizardCriteria(next)) + + const saveCriteria = (event: FormEvent) => { + event.preventDefault() + const normalized = normalizeCriteria({ ...criteriaForm, listFormCode }) + const id = normalized.id || nextId() + const nextItem = { ...normalized, id, nodeId: id } as WorkflowCriteriaDto + const exists = currentCriteria.some((item) => item.id === id) + updateCriteria( + exists + ? currentCriteria.map((item) => (item.id === id ? nextItem : item)) + : [...currentCriteria, nextItem], + ) + setSelectedId(id) + setDesignerTab('flow') + } + + const addCriteria = (kind: string) => { + const id = nextId() + const nextItem = { + ...normalizeCriteria(emptyCriteria(kind, listFormCode)), + id, + nodeId: id, + positionX: 80 + (currentCriteria.length % 5) * 230, + positionY: 220 + Math.floor(currentCriteria.length / 5) * 140, + } as WorkflowCriteriaDto + updateCriteria([...currentCriteria, nextItem]) + setSelectedId(id) + } + + const deleteCriteria = (criteriaId: string = selectedId) => { + if (!criteriaId) return + updateCriteria( + currentCriteria + .filter((item) => item.id !== criteriaId) + .map((item) => ({ + ...item, + nextOnStart: item.nextOnStart === criteriaId ? '' : item.nextOnStart, + nextOnTrue: item.nextOnTrue === criteriaId ? '' : item.nextOnTrue, + nextOnFalse: item.nextOnFalse === criteriaId ? '' : item.nextOnFalse, + nextOnApprove: item.nextOnApprove === criteriaId ? '' : item.nextOnApprove, + nextOnReject: item.nextOnReject === criteriaId ? '' : item.nextOnReject, + compareOutcomes: (item.compareOutcomes || []).map((outcome) => ({ + ...outcome, + targetId: outcome.targetId === criteriaId ? null : outcome.targetId, + })), + })), + ) + setSelectedId('') + } + + const disconnectLink = (sourceId: string, outcome: string) => { + updateCriteria( + currentCriteria.map((item) => { + if (item.id !== sourceId) return item + if (outcome.startsWith('compareOutcomes:')) { + const index = Number(outcome.split(':')[1]) + const compareOutcomes = [...(item.compareOutcomes || [])] + if (compareOutcomes[index]) + compareOutcomes[index] = { ...compareOutcomes[index], targetId: null } + return { ...item, compareOutcomes } + } + return { ...item, [outcome]: '' } + }), + ) + setPendingLink(null) + } + + const connectNodes = (sourceId: string, outcome: string, targetId: string) => { + if (sourceId === targetId) return + updateCriteria( + currentCriteria.map((item) => { + if (item.id !== sourceId) return item + if (outcome.startsWith('compareOutcomes:')) { + const index = Number(outcome.split(':')[1]) + const compareOutcomes = [...(item.compareOutcomes || [])] + compareOutcomes[index] = { ...compareOutcomes[index], targetId } + return { + ...item, + compareOutcomes, + nextOnTrue: index === 0 ? targetId : item.nextOnTrue, + nextOnFalse: index === 1 ? targetId : item.nextOnFalse, + } + } + return { ...item, [outcome]: targetId } + }), + ) + setPendingLink(null) + } + + const fitFlowLayout = () => { + const positions = buildFitLayout(currentCriteria) + updateCriteria( + currentCriteria.map((item) => { + const position = positions.get(item.id) + return position ? { ...item, positionX: position.x, positionY: position.y } : item + }), + ) + setCanvasZoom(1) + } + + const resetDemo = () => { + const startId = nextId() + const approvalId = nextId() + const endId = nextId() + updateCriteria([ + { + ...normalizeCriteria(emptyCriteria('Start', listFormCode)), + id: startId, + nodeId: startId, + nextOnStart: approvalId, + positionX: 72, + positionY: 160, + } as WorkflowCriteriaDto, + { + ...normalizeCriteria(emptyCriteria('Approval', listFormCode)), + id: approvalId, + nodeId: approvalId, + nextOnApprove: endId, + positionX: 360, + positionY: 160, + } as WorkflowCriteriaDto, + { + ...normalizeCriteria(emptyCriteria('End', listFormCode)), + id: endId, + nodeId: endId, + positionX: 650, + positionY: 160, + } as WorkflowCriteriaDto, + ]) + } + + return ( +
+
+ onWorkflowChange({ ...values, criteria })} + > + {({ values }) => ( +
+ + +
+ {[ + [ + 'approvalUserFieldName', + '::ListForms.ListFormEdit.Workflow.ApprovalUserFieldName', + ], + [ + 'approvalStatusFieldName', + '::ListForms.ListFormEdit.Workflow.ApprovalStatusFieldName', + ], + [ + 'approvalDateFieldName', + '::ListForms.ListFormEdit.Workflow.ApprovalDateFieldName', + ], + [ + 'approvalDescriptionFieldName', + '::ListForms.ListFormEdit.Workflow.ApprovalDescriptionFieldName', + ], + ].map(([name, label]) => ( + + + {({ field, form }: FieldProps) => ( +