SqlTableDesigner ve Localization

This commit is contained in:
Sedat ÖZTÜRK 2026-03-03 09:15:23 +03:00
parent 2b96619a1d
commit 963dfb56f0
5 changed files with 582 additions and 107 deletions

View file

@ -1020,6 +1020,24 @@
"en": "Delete",
"tr": "Sil"
},
{
"resourceName": "Platform",
"key": "App.Platform.HangfireLogin",
"en": "Hangfire Login",
"tr": "Hangfire Girişi"
},
{
"resourceName": "Platform",
"key": "App.Platform.HangfireOpen",
"en": "Hangfire Open",
"tr": "Hangfire Aç"
},
{
"resourceName": "Platform",
"key": "App.Platform.HangfireRefresh",
"en": "Hangfire Refresh",
"tr": "Hangfire Yenile"
},
{
"resourceName": "Platform",
"key": "DeleteConfirmation",
@ -3186,6 +3204,12 @@
"en": "MENU",
"tr": "MENÜ"
},
{
"resourceName": "Platform",
"key": "ListForms.ListForm.ClearRedisCache",
"en": "Clear Redis Cache",
"tr": "Redis Önbelleğini Temizle"
},
{
"resourceName": "Platform",
"key": "ListForms.ListForm.SaveGridState",
@ -10224,6 +10248,12 @@
"tr": "Düzenle",
"en": "Edit"
},
{
"resourceName": "Platform",
"key": "App.Platform.Permissions",
"tr": "İzinler",
"en": "Permissions"
},
{
"resourceName": "Platform",
"key": "App.Platform.Detail",
@ -10440,6 +10470,24 @@
"tr": "View",
"en": "View"
},
{
"resourceName": "Platform",
"key": "App.Platform.Manage",
"tr": "Yönet",
"en": "Manage"
},
{
"resourceName": "Platform",
"key": "App.Platform.Show",
"tr": "Göster",
"en": "Show"
},
{
"resourceName": "Platform",
"key": "App.Platform.Design",
"tr": "Design",
"en": "Design"
},
{
"resourceName": "Platform",
"key": "App.Platform.Tables",
@ -16369,6 +16417,426 @@
"key": "ListForms.Wizard.Step2.SelectKeyColumn",
"en": "Select key column",
"tr": "Anahtar sütunu seç"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.ColumnDesign",
"en": "Column Design",
"tr": "Sütun Tasarımı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.EntitySettings",
"en": "Entity Settings",
"tr": "Entity Ayarları"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Relationships",
"en": "Relationships",
"tr": "İlişkiler"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.TSqlPreview",
"en": "T-SQL Preview",
"tr": "T-SQL Önizleme"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.TableDesigner",
"en": "Table Designer",
"tr": "Tablo Tasarımcısı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.EditTable",
"en": "Edit Table",
"tr": "Tablo Düzenle"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.EditModeDescription",
"en": "Edit existing columns, add new ones or define relationships — ALTER TABLE SQL is generated",
"tr": "Mevcut sütunları düzenleyin, yeni ekleyin veya ilişki tanımlayın — ALTER TABLE SQL üretilir"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.NewModeDescription",
"en": "Define columns, configure settings and deploy with T-SQL",
"tr": "Sütunları tanımlayın, ayarları yapın ve T-SQL ile deploy edin"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.LoadingColumns",
"en": "Loading table columns...",
"tr": "Tablo sütunları yükleniyor..."
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.AddFullAuditedColumns",
"en": "Add Full Audited Columns",
"tr": "Full Audited Entity Sütunları Ekle"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.AddMultiTenantColumns",
"en": "Add Multi-Tenant Column",
"tr": "MultiTenant Sütunları Ekle"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.ClearAllColumns",
"en": "Clear All Columns",
"tr": "Tüm Sütunları Sil"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.AddColumn",
"en": "Add Column",
"tr": "Sütun Ekle"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.ColumnName",
"en": "Column Name *",
"tr": "Sütun Adı *"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.ColumnNamePlaceholder",
"en": "ColumnName",
"tr": "SütunAdı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.DataType",
"en": "Data Type *",
"tr": "Veri Tipi *"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Max",
"en": "Max",
"tr": "Max"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Nullable",
"en": "Null",
"tr": "Null"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.DefaultValue",
"en": "Default",
"tr": "Varsayılan"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Note",
"en": "Note",
"tr": "Not"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Actions",
"en": "Actions",
"tr": "İşlem"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.MoveUp",
"en": "Move Up",
"tr": "Yukarı Taşı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.MoveDown",
"en": "Move Down",
"tr": "Aşağı Taşı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Delete",
"en": "Delete",
"tr": "Sil"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Edit",
"en": "Edit",
"tr": "Düzenle"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.DuplicateColumnWarning",
"en": "⚠️ Duplicate column names are not allowed:",
"tr": "⚠️ Aynı isimde sütun tanımlanamaz:"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.NoIdColumnWarning",
"en": "⚠️ Full Audited Entity not selected. You must manually add an Id column as the primary key for the table.",
"tr": "⚠️ Full Audited Entity seçilmedi. Tablonun birincil anahtarı için Id sütununu elle eklemeniz gerekmektedir."
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.NoIdColumnError",
"en": "⛔ Full Audited Entity not selected. Go back and manually add an Id column (uniqueidentifier) as the primary key.",
"tr": "⛔ Full Audited Entity seçili değil. Geri dönüp Id sütununu uniqueidentifier tipinde manuel olarak eklemelisiniz."
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.MenuName",
"en": "Menu Name",
"tr": "Menü Adı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.EntityName",
"en": "Entity Name",
"tr": "Entity Adı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.TableName",
"en": "Table Name",
"tr": "Tablo Adı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.TableNameAutoGenerated",
"en": "Auto-generated from Menu and Entity Name",
"tr": "Menü ve Entity Name seçince otomatik oluşur"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.EntityNamePlaceholder",
"en": "e.g. Product, User, Order",
"tr": "örn. Product, User, Order"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Loading",
"en": "Loading...",
"tr": "Yükleniyor..."
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.LoadingFkConstraints",
"en": "Loading existing FK constraints...",
"tr": "Mevcut FK kısıtlamaları yükleniyor..."
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.NoRelationshipsDefined",
"en": "No relationship defined",
"tr": "İlişki tanımlanmamış"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Relationship",
"en": "relationship(s)",
"tr": "ilişki"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.AddRelationship",
"en": "Add Relationship",
"tr": "İlişki Ekle"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.NoRelationshipsYet",
"en": "No relationships defined for this table yet",
"tr": "Bu tablo için henüz ilişki tanımlanmamış"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.StepIsOptional",
"en": "This step is optional, you can skip it",
"tr": "Bu adım isteğe bağlıdır, atlayabilirsiniz"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Required",
"en": "Required",
"tr": "Zorunlu"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.EditRelationship",
"en": "Edit Relationship",
"tr": "İlişkiyi Düzenle"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.AddNewRelationship",
"en": "Add New Relationship",
"tr": "Yeni İlişki Ekle"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.RelationshipType",
"en": "Relationship Type",
"tr": "İlişki Tipi"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.FkColumnInThisTable",
"en": "FK Column in This Table *",
"tr": "Bu Tablodaki FK Sütunu *"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.SelectPlaceholder",
"en": "— Select —",
"tr": "— Seçiniz —"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.TargetTable",
"en": "Target Table *",
"tr": "Hedef Tablo *"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.TargetColumn",
"en": "Target Column (PK)",
"tr": "Hedef Sütun (PK)"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.SelectTargetTableFirst",
"en": "— Select target table first —",
"tr": "— Önce hedef tablo seçin —"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.CascadeDelete",
"en": "Cascade Delete",
"tr": "Cascade Delete"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.CascadeUpdate",
"en": "Cascade Update",
"tr": "Cascade Update"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Description",
"en": "Description",
"tr": "Açıklama"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.OptionalDescriptionPlaceholder",
"en": "Optional description...",
"tr": "İsteğe bağlııklama..."
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.GeneratedSqlDescription",
"en": "Generated T-SQL code. Apply to the database with Deploy.",
"tr": "Oluşturulan T-SQL kodu. Deploy Et ile veritabanına uygulayın."
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Copy",
"en": "Copy",
"tr": "Kopyala"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Cancel",
"en": "Cancel",
"tr": "İptal"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Save",
"en": "Save",
"tr": "Kaydet"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Back",
"en": "Back",
"tr": "Geri"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Next",
"en": "Next",
"tr": "İleri"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Deploy",
"en": "Deploy",
"tr": "Deploy Et"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Warning",
"en": "Warning",
"tr": "Uyarı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.PleaseSelectDataSource",
"en": "Please select a data source first.",
"tr": "Lütfen önce bir veri kaynağı seçin."
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.Success",
"en": "Success",
"tr": "Başarılı"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.TableUpdated",
"en": "Table successfully updated",
"tr": "Tablo başarıyla güncellendi"
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.TableCreated",
"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",
"en": "Table could not be created.",
"tr": "Tablo oluşturulamadı."
},
{
"resourceName": "Platform",
"key": "App.SqlQueryManager.TableDeployFailed",
"en": "Table could not be deployed.",
"tr": "Tablo deploy edilemedi."
}
]
}

View file

@ -665,8 +665,8 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
UpdateServiceAddress = "list-form-dynamic-api/role-update",
CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] {
new() {
Hint = "Permission",
Text = "Permission",
Hint = "App.Platform.Permissions",
Text = "App.Platform.Permissions",
AuthName = PlatformConsts.IdentityPermissions.Roles.ManagePermissions,
DialogName = "RolesPermission",
DialogParameters = JsonSerializer.Serialize(new { name = "@Name" }),
@ -803,16 +803,16 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
UpdateServiceAddress = "list-form-dynamic-api/user-update",
CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] {
new() {
Hint = "Detail",
Text ="Detail",
Hint = "App.Platform.Detail",
Text ="App.Platform.Detail",
UrlTarget="_blank",
AuthName=PlatformConsts.IdentityPermissions.Users.Update,
Url="/admin/users/detail/@Id",
IsVisible = true,
},
new() {
Hint = "Permission",
Text = "Permission",
Hint = "App.Platform.Permissions",
Text = "App.Platform.Permissions",
AuthName = PlatformConsts.IdentityPermissions.Users.ManagePermissions,
DialogName = "UsersPermission",
DialogParameters = JsonSerializer.Serialize(new { name = "@Email", id = "@Id" }),
@ -1195,8 +1195,8 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
PagerOptionJson = DefaultPagerOptionJson,
CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] {
new CommandColumnDto() {
Hint = "Details",
Text = "Details",
Hint = "ListForms.ListFormEdit.TabDetails",
Text = "ListForms.ListFormEdit.TabDetails",
AuthName = listFormName,
DialogName = "AuditLogDetail",
DialogParameters = JsonSerializer.Serialize(new { id = "@Id" }),
@ -2272,16 +2272,16 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
}),
CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] {
new() {
Hint = "View",
Text ="View",
Hint = "App.Platform.View",
Text ="App.Platform.View",
UrlTarget="_blank",
AuthName = listFormName,
Url=$"/admin/reports/TemplateReport/view?id=@Id",
IsVisible = true,
},
new() {
Hint = "Design",
Text ="Design",
Hint = "App.Platform.Design",
Text ="App.Platform.Design",
UrlTarget="_blank",
AuthName = listFormName + ".Update",
Url=$"/admin/reports/TemplateReport/design?id=@Id",

View file

@ -17,6 +17,8 @@ using Volo.Abp.TenantManagement;
using AppCodes = Sozsoft.Platform.Data.Seeds.SeedConsts.AppCodes;
using static Sozsoft.Platform.PlatformConsts;
using static Sozsoft.Platform.PlatformSeeder.SeederDefaults;
using Microsoft.Extensions.Localization;
using Sozsoft.Platform.Localization;
namespace Sozsoft.Platform.Data.Seeds;
@ -27,19 +29,23 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
private readonly IdentityUserManager _identityUserManager;
private readonly IdentityRoleManager _identityRoleManager;
private readonly IConfiguration _configuration;
protected IStringLocalizer<PlatformResource> _localizer { get; }
public ListFormSeeder_Saas(
IRepository<ListForm, Guid> listFormRepository,
IRepository<ListFormField, Guid> listFormFieldRepository,
IdentityUserManager userManager,
IdentityRoleManager roleManager,
IConfiguration configuration)
IConfiguration configuration,
IStringLocalizer<PlatformResource> localizer
)
{
_listFormRepository = listFormRepository;
_listFormFieldRepository = listFormFieldRepository;
_identityUserManager = userManager;
_identityRoleManager = roleManager;
_configuration = configuration;
_localizer = localizer;
}
public async Task SeedAsync(DataSeedContext context)
@ -1921,8 +1927,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] {
new() {
ButtonPosition= UiCommandButtonPositionTypeEnum.Toolbar,
Hint = "Clear Redis Cache",
Text = "Clear Redis Cache",
Hint = "ListForms.ListForm.ClearRedisCache",
Text = "ListForms.ListForm.ClearRedisCache",
AuthName = listFormName,
OnClick = "UiEvalService.ApiClearRedisCache();",
IsVisible = true,
@ -2254,16 +2260,16 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] {
new() {
Hint = "Manage Listform",
Text ="Manage",
Hint = "App.Platform.Manage",
Text ="App.Platform.Manage",
UrlTarget = "_blank",
AuthName = listFormName + ".Update",
Url = "/admin/listform/edit/@ListFormCode",
IsVisible = true,
},
new() {
Hint = "Göster",
Text = "Göster",
Hint = "App.Platform.Show",
Text = "App.Platform.Show",
UrlTarget = "_blank",
AuthName = listFormName,
Url = "/admin/list/@ListFormCode",
@ -3153,24 +3159,24 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] {
new() {
ButtonPosition= UiCommandButtonPositionTypeEnum.Toolbar,
Hint = "Hangfire Login",
Text = "Hangfire Login",
Hint = "App.Platform.HangfireLogin",
Text = "App.Platform.HangfireLogin",
AuthName=listFormName,
Url= swaggerRootUrl + "/Account/Login",
IsVisible = true,
},
new() {
ButtonPosition= UiCommandButtonPositionTypeEnum.Toolbar,
Hint = "Hangfire Aç",
Text = "Hangfire Aç",
Hint = "App.Platform.HangfireOpen",
Text = "App.Platform.HangfireOpen",
AuthName=listFormName,
Url= swaggerRootUrl + "/hangfire",
IsVisible = true,
},
new() {
ButtonPosition= UiCommandButtonPositionTypeEnum.Toolbar,
Hint = "Hangfire Tazele",
Text = "Hangfire Tazele",
Hint = "App.Platform.HangfireRefresh",
Text = "App.Platform.HangfireRefresh",
AuthName=listFormName,
OnClick="UiEvalService.ApiGenerateBackgroundWorkers();",
IsVisible = true,

View file

@ -779,8 +779,8 @@ const SqlTableDesignerDialog = ({
const handleDeploy = async () => {
if (!dataSource) {
toast.push(
<Notification type="warning" title="Uyari">
Lutfen once bir veri kaynagi secin.
<Notification type="warning" title={translate('::App.SqlQueryManager.Warning')}>
{translate('::App.SqlQueryManager.PleaseSelectDataSource')}
</Notification>,
{ placement: 'top-center' },
)
@ -795,8 +795,8 @@ const SqlTableDesignerDialog = ({
if (result.data.success) {
const deployedTable = settings.tableName || initialTableData?.tableName || ''
toast.push(
<Notification type="success" title="Basarili">
Tablo basariyla {isEditMode ? 'güncellendi' : 'oluşturuldu'}: [dbo].[{deployedTable}]
<Notification type="success" title={translate('::App.SqlQueryManager.Success')}>
{`${translate(isEditMode ? '::App.SqlQueryManager.TableUpdated' : '::App.SqlQueryManager.TableCreated')}: [dbo].[${deployedTable}]`}
</Notification>,
{ placement: 'top-center' },
)
@ -804,16 +804,16 @@ const SqlTableDesignerDialog = ({
handleClose()
} else {
toast.push(
<Notification type="danger" title="Hata">
{result.data.message || 'Tablo olusturulamadi.'}
<Notification type="danger" title={translate('::App.SqlQueryManager.Error')}>
{result.data.message || translate('::App.SqlQueryManager.TableCreationFailed')}
</Notification>,
{ placement: 'top-center' },
)
}
} catch (error: any) {
toast.push(
<Notification type="danger" title="Hata">
{error.response?.data?.error?.message || 'Tablo deploy edilemedi.'}
<Notification type="danger" title={translate('::App.SqlQueryManager.Error')}>
{error.response?.data?.error?.message || translate('::App.SqlQueryManager.TableDeployFailed')}
</Notification>,
{ placement: 'top-center' },
)
@ -836,7 +836,12 @@ const SqlTableDesignerDialog = ({
// ── Step Indicator ─────────────────────────────────────────────────────────
const STEP_LABELS = ['Sütun Tasarımı', 'Entity Ayarları', 'İlişkiler', 'T-SQL Önizleme']
const STEP_LABELS = [
translate('::App.SqlQueryManager.ColumnDesign'),
translate('::App.SqlQueryManager.EntitySettings'),
translate('::App.SqlQueryManager.Relationships'),
translate('::App.SqlQueryManager.TSqlPreview'),
]
const renderStepIndicator = () => (
<div className="flex items-center justify-between mb-2">
@ -873,7 +878,7 @@ const SqlTableDesignerDialog = ({
<div className="flex flex-col">
{colsLoading && (
<div className="flex items-center justify-center py-12 text-gray-500">
<span className="animate-spin mr-2">&#9696;</span> Tablo sütunları yükleniyor...
<span className="animate-spin mr-2">&#9696;</span> {translate('::App.SqlQueryManager.LoadingColumns')}
</div>
)}
{!colsLoading && (
@ -881,31 +886,31 @@ const SqlTableDesignerDialog = ({
<div className="flex items-center justify-between py-2">
<div className="flex items-center gap-2">
<Button size="xs" variant="solid" color="blue-600" onClick={addFullAuditedColumns}>
Full Audited Entity Sütunları Ekle
{translate('::App.SqlQueryManager.AddFullAuditedColumns')}
</Button>
<Button size="xs" variant="solid" color="green-600" onClick={addMultiTenantColumns}>
MultiTenant Sütunları Ekle
{translate('::App.SqlQueryManager.AddMultiTenantColumns')}
</Button>
</div>
<div className="flex items-center gap-2">
<Button size="xs" variant="solid" color="red-600" icon={<FaTrash />} onClick={clearAllColumns}>
Tüm Sütunları Sil
{translate('::App.SqlQueryManager.ClearAllColumns')}
</Button>
<Button size="xs" variant="solid" color="blue-600" icon={<FaPlus />} onClick={addColumn}>
Sütun Ekle
{translate('::App.SqlQueryManager.AddColumn')}
</Button>
</div>
</div>
{/* Header row */}
<div className="grid grid-cols-12 gap-1 px-1 py-1 bg-gray-50 dark:bg-gray-800 rounded text-xs font-semibold text-gray-600 dark:text-gray-300">
<div className="col-span-3">Sutun Adi *</div>
<div className="col-span-3">Veri Tipi *</div>
<div className="col-span-1 text-center">Max</div>
<div className="col-span-1 text-center">Null</div>
<div className="col-span-2">Varsayilan</div>
<div className="col-span-1">Not</div>
<div className="col-span-1 text-center">Islem</div>
<div className="col-span-3">{translate('::App.SqlQueryManager.ColumnName')}</div>
<div className="col-span-3">{translate('::App.SqlQueryManager.DataType')}</div>
<div className="col-span-1 text-center">{translate('::App.SqlQueryManager.Max')}</div>
<div className="col-span-1 text-center">{translate('::App.SqlQueryManager.Nullable')}</div>
<div className="col-span-2">{translate('::App.SqlQueryManager.DefaultValue')}</div>
<div className="col-span-1">{translate('::App.SqlQueryManager.Note')}</div>
<div className="col-span-1 text-center">{translate('::App.SqlQueryManager.Actions')}</div>
</div>
{/* Editable column rows */}
@ -965,7 +970,7 @@ const SqlTableDesignerDialog = ({
className={`w-full px-2 py-1 text-sm border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white ${
isDuplicate ? 'border-red-400' : ''
}`}
placeholder="SutunAdi"
placeholder={translate('::App.SqlQueryManager.ColumnNamePlaceholder')}
value={col.columnName}
onChange={(e) => updateColumn(col.id, 'columnName', e.target.value)}
/>
@ -1008,7 +1013,7 @@ const SqlTableDesignerDialog = ({
<input
type="text"
className="w-full px-2 py-1 text-sm border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white"
placeholder="Varsayilan"
placeholder={translate('::App.SqlQueryManager.DefaultValue')}
value={col.defaultValue}
onChange={(e) => updateColumn(col.id, 'defaultValue', e.target.value)}
/>
@ -1017,7 +1022,7 @@ const SqlTableDesignerDialog = ({
<input
type="text"
className="w-full px-2 py-1 text-xs border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white"
placeholder="Not"
placeholder={translate('::App.SqlQueryManager.Note')}
value={col.description}
onChange={(e) => updateColumn(col.id, 'description', e.target.value)}
/>
@ -1027,7 +1032,7 @@ const SqlTableDesignerDialog = ({
onClick={() => moveColumn(col.id, 'up')}
disabled={idx === 0}
className="p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-30 text-gray-500"
title="Yukari tasi"
title={translate('::App.SqlQueryManager.MoveUp')}
>
<FaArrowUp className="text-xs" />
</button>
@ -1035,15 +1040,14 @@ const SqlTableDesignerDialog = ({
onClick={() => moveColumn(col.id, 'down')}
disabled={idx === columns.length - 1}
className="p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-30 text-gray-500"
title="Asagi tasi"
title={translate('::App.SqlQueryManager.MoveDown')}
>
<FaArrowDown className="text-xs" />
</button>
<button
onClick={() => removeColumn(col.id)}
className="p-1 rounded hover:bg-red-50 dark:hover:bg-red-900/30 text-red-500"
title="Sil"
>
title={translate('::App.SqlQueryManager.Delete')}>
<FaTrash className="text-xs" />
</button>
</div>
@ -1055,10 +1059,8 @@ const SqlTableDesignerDialog = ({
{/* Id warning */}
{!isEditMode &&
!columns.some((c) => c.columnName.trim().toLowerCase() === 'id') && (
<div className="px-2 py-1.5 bg-orange-50 dark:bg-orange-900/20 border border-orange-300 dark:border-orange-700 rounded text-xs text-orange-700 dark:text-orange-300">
<strong>Full Audited Entity</strong> seçilmedi. Tablonun birincil anahtarı için{' '}
<code className="bg-orange-100 dark:bg-orange-900/40 px-1 rounded">Id</code> sütununu
elle eklemeniz gerekmektedir.
<div className="px-2 py-1.5 mt-2 bg-orange-50 dark:bg-orange-900/20 border border-orange-300 dark:border-orange-700 rounded text-xs text-orange-700 dark:text-orange-300">
{translate('::App.SqlQueryManager.NoIdColumnWarning')}
</div>
)}
</>
@ -1074,7 +1076,7 @@ const SqlTableDesignerDialog = ({
{/* Menu Name */}
<div className="col-span-2">
<label className="block text-sm font-medium mb-1">
Menu Name <span className="text-red-500">*</span>
{translate('::App.SqlQueryManager.MenuName')} <span className="text-red-500">*</span>
</label>
<select
className="w-full px-3 py-2 text-sm border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white"
@ -1089,13 +1091,13 @@ const SqlTableDesignerDialog = ({
</option>
))}
</select>
{menuLoading && <p className="text-xs text-gray-400 mt-1">Yukleniyor...</p>}
{menuLoading && <p className="text-xs text-gray-400 mt-1">{translate('::App.SqlQueryManager.Loading')}</p>}
</div>
{/* Entity Name */}
<div>
<label className="block text-sm font-medium mb-1">
Entity Name <span className="text-red-500">*</span>
{translate('::App.SqlQueryManager.EntityName')} <span className="text-red-500">*</span>
</label>
<input
type="text"
@ -1103,19 +1105,19 @@ const SqlTableDesignerDialog = ({
className="w-full px-3 py-2 text-sm border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white"
value={settings.entityName}
onChange={(e) => onEntityNameChange(e.target.value)}
placeholder="e.g. Product, User, Order"
placeholder={translate('::App.SqlQueryManager.EntityNamePlaceholder')}
/>
</div>
{/* Table Name (readonly, auto-generated) */}
<div>
<label className="block text-sm font-medium mb-1">Table Name</label>
<label className="block text-sm font-medium mb-1">{translate('::App.SqlQueryManager.TableName')}</label>
<input
type="text"
readOnly
className="w-full px-3 py-2 text-sm border rounded bg-gray-50 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 cursor-not-allowed"
value={isEditMode ? (initialTableData?.tableName ?? '') : settings.tableName}
placeholder="Menu ve Entity Name seçince otomatik oluşur"
placeholder={translate('::App.SqlQueryManager.TableNameAutoGenerated')}
/>
</div>
</div>
@ -1125,10 +1127,7 @@ const SqlTableDesignerDialog = ({
{!isEditMode &&
!columns.some((c) => c.columnName.trim().toLowerCase() === 'id') && (
<div className="px-3 py-2 bg-red-50 dark:bg-red-900/20 border border-red-300 dark:border-red-700 rounded text-xs text-red-700 dark:text-red-300">
<strong>Full Audited Entity</strong> seçili değil. Geri dönüp{' '}
<code className="bg-red-100 dark:bg-red-900/40 px-1 rounded">Id</code> sütununu{' '}
<code className="bg-red-100 dark:bg-red-900/40 px-1 rounded">uniqueidentifier</code>{' '}
tipinde manuel olarak eklemelisiniz.
{translate('::App.SqlQueryManager.NoIdColumnError')}
</div>
)}
</div>
@ -1141,20 +1140,22 @@ const SqlTableDesignerDialog = ({
{/* Loading indicator for edit mode */}
{fksLoading && (
<div className="flex items-center justify-center py-10 text-gray-500 text-sm gap-2">
<span className="animate-spin">&#9696;</span> Mevcut FK kısıtlamaları yükleniyor...
<span className="animate-spin">&#9696;</span> {translate('::App.SqlQueryManager.LoadingFkConstraints')}
</div>
)}
{!fksLoading && <>
{/* Header */}
<div className="flex items-center justify-between">
<span className="text-xs text-gray-500">
{relationships.length === 0 ? 'İlişki tanımlanmamış' : `${relationships.length} ilişki`}
{relationships.length === 0
? translate('::App.SqlQueryManager.NoRelationshipsDefined')
: `${relationships.length} ${translate('::App.SqlQueryManager.Relationship')}`}
</span>
<button
onClick={openAddFk}
className="flex items-center gap-1 px-3 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white text-xs rounded-lg transition-colors"
>
<FaPlus className="w-2.5 h-2.5" /> İlişki Ekle
<FaPlus className="w-2.5 h-2.5" /> {translate('::App.SqlQueryManager.AddRelationship')}
</button>
</div>
@ -1162,8 +1163,8 @@ const SqlTableDesignerDialog = ({
{relationships.length === 0 && (
<div className="py-8 text-center border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-xl bg-gray-50 dark:bg-gray-800/50">
<FaLink className="text-3xl mx-auto text-gray-300 dark:text-gray-600 mb-2" />
<p className="text-sm text-gray-500">Bu tablo için henüz ilişki tanımlanmamış</p>
<p className="text-xs text-gray-400 mt-1">Bu adım isteğe bağlıdır, atlayabilirsiniz</p>
<p className="text-sm text-gray-500">{translate('::App.SqlQueryManager.NoRelationshipsYet')}</p>
<p className="text-xs text-gray-400 mt-1">{translate('::App.SqlQueryManager.StepIsOptional')}</p>
</div>
)}
@ -1194,7 +1195,7 @@ const SqlTableDesignerDialog = ({
<span>ON DELETE: <strong>{rel.cascadeDelete}</strong></span>
<span>ON UPDATE: <strong>{rel.cascadeUpdate}</strong></span>
{rel.isRequired && (
<span className="text-orange-600 dark:text-orange-400">Zorunlu</span>
<span className="text-orange-600 dark:text-orange-400">{translate('::App.SqlQueryManager.Required')}</span>
)}
{rel.description && (
<span className="text-gray-400 italic">{rel.description}</span>
@ -1204,14 +1205,14 @@ const SqlTableDesignerDialog = ({
<div className="flex items-center gap-1 flex-shrink-0">
<button
onClick={() => openEditFk(rel)}
title="Düzenle"
title={translate('::App.SqlQueryManager.Edit')}
className="p-1.5 text-gray-400 hover:text-indigo-600 hover:bg-indigo-50 dark:hover:bg-indigo-900/20 rounded transition-colors"
>
<FaEdit className="w-3.5 h-3.5" />
</button>
<button
onClick={() => deleteFk(rel.id)}
title="Sil"
title={translate('::App.SqlQueryManager.Delete')}
className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded transition-colors"
>
<FaTrash className="w-3.5 h-3.5" />
@ -1229,7 +1230,7 @@ const SqlTableDesignerDialog = ({
{/* Modal Header */}
<div className="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<h2 className="text-base font-bold text-gray-900 dark:text-white">
{editingFkId ? 'İlişkiyi Düzenle' : 'Yeni İlişki Ekle'}
{editingFkId ? translate('::App.SqlQueryManager.EditRelationship') : translate('::App.SqlQueryManager.AddNewRelationship')}
</h2>
<button
onClick={() => setFkModalOpen(false)}
@ -1244,7 +1245,7 @@ const SqlTableDesignerDialog = ({
{/* Relationship type */}
<div>
<label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-2">
İlişki Tipi
{translate('::App.SqlQueryManager.RelationshipType')}
</label>
<div className="flex gap-2">
{REL_TYPES.map((t) => (
@ -1269,14 +1270,14 @@ const SqlTableDesignerDialog = ({
<div className="grid grid-cols-2 gap-3">
<div>
<label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
Bu Tablodaki FK Sütunu *
{translate('::App.SqlQueryManager.FkColumnInThisTable')}
</label>
<select
value={fkForm.fkColumnName}
onChange={(e) => setFkForm((f) => ({ ...f, fkColumnName: e.target.value }))}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500"
>
<option value=""> Seçiniz </option>
<option value="">{translate('::App.SqlQueryManager.SelectPlaceholder')}</option>
{columns
.filter((c) => c.columnName.trim())
.map((c) => (
@ -1288,7 +1289,7 @@ const SqlTableDesignerDialog = ({
</div>
<div>
<label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
Hedef Tablo *
{translate('::App.SqlQueryManager.TargetTable')}
</label>
<select
value={fkForm.referencedTable}
@ -1299,7 +1300,7 @@ const SqlTableDesignerDialog = ({
}}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500"
>
<option value=""> Seçiniz </option>
<option value="">{translate('::App.SqlQueryManager.SelectPlaceholder')}</option>
{dbTables.map((t) => (
<option key={`${t.schemaName}.${t.tableName}`} value={t.tableName}>
{t.tableName}
@ -1311,7 +1312,7 @@ const SqlTableDesignerDialog = ({
<div>
<label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
Hedef Sütun (PK){targetColsLoading ? ' — Yükleniyor...' : ''}
{translate('::App.SqlQueryManager.TargetColumn')}{targetColsLoading ? `${translate('::App.SqlQueryManager.Loading')}` : ''}
</label>
<select
value={fkForm.referencedColumn}
@ -1319,7 +1320,7 @@ const SqlTableDesignerDialog = ({
disabled={targetColsLoading || targetTableColumns.length === 0}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500 disabled:opacity-60"
>
<option value=""> Önce hedef tablo seçin </option>
<option value="">{translate('::App.SqlQueryManager.SelectTargetTableFirst')}</option>
{targetTableColumns.map((col) => (
<option key={col} value={col}>
{col}
@ -1332,12 +1333,12 @@ const SqlTableDesignerDialog = ({
<div className="grid grid-cols-2 gap-3">
<div>
<label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
Cascade Delete
{translate('::App.SqlQueryManager.CascadeUpdate')}
</label>
<select
value={fkForm.cascadeDelete}
value={fkForm.cascadeUpdate}
onChange={(e) =>
setFkForm((f) => ({ ...f, cascadeDelete: e.target.value as CascadeBehavior }))
setFkForm((f) => ({ ...f, cascadeUpdate: e.target.value as CascadeBehavior }))
}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500"
>
@ -1348,12 +1349,12 @@ const SqlTableDesignerDialog = ({
</div>
<div>
<label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
Cascade Update
{translate('::App.SqlQueryManager.CascadeDelete')}
</label>
<select
value={fkForm.cascadeUpdate}
value={fkForm.cascadeDelete}
onChange={(e) =>
setFkForm((f) => ({ ...f, cascadeUpdate: e.target.value as CascadeBehavior }))
setFkForm((f) => ({ ...f, cascadeDelete: e.target.value as CascadeBehavior }))
}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500"
>
@ -1373,20 +1374,20 @@ const SqlTableDesignerDialog = ({
onChange={(e) => setFkForm((f) => ({ ...f, isRequired: e.target.checked }))}
className="w-4 h-4 text-indigo-600 rounded"
/>
<span className="text-sm text-gray-700 dark:text-gray-300">Zorunlu</span>
<span className="text-sm text-gray-700 dark:text-gray-300">{translate('::App.SqlQueryManager.Required')}</span>
</label>
</div>
{/* Description */}
<div>
<label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
ıklama
{translate('::App.SqlQueryManager.Description')}
</label>
<textarea
value={fkForm.description}
onChange={(e) => setFkForm((f) => ({ ...f, description: e.target.value }))}
rows={2}
placeholder="İsteğe bağlııklama..."
placeholder={translate('::App.SqlQueryManager.OptionalDescriptionPlaceholder')}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500 resize-none"
/>
</div>
@ -1398,14 +1399,14 @@ const SqlTableDesignerDialog = ({
onClick={() => setFkModalOpen(false)}
className="px-4 py-2 text-sm text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
>
İptal
{translate('::App.SqlQueryManager.Cancel')}
</button>
<button
onClick={saveFk}
disabled={!fkForm.fkColumnName.trim() || !fkForm.referencedTable.trim()}
className="px-4 py-2 text-sm bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 text-white rounded-lg transition-colors"
>
Kaydet
{translate('::App.SqlQueryManager.Save')}
</button>
</div>
</div>
@ -1421,13 +1422,13 @@ const SqlTableDesignerDialog = ({
<div className="flex flex-col gap-3">
<div className="flex items-center justify-between">
<p className="text-sm text-gray-600 dark:text-gray-400">
Olusturulan T-SQL kodu. <strong>Deploy Et</strong> ile veritabanina uygulayin.
{translate('::App.SqlQueryManager.GeneratedSqlDescription')}
</p>
<button
className="text-xs text-blue-500 hover:underline"
onClick={() => navigator.clipboard.writeText(generatedSql)}
>
Kopyala
{translate('::App.SqlQueryManager.Copy')}
</button>
</div>
<pre className="bg-gray-900 text-green-300 rounded-lg p-4 text-xs overflow-auto max-h-96 leading-relaxed whitespace-pre">
@ -1447,13 +1448,13 @@ const SqlTableDesignerDialog = ({
<div>
<h5 className="font-bold">
{isEditMode
? `Tablo Düzenle${initialTableData?.tableName}`
: 'Tablo Tasarımcısı'}
? `${translate('::App.SqlQueryManager.EditTable')}${initialTableData?.tableName}`
: translate('::App.SqlQueryManager.TableDesigner')}
</h5>
<p className="text-xs text-gray-500">
{isEditMode
? 'Mevcut sütunları düzenleyin, yeni ekleyin veya ilişki tanımlayın — ALTER TABLE SQL üretilir'
: 'Sütunları tanımlayın, ayarları yapın ve T-SQL ile deploy edin'}
? translate('::App.SqlQueryManager.EditModeDescription')
: translate('::App.SqlQueryManager.NewModeDescription')}
</p>
</div>
</div>
@ -1472,17 +1473,17 @@ const SqlTableDesignerDialog = ({
{/* Footer */}
<div className="flex justify-between items-center border-t pt-3 mt-1">
<Button variant="plain" onClick={handleClose}>
Iptal
{translate('::App.SqlQueryManager.Cancel')}
</Button>
<div className="flex items-center gap-2">
{step > 0 && (
<Button variant="default" onClick={handleBack}>
Geri
{translate('::App.SqlQueryManager.Back')}
</Button>
)}
{step < 3 ? (
<Button variant="solid" color="blue-600" onClick={handleNext} disabled={!canGoNext()}>
İleri
{translate('::App.SqlQueryManager.Next')}
</Button>
) : (
<Button
@ -1493,7 +1494,7 @@ const SqlTableDesignerDialog = ({
loading={isDeploying}
disabled={!dataSource || isDeploying || (isEditMode && generatedSql.includes('Henüz değişiklik yapılmadı'))}
>
Deploy Et
{translate('::App.SqlQueryManager.Deploy')}
</Button>
)}
</div>

View file

@ -258,8 +258,8 @@ const useToolbar = ({
widget: 'dxButton',
name: action.hint,
options: {
hint: action.hint,
text: action.text,
hint: translate('::' + action.hint),
text: translate('::' + action.text),
icon: action.icon,
visible: true,
onClick(e: any) {