SQL Query Managerda RunSql Script
This commit is contained in:
parent
ff58614f0d
commit
63695be34e
5 changed files with 335 additions and 107 deletions
|
|
@ -10428,6 +10428,30 @@
|
||||||
"tr": "Seçili Nesneler",
|
"tr": "Seçili Nesneler",
|
||||||
"en": "Selected Objects"
|
"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",
|
"resourceName": "Platform",
|
||||||
"key": "App.Platform.SourceDataSource",
|
"key": "App.Platform.SourceDataSource",
|
||||||
|
|
@ -10650,12 +10674,6 @@
|
||||||
"tr": "Fonksiyon",
|
"tr": "Fonksiyon",
|
||||||
"en": "Function"
|
"en": "Function"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"resourceName": "Platform",
|
|
||||||
"key": "App.Platform.Object",
|
|
||||||
"tr": "Nesne",
|
|
||||||
"en": "Object"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Platform.Draft",
|
"key": "App.Platform.Draft",
|
||||||
|
|
@ -11600,7 +11618,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Platform.Intranet.AnnouncementDetailModal.Close",
|
"key": "App.Platform.Close",
|
||||||
"tr": "Kapat",
|
"tr": "Kapat",
|
||||||
"en": "Close"
|
"en": "Close"
|
||||||
},
|
},
|
||||||
|
|
@ -17051,6 +17069,24 @@
|
||||||
"en": "Overwrite if exists",
|
"en": "Overwrite if exists",
|
||||||
"tr": "Varsa üzerine yaz"
|
"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",
|
"resourceName": "Platform",
|
||||||
"key": "App.Platform.OverwriteIfExistsDesc",
|
"key": "App.Platform.OverwriteIfExistsDesc",
|
||||||
|
|
@ -17136,12 +17172,6 @@
|
||||||
"en": "Table successfully created",
|
"en": "Table successfully created",
|
||||||
"tr": "Tablo başarıyla oluşturuldu"
|
"tr": "Tablo başarıyla oluşturuldu"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"resourceName": "Platform",
|
|
||||||
"key": "App.SqlQueryManager.Error",
|
|
||||||
"en": "Error",
|
|
||||||
"tr": "Hata"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.SqlQueryManager.TableCreationFailed",
|
"key": "App.SqlQueryManager.TableCreationFailed",
|
||||||
|
|
|
||||||
|
|
@ -4142,7 +4142,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
CaptionName = "App.Listform.ListformField.PermissionJson",
|
CaptionName = "App.Listform.ListformField.PermissionJson",
|
||||||
Width = 700,
|
Width = 700,
|
||||||
ListOrderNo = 16,
|
ListOrderNo = 16,
|
||||||
Visible = true,
|
Visible = false,
|
||||||
IsActive = true,
|
IsActive = true,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ public class ListFormField : FullAuditedEntity<Guid>
|
||||||
public string ListFormCode { get; set; }// Sozsoft.LF.SATIS-323
|
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 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 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 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? 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 bool? IsActive { get; set; } = true; // Sadece IsActive olan alanlar sorguya dahil edilir
|
||||||
public int? Width { get; set; } // Sütunun listedeki genişliği
|
public int? Width { get; set; } // Sütunun listedeki genişliği
|
||||||
|
|
@ -21,7 +21,7 @@ public class ListFormField : FullAuditedEntity<Guid>
|
||||||
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 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 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 bool? AllowEditing { get; set; }
|
||||||
public string BandName { get; set; }
|
public string BandName { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -324,6 +324,7 @@ const Wizard = () => {
|
||||||
const col = selectCommandColumns.find((c) => c.columnName === item.dataField)
|
const col = selectCommandColumns.find((c) => c.columnName === item.dataField)
|
||||||
return {
|
return {
|
||||||
dataField: item.dataField,
|
dataField: item.dataField,
|
||||||
|
captionName: `App.Listform.ListformField.${item.dataField}`,
|
||||||
editorType: item.editorType,
|
editorType: item.editorType,
|
||||||
editorOptions: item.editorOptions ?? '',
|
editorOptions: item.editorOptions ?? '',
|
||||||
editorScript: item.editorScript ?? '',
|
editorScript: item.editorScript ?? '',
|
||||||
|
|
@ -340,11 +341,12 @@ const Wizard = () => {
|
||||||
</Notification>,
|
</Notification>,
|
||||||
{ placement: 'top-end' },
|
{ placement: 'top-end' },
|
||||||
)
|
)
|
||||||
getConfig(true)
|
setTimeout(async () => {
|
||||||
|
getConfig(true)
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
navigate(ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode))
|
navigate(ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode))
|
||||||
}, 1500)
|
}, 6000)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -383,13 +385,12 @@ const Wizard = () => {
|
||||||
{ placement: 'top-end' },
|
{ placement: 'top-end' },
|
||||||
)
|
)
|
||||||
setSubmitting(false)
|
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) {
|
} catch (error: any) {
|
||||||
toast.push(<Notification title={error.message} type="danger" />, {
|
toast.push(<Notification title={error.message} type="danger" />, {
|
||||||
placement: 'top-end',
|
placement: 'top-end',
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ const SqlQueryManager = () => {
|
||||||
const [isCopyingObjects, setIsCopyingObjects] = useState(false)
|
const [isCopyingObjects, setIsCopyingObjects] = useState(false)
|
||||||
const [copyResults, setCopyResults] = useState<SqlCopyResultItem[]>([])
|
const [copyResults, setCopyResults] = useState<SqlCopyResultItem[]>([])
|
||||||
const [showCopyResultDialog, setShowCopyResultDialog] = useState(false)
|
const [showCopyResultDialog, setShowCopyResultDialog] = useState(false)
|
||||||
|
const [copyDialogMode, setCopyDialogMode] = useState<'objects' | 'sql'>('objects')
|
||||||
|
const [sqlScriptForCopy, setSqlScriptForCopy] = useState('')
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadDataSources()
|
loadDataSources()
|
||||||
|
|
@ -614,19 +616,18 @@ GO`,
|
||||||
const handleOpenCopyDialog = () => {
|
const handleOpenCopyDialog = () => {
|
||||||
if (!state.selectedDataSource) return
|
if (!state.selectedDataSource) return
|
||||||
|
|
||||||
if (selectedExplorerObjects.length === 0) {
|
setCopyDialogMode('objects')
|
||||||
toast.push(
|
|
||||||
<Notification type="warning" title={translate('::App.Platform.Warning')}>
|
|
||||||
{'Lutfen kopyalamak icin en az bir obje secin.'}
|
|
||||||
</Notification>,
|
|
||||||
{ placement: 'top-center' },
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setCopyTargetDataSources([])
|
setCopyTargetDataSources([])
|
||||||
setOverwriteIfExists(false)
|
setOverwriteIfExists(false)
|
||||||
|
setSqlScriptForCopy('')
|
||||||
setShowCopyDialog(true)
|
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 () => {
|
const handleCopyObjects = async () => {
|
||||||
|
|
@ -665,7 +666,7 @@ GO`,
|
||||||
objectFullName: obj.fullName,
|
objectFullName: obj.fullName,
|
||||||
objectType: obj.objectType,
|
objectType: obj.objectType,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
message: 'Kaynak objenin scripti olusturulamadi.',
|
message: translate('::App.Platform.CreateScriptFailed'),
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -686,7 +687,7 @@ GO`,
|
||||||
objectFullName: obj.fullName,
|
objectFullName: obj.fullName,
|
||||||
objectType: obj.objectType,
|
objectType: obj.objectType,
|
||||||
status: 'skipped',
|
status: 'skipped',
|
||||||
message: translate('::App.SqlQueryManager.SkippedDescription') ,
|
message: translate('::App.SqlQueryManager.SkippedDescription'),
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -706,7 +707,7 @@ GO`,
|
||||||
objectFullName: obj.fullName,
|
objectFullName: obj.fullName,
|
||||||
objectType: obj.objectType,
|
objectType: obj.objectType,
|
||||||
status: 'success',
|
status: 'success',
|
||||||
message: 'Basariyla kopyalandi.',
|
message: translate('::App.Platform.CopyCompleted'),
|
||||||
})
|
})
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
results.push({
|
results.push({
|
||||||
|
|
@ -734,7 +735,8 @@ GO`,
|
||||||
: translate('::App.Platform.Success')
|
: 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}`}
|
||||||
</Notification>,
|
</Notification>,
|
||||||
{ placement: 'top-center' },
|
{ placement: 'top-center' },
|
||||||
)
|
)
|
||||||
|
|
@ -748,6 +750,82 @@ GO`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleExecuteDirectSql = async () => {
|
||||||
|
if (!sqlScriptForCopy?.trim()) {
|
||||||
|
toast.push(
|
||||||
|
<Notification type="warning" title={translate('::App.Platform.Warning')}>
|
||||||
|
{translate('::App.Platform.PleaseEnterQuery')}
|
||||||
|
</Notification>,
|
||||||
|
{ placement: 'top-center' },
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copyTargetDataSources.length === 0) {
|
||||||
|
toast.push(
|
||||||
|
<Notification type="warning" title={translate('::App.Platform.Warning')}>
|
||||||
|
{translate('::App.Platform.PleaseSelectAtLeastOneTarget')}
|
||||||
|
</Notification>,
|
||||||
|
{ 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(
|
||||||
|
<Notification
|
||||||
|
type={notificationType}
|
||||||
|
title={
|
||||||
|
errorCount > 0
|
||||||
|
? translate('::App.Platform.Warning')
|
||||||
|
: translate('::App.Platform.Success')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{translate('::App.Platform.ExecutionCompleted') ||
|
||||||
|
`translate('::App.Platform.Successful'): ${successCount}, ${translate('::App.Platform.Error')}: ${errorCount}`}
|
||||||
|
</Notification>,
|
||||||
|
{ placement: 'top-center' },
|
||||||
|
)
|
||||||
|
|
||||||
|
setCopyResults(results)
|
||||||
|
setShowCopyResultDialog(true)
|
||||||
|
setShowCopyDialog(false)
|
||||||
|
} finally {
|
||||||
|
setIsCopyingObjects(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const availableTargetDataSourceCodes = state.dataSources
|
const availableTargetDataSourceCodes = state.dataSources
|
||||||
.filter((d) => d.code && d.code !== state.selectedDataSource)
|
.filter((d) => d.code && d.code !== state.selectedDataSource)
|
||||||
.map((d) => d.code || '')
|
.map((d) => d.code || '')
|
||||||
|
|
@ -805,8 +883,12 @@ GO`,
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
onClick={handleOpenCopyDialog}
|
onClick={handleOpenCopyDialog}
|
||||||
disabled={!state.selectedDataSource || selectedExplorerObjects.length === 0}
|
disabled={!state.selectedDataSource}
|
||||||
className="shadow-sm"
|
className="shadow-sm"
|
||||||
|
title={
|
||||||
|
translate('::App.Platform.CopyOrExecuteSql') ||
|
||||||
|
'Seçili nesneleri kopyala veya SQL script calistir'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{translate('::App.Platform.CopySelectedObjects') || 'Copy Selected Objects'}
|
{translate('::App.Platform.CopySelectedObjects') || 'Copy Selected Objects'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -978,65 +1060,163 @@ GO`,
|
||||||
>
|
>
|
||||||
<div className="flex h-full max-h-[85vh] flex-col">
|
<div className="flex h-full max-h-[85vh] flex-col">
|
||||||
<h5 className="mb-3">{translate('::App.Platform.CopySelectedObjects')}</h5>
|
<h5 className="mb-3">{translate('::App.Platform.CopySelectedObjects')}</h5>
|
||||||
<div className="flex-1 overflow-y-auto pr-1">
|
|
||||||
<div className="mb-2 flex items-center justify-between gap-4">
|
|
||||||
<p className="text-sm text-gray-600 dark:text-gray-400 mb-0">
|
|
||||||
{translate('::App.Platform.SourceDataSource')}:{' '}
|
|
||||||
<strong>{state.selectedDataSource}</strong>
|
|
||||||
</p>
|
|
||||||
<label className="flex items-center gap-2 text-sm cursor-pointer shrink-0">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={overwriteIfExists}
|
|
||||||
onChange={(e) => setOverwriteIfExists(e.target.checked)}
|
|
||||||
disabled={isCopyingObjects}
|
|
||||||
/>
|
|
||||||
<span>{translate('::App.Platform.OverwriteIfExists')}</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-4 max-h-36 overflow-auto border rounded p-2">
|
{/* Mode Tabs */}
|
||||||
{selectedExplorerObjects.map((obj) => (
|
<div className="flex gap-2 mb-4 border-b">
|
||||||
<div key={obj.id} className="text-sm py-0.5">
|
<button
|
||||||
{obj.objectType.toUpperCase()} - {obj.fullName}
|
onClick={() => setCopyDialogMode('objects')}
|
||||||
</div>
|
className={`px-4 py-2 font-medium text-sm border-b-2 transition ${
|
||||||
))}
|
copyDialogMode === 'objects'
|
||||||
</div>
|
? 'border-blue-500 text-blue-600'
|
||||||
|
: 'border-transparent text-gray-600 hover:text-gray-900'
|
||||||
<div className="mb-4">
|
}`}
|
||||||
<div className="text-sm font-medium mb-2">
|
disabled={isCopyingObjects}
|
||||||
{translate('::App.Platform.TargetDataSources')}
|
>
|
||||||
</div>
|
{translate('::App.Platform.CopyObjects') || 'Nesneleri Kopyala'}
|
||||||
<label className="flex items-center gap-2 text-sm cursor-pointer mb-2">
|
</button>
|
||||||
<input
|
<button
|
||||||
type="checkbox"
|
onClick={() => setCopyDialogMode('sql')}
|
||||||
checked={allTargetsSelected}
|
className={`px-4 py-2 font-medium text-sm border-b-2 transition ${
|
||||||
onChange={(e) => handleToggleSelectAllTargets(e.target.checked)}
|
copyDialogMode === 'sql'
|
||||||
/>
|
? 'border-blue-500 text-blue-600'
|
||||||
<span>{translate('::App.Platform.SelectAllTargets') || 'Tumunu sec'}</span>
|
: 'border-transparent text-gray-600 hover:text-gray-900'
|
||||||
</label>
|
}`}
|
||||||
<div className="max-h-44 overflow-auto border-t pt-2">
|
disabled={isCopyingObjects}
|
||||||
{availableTargetDataSourceCodes.map((code) => {
|
>
|
||||||
const checked = copyTargetDataSources.includes(code)
|
{translate('::App.Platform.DirectSqlScript') || 'Direkt SQL Script'}
|
||||||
return (
|
</button>
|
||||||
<label key={code} className="flex items-center gap-2 text-sm cursor-pointer">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={checked}
|
|
||||||
onChange={(e) => {
|
|
||||||
setCopyTargetDataSources((prev) => {
|
|
||||||
if (e.target.checked) return [...prev, code]
|
|
||||||
return prev.filter((x) => x !== code)
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<span>{code}</span>
|
|
||||||
</label>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 overflow-y-auto pr-1">
|
||||||
|
{copyDialogMode === 'objects' ? (
|
||||||
|
<>
|
||||||
|
{/* Objects Mode */}
|
||||||
|
<div className="mb-2 flex items-center justify-between gap-4">
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 mb-0">
|
||||||
|
{translate('::App.Platform.SourceDataSource')}:{' '}
|
||||||
|
<strong>{state.selectedDataSource}</strong>
|
||||||
|
</p>
|
||||||
|
<label className="flex items-center gap-2 text-sm cursor-pointer shrink-0">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={overwriteIfExists}
|
||||||
|
onChange={(e) => setOverwriteIfExists(e.target.checked)}
|
||||||
|
disabled={isCopyingObjects}
|
||||||
|
/>
|
||||||
|
<span>{translate('::App.Platform.OverwriteIfExists')}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4 max-h-36 overflow-auto border rounded p-2">
|
||||||
|
{selectedExplorerObjects.length === 0 ? (
|
||||||
|
<p className="text-sm text-gray-500">
|
||||||
|
{translate('::App.Platform.NoObjectSelected') ||
|
||||||
|
'Secili nesne yok. Lutfen Explorer alanından bir nesne secin.'}
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
selectedExplorerObjects.map((obj) => (
|
||||||
|
<div key={obj.id} className="text-sm py-0.5">
|
||||||
|
{obj.objectType.toUpperCase()} - {obj.fullName}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<div className="text-sm font-medium mb-2">
|
||||||
|
{translate('::App.Platform.TargetDataSources')}
|
||||||
|
</div>
|
||||||
|
<label className="flex items-center gap-2 text-sm cursor-pointer mb-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={allTargetsSelected}
|
||||||
|
onChange={(e) => handleToggleSelectAllTargets(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span>{translate('::App.Platform.SelectAllTargets') || 'Tumunu sec'}</span>
|
||||||
|
</label>
|
||||||
|
<div className="max-h-44 overflow-auto border-t pt-2">
|
||||||
|
{availableTargetDataSourceCodes.map((code) => {
|
||||||
|
const checked = copyTargetDataSources.includes(code)
|
||||||
|
return (
|
||||||
|
<label
|
||||||
|
key={code}
|
||||||
|
className="flex items-center gap-2 text-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={checked}
|
||||||
|
onChange={(e) => {
|
||||||
|
setCopyTargetDataSources((prev) => {
|
||||||
|
if (e.target.checked) return [...prev, code]
|
||||||
|
return prev.filter((x) => x !== code)
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span>{code}</span>
|
||||||
|
</label>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{/* SQL Mode */}
|
||||||
|
<div className="mb-2">
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 mb-2">
|
||||||
|
{translate('::App.Platform.SourceDataSource')}:{' '}
|
||||||
|
<strong>{state.selectedDataSource}</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4 border rounded bg-white dark:bg-gray-800 h-64 overflow-hidden">
|
||||||
|
<SqlEditor
|
||||||
|
value={sqlScriptForCopy}
|
||||||
|
onChange={(value) => setSqlScriptForCopy(value || '')}
|
||||||
|
readOnly={isCopyingObjects}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<div className="text-sm font-medium mb-2">
|
||||||
|
{translate('::App.Platform.TargetDataSources')}
|
||||||
|
</div>
|
||||||
|
<label className="flex items-center gap-2 text-sm cursor-pointer mb-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={allTargetsSelected}
|
||||||
|
onChange={(e) => handleToggleSelectAllTargets(e.target.checked)}
|
||||||
|
/>
|
||||||
|
<span>{translate('::App.Platform.SelectAllTargets') || 'Tumunu sec'}</span>
|
||||||
|
</label>
|
||||||
|
<div className="max-h-44 overflow-auto border-t pt-2">
|
||||||
|
{availableTargetDataSourceCodes.map((code) => {
|
||||||
|
const checked = copyTargetDataSources.includes(code)
|
||||||
|
return (
|
||||||
|
<label
|
||||||
|
key={code}
|
||||||
|
className="flex items-center gap-2 text-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={checked}
|
||||||
|
onChange={(e) => {
|
||||||
|
setCopyTargetDataSources((prev) => {
|
||||||
|
if (e.target.checked) return [...prev, code]
|
||||||
|
return prev.filter((x) => x !== code)
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span>{code}</span>
|
||||||
|
</label>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="mt-2 flex justify-end gap-2 border-t pt-3">
|
<div className="mt-2 flex justify-end gap-2 border-t pt-3">
|
||||||
<Button
|
<Button
|
||||||
variant="plain"
|
variant="plain"
|
||||||
|
|
@ -1047,11 +1227,18 @@ GO`,
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="solid"
|
variant="solid"
|
||||||
onClick={handleCopyObjects}
|
onClick={copyDialogMode === 'objects' ? handleCopyObjects : handleExecuteDirectSql}
|
||||||
loading={isCopyingObjects}
|
loading={isCopyingObjects}
|
||||||
disabled={copyTargetDataSources.length === 0 || selectedExplorerObjects.length === 0}
|
disabled={
|
||||||
|
copyTargetDataSources.length === 0 ||
|
||||||
|
(copyDialogMode === 'objects'
|
||||||
|
? selectedExplorerObjects.length === 0
|
||||||
|
: !sqlScriptForCopy?.trim())
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{translate('::Copy')}
|
{copyDialogMode === 'objects'
|
||||||
|
? translate('::Copy')
|
||||||
|
: translate('::App.Platform.Execute') || 'Calistir'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1137,11 +1324,21 @@ GO`,
|
||||||
<table className="hidden md:table w-full table-fixed text-sm">
|
<table className="hidden md:table w-full table-fixed text-sm">
|
||||||
<thead className="bg-gray-50 dark:bg-gray-700 sticky top-0 z-10">
|
<thead className="bg-gray-50 dark:bg-gray-700 sticky top-0 z-10">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="w-[110px] text-left px-3 py-2 border-b">{translate('::App.Platform.Status')}</th>
|
<th className="w-[110px] text-left px-3 py-2 border-b">
|
||||||
<th className="w-[270px] text-left px-3 py-2 border-b">{translate('::App.Platform.Object')}</th>
|
{translate('::App.Platform.Status')}
|
||||||
<th className="w-[90px] text-left px-3 py-2 border-b">{translate('::App.Platform.Type')}</th>
|
</th>
|
||||||
<th className="w-[140px] text-left px-3 py-2 border-b">{translate('::App.Platform.Target')}</th>
|
<th className="w-[270px] text-left px-3 py-2 border-b">
|
||||||
<th className="text-left px-3 py-2 border-b">{translate('::App.Platform.Message')}</th>
|
{translate('::App.Platform.Object')}
|
||||||
|
</th>
|
||||||
|
<th className="w-[90px] text-left px-3 py-2 border-b">
|
||||||
|
{translate('::App.Platform.Type')}
|
||||||
|
</th>
|
||||||
|
<th className="w-[140px] text-left px-3 py-2 border-b">
|
||||||
|
{translate('::App.Platform.Target')}
|
||||||
|
</th>
|
||||||
|
<th className="text-left px-3 py-2 border-b">
|
||||||
|
{translate('::App.Platform.Message')}
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
@ -1209,7 +1406,7 @@ GO`,
|
||||||
|
|
||||||
<div className="flex justify-end gap-2 mt-4">
|
<div className="flex justify-end gap-2 mt-4">
|
||||||
<Button variant="solid" onClick={() => setShowCopyResultDialog(false)}>
|
<Button variant="solid" onClick={() => setShowCopyResultDialog(false)}>
|
||||||
Kapat
|
{translate('::App.Platform.Close')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue