From 63695be34e506f9dd13221aeddd76f3bb7ac1634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Wed, 18 Mar 2026 21:53:51 +0300 Subject: [PATCH] SQL Query Managerda RunSql Script --- .../Seeds/LanguagesData.json | 56 ++- .../Seeds/ListFormSeeder_Saas.cs | 2 +- .../Entities/Tenant/ListForm/ListFormField.cs | 6 +- ui/src/views/admin/listForm/Wizard.tsx | 19 +- ui/src/views/developerKit/SqlQueryManager.tsx | 359 ++++++++++++++---- 5 files changed, 335 insertions(+), 107 deletions(-) diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json index bcd9da5..9c02be4 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json @@ -10428,6 +10428,30 @@ "tr": "Seçili Nesneler", "en": "Selected Objects" }, + { + "resourceName": "Platform", + "key": "App.Platform.CopyObjects", + "tr": "Nesneleri Kopyala", + "en": "Copy Objects" + }, + { + "resourceName": "Platform", + "key": "App.Platform.DirectSqlScript", + "tr": "Doğrudan SQL Scripti", + "en": "Direct SQL Script" + }, + { + "resourceName": "Platform", + "key": "App.Platform.SqlScriptPlaceholder", + "tr": "SQL scriptinizi buraya girin", + "en": "Enter your SQL script here" + }, + { + "resourceName": "Platform", + "key": "App.Platform.NoObjectSelected", + "tr": "Nesne Seçilmedi", + "en": "No Object Selected" + }, { "resourceName": "Platform", "key": "App.Platform.SourceDataSource", @@ -10650,12 +10674,6 @@ "tr": "Fonksiyon", "en": "Function" }, - { - "resourceName": "Platform", - "key": "App.Platform.Object", - "tr": "Nesne", - "en": "Object" - }, { "resourceName": "Platform", "key": "App.Platform.Draft", @@ -11600,7 +11618,7 @@ }, { "resourceName": "Platform", - "key": "App.Platform.Intranet.AnnouncementDetailModal.Close", + "key": "App.Platform.Close", "tr": "Kapat", "en": "Close" }, @@ -17051,6 +17069,24 @@ "en": "Overwrite if exists", "tr": "Varsa üzerine yaz" }, + { + "resourceName": "Platform", + "key": "App.Platform.ExecutionCompleted", + "en": "Execution completed", + "tr": "Yürütme tamamlandı" + }, + { + "resourceName": "Platform", + "key": "App.Platform.CopyCompleted", + "en": "Copy completed", + "tr": "Kopyalama tamamlandı" + }, + { + "resourceName": "Platform", + "key": "App.Platform.CreateScriptFailed", + "en": "Failed to create script", + "tr": "Kaynak objenin scripti oluşturulamadı" + }, { "resourceName": "Platform", "key": "App.Platform.OverwriteIfExistsDesc", @@ -17136,12 +17172,6 @@ "en": "Table successfully created", "tr": "Tablo başarıyla oluşturuldu" }, - { - "resourceName": "Platform", - "key": "App.SqlQueryManager.Error", - "en": "Error", - "tr": "Hata" - }, { "resourceName": "Platform", "key": "App.SqlQueryManager.TableCreationFailed", diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs index 3eb082b..ce46ee6 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs @@ -4142,7 +4142,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency CaptionName = "App.Listform.ListformField.PermissionJson", Width = 700, ListOrderNo = 16, - Visible = true, + Visible = false, IsActive = true, IsDeleted = false, ColumnCustomizationJson = DefaultColumnCustomizationJson, diff --git a/api/src/Sozsoft.Platform.Domain/Entities/Tenant/ListForm/ListFormField.cs b/api/src/Sozsoft.Platform.Domain/Entities/Tenant/ListForm/ListFormField.cs index 36fcc2d..e22fdba 100644 --- a/api/src/Sozsoft.Platform.Domain/Entities/Tenant/ListForm/ListFormField.cs +++ b/api/src/Sozsoft.Platform.Domain/Entities/Tenant/ListForm/ListFormField.cs @@ -10,9 +10,9 @@ public class ListFormField : FullAuditedEntity public string ListFormCode { get; set; }// Sozsoft.LF.SATIS-323 public string UserId { get; set; } // External kullanici id (orn: ali.akman. ihtiyaca gore guid veya int de olabilir) public string RoleId { get; set; } // External role id (orn: ihracat) - public string CultureName { get; set; } // Bu tanım hangi dil için (“tr”, “en”) + public string CultureName { get; set; } // Bu tanım hangi dil için (“tr”, “en”) public string FieldName { get; set; } // Kaynaktaki sutun adi - public string CaptionName { get; set; } // Sutun basligi + public string CaptionName { get; set; } // Sutun basligi public bool? Visible { get; set; } // Liste üzerinde gösterilecek mi? Yoksa eklenebilir sütunların arasında mı duracak. select sorgusuna dahildir public bool? IsActive { get; set; } = true; // Sadece IsActive olan alanlar sorguya dahil edilir public int? Width { get; set; } // Sütunun listedeki genişliği @@ -21,7 +21,7 @@ public class ListFormField : FullAuditedEntity public int? SortIndex { get; set; } //bu sütuna göre sıralama yapılacaktır. Birden fazla sütuna göre sıralama varsa, sortindexe göre sıralama yapılır. public string SortDirection { get; set; } // Sortindex varsa alacagi degerler asc, desc - public bool? AllowSearch { get; set; } + public bool? AllowSearch { get; set; } = true; public bool? AllowEditing { get; set; } public string BandName { get; set; } diff --git a/ui/src/views/admin/listForm/Wizard.tsx b/ui/src/views/admin/listForm/Wizard.tsx index a687254..f8426ed 100644 --- a/ui/src/views/admin/listForm/Wizard.tsx +++ b/ui/src/views/admin/listForm/Wizard.tsx @@ -324,6 +324,7 @@ const Wizard = () => { const col = selectCommandColumns.find((c) => c.columnName === item.dataField) return { dataField: item.dataField, + captionName: `App.Listform.ListformField.${item.dataField}`, editorType: item.editorType, editorOptions: item.editorOptions ?? '', editorScript: item.editorScript ?? '', @@ -340,11 +341,12 @@ const Wizard = () => { , { placement: 'top-end' }, ) - getConfig(true) + setTimeout(async () => { + getConfig(true) - setTimeout(() => { navigate(ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode)) - }, 1500) + }, 6000) + } return ( @@ -383,13 +385,12 @@ const Wizard = () => { { placement: 'top-end' }, ) setSubmitting(false) - getConfig(true) + setTimeout(async () => { + getConfig(true) + + navigate(ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode)) + }, 6000) - setTimeout(() => { - navigate( - ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode), - ) - }, 1500) } catch (error: any) { toast.push(, { placement: 'top-end', diff --git a/ui/src/views/developerKit/SqlQueryManager.tsx b/ui/src/views/developerKit/SqlQueryManager.tsx index 28196d3..85703ad 100644 --- a/ui/src/views/developerKit/SqlQueryManager.tsx +++ b/ui/src/views/developerKit/SqlQueryManager.tsx @@ -72,6 +72,8 @@ const SqlQueryManager = () => { const [isCopyingObjects, setIsCopyingObjects] = useState(false) const [copyResults, setCopyResults] = useState([]) const [showCopyResultDialog, setShowCopyResultDialog] = useState(false) + const [copyDialogMode, setCopyDialogMode] = useState<'objects' | 'sql'>('objects') + const [sqlScriptForCopy, setSqlScriptForCopy] = useState('') useEffect(() => { loadDataSources() @@ -614,19 +616,18 @@ GO`, const handleOpenCopyDialog = () => { if (!state.selectedDataSource) return - if (selectedExplorerObjects.length === 0) { - toast.push( - - {'Lutfen kopyalamak icin en az bir obje secin.'} - , - { placement: 'top-center' }, - ) - return - } - + setCopyDialogMode('objects') setCopyTargetDataSources([]) setOverwriteIfExists(false) + setSqlScriptForCopy('') setShowCopyDialog(true) + + // Eğer seçili obje yoksa uyarı göster + if (selectedExplorerObjects.length === 0) { + // SQL mode'da obje seçimi zorunlu değil, object mode'da zorunlu + // Bu uyarı sadece object mode'da gerekirse + return + } } const handleCopyObjects = async () => { @@ -665,7 +666,7 @@ GO`, objectFullName: obj.fullName, objectType: obj.objectType, status: 'error', - message: 'Kaynak objenin scripti olusturulamadi.', + message: translate('::App.Platform.CreateScriptFailed'), }) continue } @@ -686,7 +687,7 @@ GO`, objectFullName: obj.fullName, objectType: obj.objectType, status: 'skipped', - message: translate('::App.SqlQueryManager.SkippedDescription') , + message: translate('::App.SqlQueryManager.SkippedDescription'), }) continue } @@ -706,7 +707,7 @@ GO`, objectFullName: obj.fullName, objectType: obj.objectType, status: 'success', - message: 'Basariyla kopyalandi.', + message: translate('::App.Platform.CopyCompleted'), }) } catch (error: any) { results.push({ @@ -734,7 +735,8 @@ GO`, : translate('::App.Platform.Success') } > - {`Kopyalama tamamlandi. Basarili: ${successCount}, Atlanan: ${skippedCount}, Hata: ${errorCount}`} + {translate('::App.Platform.CopyCompleted') || + `translate('::App.Platform.Successful'): ${successCount}, ${translate('::App.Platform.Error')}: ${errorCount}, ${translate('::App.Platform.Skipped')}: ${skippedCount}`} , { placement: 'top-center' }, ) @@ -748,6 +750,82 @@ GO`, } } + const handleExecuteDirectSql = async () => { + if (!sqlScriptForCopy?.trim()) { + toast.push( + + {translate('::App.Platform.PleaseEnterQuery')} + , + { placement: 'top-center' }, + ) + return + } + + if (copyTargetDataSources.length === 0) { + toast.push( + + {translate('::App.Platform.PleaseSelectAtLeastOneTarget')} + , + { placement: 'top-center' }, + ) + return + } + + setIsCopyingObjects(true) + const results: SqlCopyResultItem[] = [] + + try { + for (const targetDataSource of copyTargetDataSources) { + try { + await sqlObjectManagerService.executeQuery({ + queryText: sqlScriptForCopy, + dataSourceCode: targetDataSource, + }) + results.push({ + targetDataSource, + objectFullName: 'SQL Script', + objectType: 'script' as any, + status: 'success', + message: 'Basariyla calistirildi.', + }) + } catch (error: any) { + results.push({ + targetDataSource, + objectFullName: 'SQL Script', + objectType: 'script' as any, + status: 'error', + message: error.response?.data?.error?.message || 'Calistirma basarisiz.', + }) + } + } + + const successCount = results.filter((x) => x.status === 'success').length + const errorCount = results.filter((x) => x.status === 'error').length + + const notificationType = errorCount > 0 ? 'warning' : 'success' + toast.push( + 0 + ? translate('::App.Platform.Warning') + : translate('::App.Platform.Success') + } + > + {translate('::App.Platform.ExecutionCompleted') || + `translate('::App.Platform.Successful'): ${successCount}, ${translate('::App.Platform.Error')}: ${errorCount}`} + , + { placement: 'top-center' }, + ) + + setCopyResults(results) + setShowCopyResultDialog(true) + setShowCopyDialog(false) + } finally { + setIsCopyingObjects(false) + } + } + const availableTargetDataSourceCodes = state.dataSources .filter((d) => d.code && d.code !== state.selectedDataSource) .map((d) => d.code || '') @@ -805,8 +883,12 @@ GO`, size="sm" variant="default" onClick={handleOpenCopyDialog} - disabled={!state.selectedDataSource || selectedExplorerObjects.length === 0} + disabled={!state.selectedDataSource} className="shadow-sm" + title={ + translate('::App.Platform.CopyOrExecuteSql') || + 'Seçili nesneleri kopyala veya SQL script calistir' + } > {translate('::App.Platform.CopySelectedObjects') || 'Copy Selected Objects'} @@ -978,65 +1060,163 @@ GO`, >
{translate('::App.Platform.CopySelectedObjects')}
-
-
-

- {translate('::App.Platform.SourceDataSource')}:{' '} - {state.selectedDataSource} -

- -
-
- {selectedExplorerObjects.map((obj) => ( -
- {obj.objectType.toUpperCase()} - {obj.fullName} -
- ))} -
- -
-
- {translate('::App.Platform.TargetDataSources')} -
- -
- {availableTargetDataSourceCodes.map((code) => { - const checked = copyTargetDataSources.includes(code) - return ( - - ) - })} -
-
+ {/* Mode Tabs */} +
+ +
+ +
+ {copyDialogMode === 'objects' ? ( + <> + {/* Objects Mode */} +
+

+ {translate('::App.Platform.SourceDataSource')}:{' '} + {state.selectedDataSource} +

+ +
+ +
+ {selectedExplorerObjects.length === 0 ? ( +

+ {translate('::App.Platform.NoObjectSelected') || + 'Secili nesne yok. Lutfen Explorer alanından bir nesne secin.'} +

+ ) : ( + selectedExplorerObjects.map((obj) => ( +
+ {obj.objectType.toUpperCase()} - {obj.fullName} +
+ )) + )} +
+ +
+
+ {translate('::App.Platform.TargetDataSources')} +
+ +
+ {availableTargetDataSourceCodes.map((code) => { + const checked = copyTargetDataSources.includes(code) + return ( + + ) + })} +
+
+ + ) : ( + <> + {/* SQL Mode */} +
+

+ {translate('::App.Platform.SourceDataSource')}:{' '} + {state.selectedDataSource} +

+
+ +
+ setSqlScriptForCopy(value || '')} + readOnly={isCopyingObjects} + /> +
+ +
+
+ {translate('::App.Platform.TargetDataSources')} +
+ +
+ {availableTargetDataSourceCodes.map((code) => { + const checked = copyTargetDataSources.includes(code) + return ( + + ) + })} +
+
+ + )} +
+
@@ -1137,11 +1324,21 @@ GO`, - - - - - + + + + + @@ -1209,7 +1406,7 @@ GO`,
{translate('::App.Platform.Status')}{translate('::App.Platform.Object')}{translate('::App.Platform.Type')}{translate('::App.Platform.Target')}{translate('::App.Platform.Message')} + {translate('::App.Platform.Status')} + + {translate('::App.Platform.Object')} + + {translate('::App.Platform.Type')} + + {translate('::App.Platform.Target')} + + {translate('::App.Platform.Message')} +