Mcp üzerinden hazırlanan listelerin Default Value değeri

TRY, true/false, 60, Adet
This commit is contained in:
Sedat ÖZTÜRK 2026-10-07 22:34:49 +03:00
parent ce5d7764d1
commit 3af82ecf94
14 changed files with 269 additions and 38 deletions

View file

@ -1647,6 +1647,33 @@ numarası için `Sequence` (`CustomValueType: 5`, §9.9) kullan.
> `QueryHelper.GetFormattedValue` tarafından sessizce yanlış biçimlenir — kolon tipiyle aynı
> `DbType` numarasını yaz (§3).
#### 4.3.5.1 Wizard / MCP ekranında yeni kayıt varsayılanı — zorunlu
Wizard ve MCP ile üretilen **her** liste ekranında yeni kayıt şu değerlerle açılır:
| Kolon | Form varsayılanı | Tablodaki `DEFAULT` |
| --- | --- | --- |
| `IsActive` | `true` | `bit NOT NULL DEFAULT 1` |
| Ölçü birimi (`UomId`, `*UomId`; lookup `Adm_T_Uom`) | `Adet` | `DEFAULT 'Adet'` |
| Para birimi (`CurrencyId`, `*Currency`; lookup `Sas_H_Currency`) | `TRY` (lookup'ın anahtarı adsa onun karşılığı) | `DEFAULT 'TRY'` |
| Talepte sabit varsayılanı olan her kolon (ör. Süre = 60) | o değer | `DEFAULT 60` |
**Değer koda yazılmaz, tablodan okunur.** Deploy (`ListFormWizardAppService`) her alan için kolonun
sabit `DEFAULT`'unu veritabanı katalogundan, tablo henüz kurulmadıysa seed scriptinden
(`PostgreSqlTableScript.ReadSeedColumns` → `SqlSeedColumn.ConstantValue`) okur ve
`FormFieldsDefaultValueJson`'a `CustomValueType: 1` (Value) olarak yazar; `bit` kolonda `1/0` →
`true/false`. Fonksiyon varsayılanı (`NEWID()`, `GETUTCDATE()`) form değeri sayılmaz. Bu yüzden
yukarıdaki kolonlar tabloda bu `DEFAULT`'larla kurulur — MCP'de `create_table` kolonunda
`defaultValue: "1"` / `"'Adet'"` / `"'TRY'"` / `"60"`.
Alana özel değer (tablo `DEFAULT`'undan farklı) wizard öğesinin **`DefaultValue`** cevabıyla verilir
(`Groups[].Items[].DefaultValue`); dosyada `ListForm.FormFieldsDefaultValueDto`'da durur ve okurken
öğeye geri döner. Alan kaydındaki `DefaultValue`/`DefaultValueType` select servisinin hesapladığı
değerdir, saklanmaz: MCP'de `Fields[].DefaultValue` yazılırsa deploy onu öğenin `DefaultValue`'suna
taşır. `CustomKey`, `DbQuery`, `Sequence` gibi diğer türler `ListForm.FormFieldsDefaultValueDto`
katmanıyla yazılır (§0.10). Deploy girdisinde sözleşmede karşılığı olmayan bir anahtar adıyla
reddedilir — sessizce yok sayılmaz.
### 4.3.6 Doğrulama — `ValidationRuleJson`
Alan başına DevExtreme doğrulama kuralları dizisi. Wizard `IsRequired: true` alanlara `required`
@ -3680,7 +3707,7 @@ sorulmadan eklenir:
| --- | --- |
| Tablo | `bit NOT NULL DEFAULT 1` (`create_table`'da iş kolonu olarak, `isNullable: false`, `defaultValue: "1"`) |
| Liste | Görünür kolon, `dxCheckBox` |
| Form | `dxCheckBox`, yeni kayıt `true` ile açılır: `FormFieldsDefaultValueJson`'da `{ "FieldName": "IsActive", "FieldDbType": 3, "Value": "true", "CustomValueType": 1 }` (istemciye `column.defaultValue` olarak iner). `InsertFieldsDefaultValueJson`'a yazılmaz — orası her insert'te değeri ezer, kullanıcı pasif kayıt açamaz |
| Form | `dxCheckBox`, yeni kayıt `true` ile açılır: `FormFieldsDefaultValueJson`'da `{ "FieldName": "IsActive", "FieldDbType": 3, "Value": "true", "CustomValueType": 1 }` (istemciye `column.defaultValue` olarak iner); deploy bu satırı tablonun `DEFAULT 1`'inden kendisi yazar (§4.3.5.1). `InsertFieldsDefaultValueJson`'a yazılmaz — orası her insert'te değeri ezer, kullanıcı pasif kayıt açamaz |
| Widget | Toplam · Aktif · Pasif kartları (§4.6.1 madde 2) |
| Demo veri | Satırlar `IsActive: true` ile yazılır |
| Dil | `App.Listform.ListformField.IsActive` (var olan anahtar) |

View file

@ -1563,7 +1563,7 @@ liste süzgeci ve çağrı kapısı aynı kuralı kullanır.
| `save_sql_object` | View/procedure/function scriptini `sql/object/{Ad}.sql` ve `postgres/object/{Ad}.sql` dosyalarına yazar (`McpSqlObjectWriter`); veritabanında çalıştırılmaz, nesneyi DB Migrate kurar. Gövde diyalektler arasında güvenle çevrilemediği için iki script de istemciden gelir ve aynı nesneyi tanımlamalıdır (`SqlObjectInvalid`); ad scriptten okunur, başlık `CREATE OR ALTER` / `CREATE OR REPLACE`'e çevrilir. Tablo scriptinin üstüne yazmaz. `.Write` + `App.SqlQueryManager` ister. |
| `generate_crud_endpoints` | SQL Query Manager CRUD diyaloğuyla aynı endpoint kümesini (`CrudEndpointSeedFileDto.Generate` — diyaloğun servisi de bunu kullanır) yalnızca `crud/{Entity}.json` dosyasına yazar; kayıtları DB Migrate ekler (`CrudEndpointSeedApplier`). `.Write` + `App.SqlQueryManager.CrudEndpoints` ister. |
| `list_wizards` / `get_wizard` | Wizard File Manager dosyaları; `get_wizard` seed dosyasını diskteki biçimiyle döndürür. |
| `deploy_wizard` | Wizard'ı Wizard ekranıyla aynı yoldan (`IListFormWizardAppService.Create`) deploy eder. Girdi seed dosyası biçimi (`{"Wizard": …, "ListForm": …, "Fields": […]}`) ya da düz cevaplardır; ikisi de `WizardSeedFileDto.FromDeployJson`'dan geçer: Wizard bölümünde yazılan cevap korunur, yazılmayan ekran alanı `ListForm`/`Fields`'tan tamamlanır, iki bölüm de ekrana katman olarak uygulanır (`WizardScreenOverlay`, üç yönlü: bölümdeki değer wizard'ın kendi ürettiğiyle aynıysa cevap kazanır, farklıysa editör ayarıdır ve korunur; kimlik alanları wizard'dan gelir, tanınmayan/hesaplanan anahtar reddedilir). Böylece MCP, ListForm editörünün yapabildiği her ayarı wizard dosyasına yazar ve `replaceFileName` ile güncelleme editör ayarlarını silmez. Dosyaya kullanıcının etkin talebi `DevRequest` olarak yazılır (sunucu doldurur). Wizard ekranı gibi yalnızca seed dosyalarını yazar; ekran DB Migrate ile kurulur ve çıkıştaki `isPending` o zamana kadar `true` kalır (model migrate'i beklemez; `verify_wizard` bekleyen dosyada `install` kontrolünde durur). `replaceFileName` doluysa güncellemedir (dosyalar yeniden yazılır, önceki kayıtları migrate kaldırır). İstek demo veri taşıyorsa (prompt'taki satırlar, ekran görüntüsü) wizard `SeedData: true` ile deploy edilir — ekranın `SeedFilePath`'i `data/{ListFormCode}.json` olur ve `SeedSync*` bayrakları açılır — satırlar aynı çağrıda `seedRows` ile bu dosyaya yazılır (alan adları doğrulanır, `Guid` anahtarı sunucu üretir); migrate ekranı kurduktan sonra satırları ekler (`lowcode.instructions.md` §0.10.1). Widget sorgularındaki her dil anahtarı tanımlı olmalı ya da wizard'ın `Language.Texts` alanında EN + TR verilmeli, yoksa deploy adlarıyla reddeder (`ValidateWidgetLanguageKeysAsync`). `uploadUrl`'süz `dxImageUpload` alanı base64 sakladığı için kolonu sınırlı boyluysa (katalogdaki karakter sınırı) deploy reddedilir; tablo kolonuna bağlı `dxImageViewer` alanı da reddedilir — görsel kolonunun editörü her zaman `dxImageUpload`'dır (`ValidateImageColumnLengths`). `MenuOrder` yok sayılır: yeni ekran kardeşlerinin sonuna, güncelleme mevcut yerine yazılır — lookup kaynağı ekran önce deploy edildiği için onu kullanan ekranın üstünde kalır. |
| `deploy_wizard` | Wizard'ı Wizard ekranıyla aynı yoldan (`IListFormWizardAppService.Create`) deploy eder. Girdi seed dosyası biçimi (`{"Wizard": …, "ListForm": …, "Fields": […]}`) ya da düz cevaplardır; ikisi de `WizardSeedFileDto.FromDeployJson`'dan geçer: Wizard bölümünde yazılan cevap korunur, yazılmayan ekran alanı `ListForm`/`Fields`'tan tamamlanır, iki bölüm de ekrana katman olarak uygulanır (`WizardScreenOverlay`, üç yönlü: bölümdeki değer wizard'ın kendi ürettiğiyle aynıysa cevap kazanır, farklıysa editör ayarıdır ve korunur; kimlik alanları wizard'dan gelir, tanınmayan/hesaplanan anahtar reddedilir). Böylece MCP, ListForm editörünün yapabildiği her ayarı wizard dosyasına yazar ve `replaceFileName` ile güncelleme editör ayarlarını silmez. Yeni kaydın form varsayılanı kolonun tablodaki sabit `DEFAULT`'udur (katalog ya da seed scripti, `SqlSeedColumn.ConstantValue`; IsActive → true, UomId → Adet, para birimi → TRY tablonun `DEFAULT`'larından gelir); alana özel değer öğenin `DefaultValue`'su ile verilir (`lowcode.instructions.md` §4.3.5.1). Girdide sözleşmede olmayan anahtar adıyla reddedilir, sessizce yok sayılmaz. Dosyaya kullanıcının etkin talebi `DevRequest` olarak yazılır (sunucu doldurur). Wizard ekranı gibi yalnızca seed dosyalarını yazar; ekran DB Migrate ile kurulur ve çıkıştaki `isPending` o zamana kadar `true` kalır (model migrate'i beklemez; `verify_wizard` bekleyen dosyada `install` kontrolünde durur). `replaceFileName` doluysa güncellemedir (dosyalar yeniden yazılır, önceki kayıtları migrate kaldırır). İstek demo veri taşıyorsa (prompt'taki satırlar, ekran görüntüsü) wizard `SeedData: true` ile deploy edilir — ekranın `SeedFilePath`'i `data/{ListFormCode}.json` olur ve `SeedSync*` bayrakları açılır — satırlar aynı çağrıda `seedRows` ile bu dosyaya yazılır (alan adları doğrulanır, `Guid` anahtarı sunucu üretir); migrate ekranı kurduktan sonra satırları ekler (`lowcode.instructions.md` §0.10.1). Widget sorgularındaki her dil anahtarı tanımlı olmalı ya da wizard'ın `Language.Texts` alanında EN + TR verilmeli, yoksa deploy adlarıyla reddeder (`ValidateWidgetLanguageKeysAsync`). `uploadUrl`'süz `dxImageUpload` alanı base64 sakladığı için kolonu sınırlı boyluysa (katalogdaki karakter sınırı) deploy reddedilir; tablo kolonuna bağlı `dxImageViewer` alanı da reddedilir — görsel kolonunun editörü her zaman `dxImageUpload`'dır (`ValidateImageColumnLengths`). `MenuOrder` yok sayılır: yeni ekran kardeşlerinin sonuna, güncelleme mevcut yerine yazılır — lookup kaynağı ekran önce deploy edildiği için onu kullanan ekranın üstünde kalır. |
| `delete_wizard` | Wizard Manager'daki silmeyle aynı: `InsertedRecords` + ekranın veri aynası, bağımlı wizard varsa reddedilir. `dropTables: true` ekranın tablosunu (yalnızca tasarımcı/`create_table` ile kurulmuş ve başka yerde kullanılmayan) CRUD endpoint'leri, `sql/object` ve `crud` dosyalarıyla düşürür; model bunu kullanıcı onayı olmadan göndermez (`WizardTableCleaner`, `lowcode.instructions.md` §4.5). |
| `verify_wizard` | Deploy edilmiş ekranı veri yazmadan doğrular: menü kaydı ve URL'si, menünün istediği yetki tanımı (`AbpPermissions`), List yolunda ekran sorgusu (`GetSelectAsync`, tek satır, çağıranın yetkisiyle), Custom yolunda bileşen (etkin, rota = menü URL'si) ve seed kapanışı (`ExportAnalysis` uyarıları; engellemez). İsteğe bağlıdır, migrate sonrasında kullanılır; `App.DevRequests` döngüsünün adımı değildir — döngü `Testing`'de biter, kullanıcı elle test edip `Staging`'e alır (`lowcode.instructions.md` §0.11). |
| `start_dev_request` | Geliştirme talebini Id ya da tam başlıkla üstlenir: yalnızca `Ready to Start` durumundakini `In Progress` durumuna alır, diğerlerini reddeder; talebin metnini döndürür. Açıklamaya yapıştırılmış base64 görseller (`data:image/png|jpeg|gif|webp`) metinden ayıklanır (`McpDevRequestImages`), yerlerinde `[image-N]` kalır ve her biri ayrı MCP resim içeriği (`ImageContentBlock`) olarak döner — model görseli resim olarak görür, görsel hiçbir yere yüklenmez. Sonuç istemcinin 1 MB sınırına sığdırılır: büyük görseller küçültülüp JPEG'e çevrilir (`IMcpImageShrinker`), sığmayan gönderilmez ve metinde bildirilir. `.Write` + `App.DevRequests.Update` ister. |

View file

@ -42,7 +42,7 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService, IMc
public async Task<McpCreateTableResultDto> CreateTableAsync(
[Description("Tablo adi; harf/rakam/alt cizgi. Adlandirma icin get_dev_guide'daki tablo onek kuralina uy (ornegin Adm_T_...).")]
string tableName,
[Description("Is kolonlari. type: nvarchar, nvarchar(MAX), int, bigint, decimal (her zaman 18,4 yazilir; boyut verme), float, bit, datetime, datetime2, date, uniqueidentifier, money. maxLength yalnizca nvarchar icin (varsayilan 100). defaultValue: sayi, 'metin' ya da NEWID()/GETDATE()/GETUTCDATE()/SYSUTCDATETIME().")]
[Description("Is kolonlari. type: nvarchar, nvarchar(MAX), int, bigint, decimal (her zaman 18,4 yazilir; boyut verme), float, bit, datetime, datetime2, date, uniqueidentifier, money. maxLength yalnizca nvarchar icin (varsayilan 100). defaultValue: sayi, 'metin' ya da NEWID()/GETDATE()/GETUTCDATE()/SYSUTCDATETIME(). Sabit defaultValue ekranda yeni kaydin form degeri olur (deploy tablodan okur); bu yuzden IsActive bit isNullable false defaultValue \"1\", olcu birimi (UomId) defaultValue \"'Adet'\", para birimi (CurrencyId) defaultValue \"'TRY'\" ve talepteki her sabit varsayilan (Sure = 60 → \"60\") kolona yazilir (get_dev_guide 4.3.5.1).")]
List<McpTableColumnDto> columns,
[Description("Tam audit kolonlari eklensin mi. Kullanici acikca istemedikce true birak.")]
bool fullAudited = true,
@ -97,7 +97,7 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService, IMc
=> await developAppService.GetWizardAsync(fileName);
[McpServerTool(Name = McpToolNames.DeployWizard, Destructive = true, Idempotent = false)]
[Description("Wizard'i deploy eder: ListForm ekrani (ComponentKind 0) ya da bir custom component'i menuye baglayan kayit (ComponentKind 1), yetkileri, dil anahtarlari ve menusu seed dosyalarina yazilir. Deploy veritabanina yazmaz: ekran, menu ve yetkiler kullanici Wizard Manager'da DB Migrate calistirinca olusur; cikistaki isPending true iken ekran henuz yoktur; migrate'i bekleme, isini bitir ve kullaniciya yalnizca DB Migrate calistirmasini soyle. Eksik modul, ust menu, izin grubu, yetki ve dil satirlari da deploy'da dosyalara yazilir ve migrate onlari dogru sirayla ekler; bunlarin veritabaninda olmamasi beklenen durumdur, uyari olarak raporlama ve kullanicidan elle eklemesini isteme. Ust menu zinciri istenen derinlikte kurulur: MenuParentCode ekranin dogrudan ust menusu, Menu.MenuParentPath onun ustundeki seviyeler (kokten asagi, her biri {Code, Icon, En, Tr}); eksik her seviye bir ustunun altina kurulur, var olana baglanilir. Liste ekraninda Grid, Card, Pivot ve Chart gorunumleri varsayilan aciktir (DefaultLayout grid); kullanici bir gorunumu istemedigini soylemedikce bu bayraklari false yazma. Hedef tablo onceden var olmalidir; yoksa once create_table ile olustur. Istek ornek/demo veri tasiyorsa (prompt'taki tablo/liste ya da ekran goruntusunde gorunen satirlar) SeedData true yaz ve satirlarin hepsini ayni cagrida seedRows ile gonder: satirlar ekranin data/{ListFormCode}.json dosyasina yazilir, migrate ekrani kurduktan sonra ekler. Satirlar icin migrate'i bekleyip insert_row kullanma. replaceFileName verilirse o wizard'in dosyalari yeniden yazilir, onceki kayitlarin yerini migrate'te yenileri alir. Wizard cevaplarinin uretmedigi ekran ayarlari (FormFieldsDefaultValueDto/InsertFieldsDefaultValueDto gibi varsayilan degerler, ValidationRuleDto, Format, Alignment, Width, Visible, BandName, ozet/gruplama, ExtraFilter, Insert/Update/Delete komutlari, PageSize, CommandColumnDto …) ayni JSON'un ListForm ve Fields bolumlerine get_wizard ciktisindaki adlarla yazilir; bolumler kismi olabilir (yalnizca degisen anahtarlar), Fields ogeleri FieldName ile eslesir, *Json adlari (FormFieldsDefaultValueJson) *Dto karsiligina cevrilir. Guncellemede get_wizard ciktisini butunuyle degistirip gonder: tasarimci ayarlari korunur; Wizard bolumunde yazdigin cevap ayni ayarin ListForm'daki eski degerine ustun gelir. Kimlik alanlari (ListFormCode, Name, Title, Description, PermissionDto, FieldName) wizard'dan gelir. Fields'taki her alan Wizard Groups'ta da bulunmalidir; tanınmayan ya da hesaplanan bir anahtar reddedilir. Liste ekraninda DescTr ve DescEn ayrintili olmali (en az 3 satir, 150 karakter): ekran basligindaki bilgi simgesinde gosterilir; ne ise yaradigi, menude nerede ya da hangi ekranin sekmesi oldugu, ana alanlar, otomatik hesaplar ve iliskili ekranlar yazilir (get_dev_guide 4.4.2); kisa aciklama reddedilir. Deploy modulun dokumanini (docs/modules) acar ya da envanterini yeniler; elle yazilan bolumleri save_module_doc ile doldur. Ne yazacagini get_dev_guide 4. bolumunden ogren.")]
[Description("Wizard'i deploy eder: ListForm ekrani (ComponentKind 0) ya da bir custom component'i menuye baglayan kayit (ComponentKind 1), yetkileri, dil anahtarlari ve menusu seed dosyalarina yazilir. Deploy veritabanina yazmaz: ekran, menu ve yetkiler kullanici Wizard Manager'da DB Migrate calistirinca olusur; cikistaki isPending true iken ekran henuz yoktur; migrate'i bekleme, isini bitir ve kullaniciya yalnizca DB Migrate calistirmasini soyle. Eksik modul, ust menu, izin grubu, yetki ve dil satirlari da deploy'da dosyalara yazilir ve migrate onlari dogru sirayla ekler; bunlarin veritabaninda olmamasi beklenen durumdur, uyari olarak raporlama ve kullanicidan elle eklemesini isteme. Ust menu zinciri istenen derinlikte kurulur: MenuParentCode ekranin dogrudan ust menusu, Menu.MenuParentPath onun ustundeki seviyeler (kokten asagi, her biri {Code, Icon, En, Tr}); eksik her seviye bir ustunun altina kurulur, var olana baglanilir. Liste ekraninda Grid, Card, Pivot ve Chart gorunumleri varsayilan aciktir (DefaultLayout grid); kullanici bir gorunumu istemedigini soylemedikce bu bayraklari false yazma. Hedef tablo onceden var olmalidir; yoksa once create_table ile olustur. Istek ornek/demo veri tasiyorsa (prompt'taki tablo/liste ya da ekran goruntusunde gorunen satirlar) SeedData true yaz ve satirlarin hepsini ayni cagrida seedRows ile gonder: satirlar ekranin data/{ListFormCode}.json dosyasina yazilir, migrate ekrani kurduktan sonra ekler. Satirlar icin migrate'i bekleyip insert_row kullanma. replaceFileName verilirse o wizard'in dosyalari yeniden yazilir, onceki kayitlarin yerini migrate'te yenileri alir. Wizard cevaplarinin uretmedigi ekran ayarlari (FormFieldsDefaultValueDto/InsertFieldsDefaultValueDto gibi varsayilan degerler, ValidationRuleDto, Format, Alignment, Width, Visible, BandName, ozet/gruplama, ExtraFilter, Insert/Update/Delete komutlari, PageSize, CommandColumnDto …) ayni JSON'un ListForm ve Fields bolumlerine get_wizard ciktisindaki adlarla yazilir. Yeni kaydin form degeri (Aktif = true, Birim = Adet, Kur = TRY, Sure = 60) ayri yazilmaz: deploy kolonun tablodaki sabit DEFAULT degerini okur; tablodan farkli deger gerekiyorsa alan ogesinde DefaultValue yaz (Groups[].Items[].DefaultValue). Wizard girdisinde taninmayan anahtar adiyla reddedilir, baska adla tekrar deneme; bolumler kismi olabilir (yalnizca degisen anahtarlar), Fields ogeleri FieldName ile eslesir, *Json adlari (FormFieldsDefaultValueJson) *Dto karsiligina cevrilir. Guncellemede get_wizard ciktisini butunuyle degistirip gonder: tasarimci ayarlari korunur; Wizard bolumunde yazdigin cevap ayni ayarin ListForm'daki eski degerine ustun gelir. Kimlik alanlari (ListFormCode, Name, Title, Description, PermissionDto, FieldName) wizard'dan gelir. Fields'taki her alan Wizard Groups'ta da bulunmalidir; tanınmayan ya da hesaplanan bir anahtar reddedilir. Liste ekraninda DescTr ve DescEn ayrintili olmali (en az 3 satir, 150 karakter): ekran basligindaki bilgi simgesinde gosterilir; ne ise yaradigi, menude nerede ya da hangi ekranin sekmesi oldugu, ana alanlar, otomatik hesaplar ve iliskili ekranlar yazilir (get_dev_guide 4.4.2); kisa aciklama reddedilir. Deploy modulun dokumanini (docs/modules) acar ya da envanterini yeniler; elle yazilan bolumleri save_module_doc ile doldur. Ne yazacagini get_dev_guide 4. bolumunden ogren.")]
public async Task<WizardFileInfoDto?> DeployWizardAsync(
[Description("Wizard JSON'u: seed dosyasi bicimi ({\"Wizard\": {...}, \"ListForm\": {...}, \"Fields\": [...]}, get_wizard cikisi gibi) ya da duz wizard cevaplari. ListForm/Fields istege baglidir ve kismi olabilir. Enum alanlari sayi olarak yazilir.")]
string wizard,

View file

@ -54,6 +54,13 @@ public class ListFormWizardDto
[JsonIgnore]
public WizardScreenOverlay ScreenOverlay { get; set; }
/// <summary>
/// Deploy girdisinde sozlesmede karsiligi olmayan anahtarlar; doluysa deploy adlariyla reddeder.
/// Yalnizca sunucu ici girdidir (<see cref="WizardSeedFileDto.FromDeployJson"/>).
/// </summary>
[JsonIgnore]
public List<string> UnknownKeys { get; set; } = [];
/// <summary>
/// Wizard'in ilk deploy edildigi an. Dosya adi tarih tasimadigi icin seeder dosyalari bu
/// damgaya gore siralar; birbirine bagli wizard'lar (once Customers, sonra Tasks) uretildikleri
@ -313,6 +320,8 @@ public class ListFormWizardDto
dto.InsertFieldsDefaultValueJson = isCreatedField
? WizardConsts.DefaultInsertFieldsDefaultValueJson(KeyFieldDbSourceType)
: WizardConsts.DefaultInsertFieldsJsonOnlyId(KeyFieldDbSourceType);
var formDefaults = BuildFormDefaults(groups);
dto.FormFieldsDefaultValueJson = formDefaults.Count > 0 ? JsonSerializer.Serialize(formDefaults) : null;
dto.EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null;
dto.SubFormsJson = subForms.Count > 0 ? JsonSerializer.Serialize(subForms) : null;
dto.WidgetsJson = widgets.Count > 0 ? JsonSerializer.Serialize(widgets) : null;
@ -339,6 +348,25 @@ public class ListFormWizardDto
return dto;
}
/// <summary>
/// Yeni kaydin form acilisindaki degerleri (<see cref="WizardColumnItemInputDto.DefaultValue"/>); alan
/// basina tek satir, sabit deger olarak yazilir (lowcode §4.3.5).
/// </summary>
private static List<FieldsDefaultValueDto> BuildFormDefaults(List<WizardColumnGroupInputDto> groups) =>
[
.. groups
.SelectMany(g => g.Items ?? [])
.Where(i => !string.IsNullOrWhiteSpace(i.FieldName) && !string.IsNullOrWhiteSpace(i.DefaultValue))
.DistinctBy(i => i.FieldName, StringComparer.OrdinalIgnoreCase)
.Select(i => new FieldsDefaultValueDto
{
FieldName = i.FieldName,
FieldDbType = i.DbSourceType,
Value = i.DefaultValue.Trim(),
CustomValueType = FieldCustomValueTypeEnum.Value
})
];
/// <summary>
/// Wizard gruplarindaki her alani ListFormField sozlesmesine cevirir. Alan sirasi gruplarin
/// sirasini izler; anahtar alan listede gizlenir ve duzenleme formuna alinmaz.
@ -461,6 +489,10 @@ public class ListFormWizardDto
private List<WizardColumnGroupInputDto> BuildGroups(GridOptionsEditDto listForm, IReadOnlyList<ColumnFormatEditDto> fields)
{
var editingForm = listForm.EditingFormDto ?? [];
var formDefaults = (listForm.FormFieldsDefaultValueDto ?? [])
.Where(d => d.CustomValueType == FieldCustomValueTypeEnum.Value && !string.IsNullOrWhiteSpace(d.FieldName))
.GroupBy(d => d.FieldName, StringComparer.OrdinalIgnoreCase)
.ToDictionary(g => g.Key, g => g.First().Value, StringComparer.OrdinalIgnoreCase);
var captions = (Groups ?? [])
.SelectMany(g => g.Items ?? [])
.Where(i => !string.IsNullOrWhiteSpace(i.FieldName))
@ -509,6 +541,7 @@ public class ListFormWizardDto
CascadeRelationField = lookup.CascadeRelationField,
CascadeFilterOperator = string.IsNullOrWhiteSpace(lookup.CascadeParentFields) ? null : lookup.CascadeFilterOperator,
CascadeEmptyFields = lookup.CascadeEmptyFields,
DefaultValue = formDefaults.GetValueOrDefault(field.FieldName ?? string.Empty),
EnglishCaption = previous?.EnglishCaption,
TurkishCaption = previous?.TurkishCaption,
});

View file

@ -21,6 +21,13 @@ public class WizardColumnItemInputDto
public string DisplayExpr { get; set; }
public string LookupQuery { get; set; }
/// <summary>
/// Yeni kayit acilirken alanin dolu gelecegi deger (<c>FormFieldsDefaultValueJson</c>, sabit deger).
/// Lookup alaninda lookup'in anahtaridir. Bos ise deploy kolonun veritabanindaki sabit DEFAULT degerini
/// yazar (IsActive DEFAULT 1 → true); deger koda degil tabloyu tanimlayan scripte aittir.
/// </summary>
public string DefaultValue { get; set; }
/// <summary>Cocuk alanda: degeri lookup sorgusuna <c>@param0…</c> olarak giden ebeveyn alan(lar), virgulle.</summary>
public string CascadeParentFields { get; set; }

View file

@ -111,7 +111,7 @@ public class WizardSeedFileDto
nameof(WizardColumnItemInputDto.ValueExpr), nameof(WizardColumnItemInputDto.DisplayExpr),
nameof(WizardColumnItemInputDto.LookupQuery), nameof(WizardColumnItemInputDto.CascadeParentFields),
nameof(WizardColumnItemInputDto.CascadeRelationField), nameof(WizardColumnItemInputDto.CascadeFilterOperator),
nameof(WizardColumnItemInputDto.CascadeEmptyFields),
nameof(WizardColumnItemInputDto.CascadeEmptyFields), nameof(WizardColumnItemInputDto.DefaultValue),
];
/// <summary>Dosyada `Menu` basligi altinda toplanan wizard alanlari; adlari degismez.</summary>
@ -308,6 +308,17 @@ public class WizardSeedFileDto
if (JsonNode.Parse(json) is not JsonObject root)
return null;
// get_wizard cevabi ({ fileName, seed }) oldugu gibi geri gonderilebilir.
if (FindKey(root, "Seed") is { } seedKey && root[seedKey] is JsonObject seed)
root = (JsonObject)seed.DeepClone();
// Bolum adlari dosyadaki gibi yazilir; istemcinin harf buyuklugu farki bolumu dusurmesin.
foreach (var section in new[] { nameof(Wizard), nameof(ListForm), nameof(Fields) })
{
if (FindKey(root, section) is { } key && key != section)
Rename(root, key, section);
}
if (!root.ContainsKey(nameof(Wizard)))
root = new JsonObject { [nameof(Wizard)] = root };
@ -319,6 +330,8 @@ public class WizardSeedFileDto
if (wizard == null)
return null;
wizard.UnknownKeys = UnknownKeys(root, wizardNode);
var listForm = root[nameof(ListForm)] as JsonObject;
var fields = root[nameof(Fields)] as JsonArray;
if (listForm == null && fields == null)
@ -339,6 +352,8 @@ public class WizardSeedFileDto
if (fields != null)
FillMissingGroups(wizard, sections, wizardNode);
MoveFieldDefaultValues(wizard, fields);
wizard.ScreenOverlay = new WizardScreenOverlay
{
ListForm = listForm,
@ -349,6 +364,61 @@ public class WizardSeedFileDto
return wizard;
}
/// <summary>
/// Alan kaydindaki <c>DefaultValue</c>/<c>DefaultValueType</c> select servisinin hesapladigi degerdir,
/// saklanmaz; form varsayilani <c>FormFieldsDefaultValueJson</c>'dadir. Fields'ta yazilan deger ayni
/// alanin wizard ogesine (<see cref="WizardColumnItemInputDto.DefaultValue"/>) tasinir ve oradaki degerin yerine gecer.
/// </summary>
private static void MoveFieldDefaultValues(ListFormWizardDto wizard, JsonArray fields)
{
var items = wizard.Groups.SelectMany(g => g.Items).ToList();
foreach (var field in (fields ?? []).OfType<JsonObject>())
{
field.Remove(FindKey(field, nameof(ColumnFormatEditDto.DefaultValueType)) ?? string.Empty);
if (FindKey(field, nameof(ColumnFormatEditDto.DefaultValue)) is not { } key || !field.Remove(key, out var value) || value is null)
continue;
var fieldName = field[FindKey(field, nameof(ColumnFormatEditDto.FieldName)) ?? string.Empty]?.ToString();
var item = items.FirstOrDefault(i => string.Equals(i.FieldName, fieldName, StringComparison.OrdinalIgnoreCase));
if (item != null)
item.DefaultValue = value is JsonValue text && text.TryGetValue<string>(out var s) ? s : value.ToJsonString();
}
}
/// <summary>
/// Sozlesmede karsiligi olmayan anahtarlar (<c>Wizard.X</c>, <c>Groups[0].Items[2].X</c>). Okuyucu
/// bunlari sessizce atar; model yazdigi degerin gittigini sanip baska adla tekrar denerdi.
/// </summary>
private static List<string> UnknownKeys(JsonObject root, JsonObject wizardNode)
{
static HashSet<string> Names(Type type) =>
[.. type.GetProperties().Select(p => p.Name)];
var unknown = new List<string>();
void Collect(JsonObject node, HashSet<string> known, string path)
{
unknown.AddRange(node.Select(x => x.Key)
.Where(key => !known.Contains(key, StringComparer.OrdinalIgnoreCase))
.Select(key => $"{path}.{key}"));
}
Collect(root, Names(typeof(WizardSeedFileDto)), "root");
Collect(wizardNode, Names(typeof(ListFormWizardDto)), nameof(Wizard));
var groupNames = Names(typeof(WizardColumnGroupInputDto));
var itemNames = Names(typeof(WizardColumnItemInputDto));
var groups = (wizardNode[nameof(ListFormWizardDto.Groups)] as JsonArray ?? []).OfType<JsonObject>().ToList();
for (var gi = 0; gi < groups.Count; gi++)
{
Collect(groups[gi], groupNames, $"Groups[{gi}]");
var items = (groups[gi][nameof(WizardColumnGroupInputDto.Items)] as JsonArray ?? []).OfType<JsonObject>().ToList();
for (var ii = 0; ii < items.Count; ii++)
Collect(items[ii], itemNames, $"Groups[{gi}].Items[{ii}]({items[ii][nameof(WizardColumnItemInputDto.FieldName)]})");
}
return unknown;
}
/// <summary>Bolumde yazilmamis wizard alanlarini <paramref name="source"/>'tan kopyalar.</summary>
private static void FillMissing<T>(T target, T source, JsonObject written, IEnumerable<string> keys)
{
@ -396,8 +466,10 @@ public class WizardSeedFileDto
}
}
private static bool ContainsKey(JsonObject node, string key) =>
node.Any(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase));
private static bool ContainsKey(JsonObject node, string key) => FindKey(node, key) != null;
private static string FindKey(JsonObject node, string key) =>
node.FirstOrDefault(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase)).Key;
/// <summary>`Menu`/`Language` basliklarini duzlestirir ve dosyadaki adlari sozlesme adlarina cevirir.</summary>
private static void FlattenWizard(JsonObject wizardNode)

View file

@ -108,6 +108,16 @@ public class ListFormWizardAppService(
var previous = isEdit ? await GetFile(editFileName!) : null;
// Okuyucu bilmedigi anahtari atar; reddedilmezse model degerin yazildigini sanip baska adla
// tekrar dener.
if (input.UnknownKeys.Count > 0)
{
throw new UserFriendlyException(
$"Wizard girdisinde tanınmayan alanlar var: {string.Join(", ", input.UnknownKeys)}. " +
"Yeni kayıt varsayılanı için alan öğesindeki DefaultValue, wizard cevabında olmayan ekran ayarları için " +
"ListForm/Fields bölümü (get_wizard çıktısındaki adlarla) kullanılır.");
}
var wizardName = input.WizardName?.Trim();
if (string.IsNullOrWhiteSpace(wizardName))
throw new UserFriendlyException("Wizard adı zorunludur.");
@ -314,6 +324,14 @@ public class ListFormWizardAppService(
? await IsQueryMainTableSoftDeletedAsync(input)
: tableColumns.ContainsKey("IsDeleted");
isCreated = tableColumns.ContainsKey("CreatorId");
// Yeni kaydin form degeri, cevapta yazilmadiysa kolonun sabit DEFAULT'udur (IsActive DEFAULT 1 →
// true, UomId DEFAULT 'Adet'); deger koda degil tabloyu tanimlayan scripte aittir.
foreach (var item in input.Groups.SelectMany(g => g.Items).Where(i => string.IsNullOrWhiteSpace(i.DefaultValue)))
{
if (tableColumns.TryGetValue(item.FieldName ?? string.Empty, out var column))
item.DefaultValue = column.ConstantValue();
}
foreach (var item in input.Groups.SelectMany(g => g.Items))
item.CaptionName = await ResolveLanguageKeyCasingAsync(rows, item.CaptionName);
listFormDto = input.BuildListForm(isDeleted, isCreated);
@ -2982,7 +3000,7 @@ public class ListFormWizardAppService(
/// kolona yazar; boyu sinirli bir kolon kayitta sessizce kesilir ya da hata verir. Sinir
/// katalogdan okunur: sinirsiz kolon (SQL Server MAX = -1, PostgreSQL text = bos) kabul edilir.
/// </summary>
private static void ValidateImageColumnLengths(ListFormWizardDto input, Dictionary<string, int?> tableColumns)
private static void ValidateImageColumnLengths(ListFormWizardDto input, Dictionary<string, SqlSeedColumn> tableColumns)
{
// Kolona bagli gorsel alani yuklenebilir olmali: goruntuleyici ile kurulan alan kayitta
// bos kalir ya da kopyalanan degeri degistirilemez hale getirir.
@ -3004,8 +3022,8 @@ public class ListFormWizardAppService(
.SelectMany(g => g.Items)
.Where(i => string.Equals(i.EditorType, ImageUploadEditorType, StringComparison.OrdinalIgnoreCase) &&
!HasUploadUrl(i.EditorOptions) &&
tableColumns.TryGetValue(i.FieldName ?? string.Empty, out var length) && length > 0)
.Select(i => $"{i.FieldName} ({tableColumns[i.FieldName]})")
tableColumns.TryGetValue(i.FieldName ?? string.Empty, out var column) && column.Length > 0)
.Select(i => $"{i.FieldName} ({tableColumns[i.FieldName].Length})")
.ToList();
if (limited.Count > 0)
@ -3124,7 +3142,7 @@ public class ListFormWizardAppService(
}
/// <summary>Tablonun kolonlari ve metin kolonlarinin karakter siniri (sinirsizsa -1 ya da bos).</summary>
private async Task<Dictionary<string, int?>> GetTableColumnsAsync(string dataSourceCode, SelectCommandTypeEnum commandType, string selectCommand)
private async Task<Dictionary<string, SqlSeedColumn>> GetTableColumnsAsync(string dataSourceCode, SelectCommandTypeEnum commandType, string selectCommand)
{
if (commandType == SelectCommandTypeEnum.Query || commandType == SelectCommandTypeEnum.StoredProcedure)
return [];
@ -3142,8 +3160,8 @@ public class ListFormWizardAppService(
// Şema/tablo adları kullanıcıdan geldiği için sorguya parametre olarak bağlanır.
var query = dbType == DataSourceTypeEnum.Postgresql
? "SELECT column_name, character_maximum_length FROM information_schema.columns WHERE table_schema = @schemaName AND table_name = @tableName"
: "SELECT COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schemaName AND TABLE_NAME = @tableName";
? "SELECT column_name, character_maximum_length, column_default, data_type FROM information_schema.columns WHERE table_schema = @schemaName AND table_name = @tableName"
: "SELECT COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH, COLUMN_DEFAULT, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schemaName AND TABLE_NAME = @tableName";
var parameters = new Dictionary<string, object>
{
@ -3153,7 +3171,7 @@ public class ListFormWizardAppService(
var rows = await repo.QueryAsync(query, connectionString, parameters);
var columns = new Dictionary<string, int?>(StringComparer.OrdinalIgnoreCase);
var columns = new Dictionary<string, SqlSeedColumn>(StringComparer.OrdinalIgnoreCase);
foreach (var row in rows)
{
if (row is not IDictionary<string, object> dict)
@ -3161,11 +3179,18 @@ public class ListFormWizardAppService(
var nameKey = dict.ContainsKey("COLUMN_NAME") ? "COLUMN_NAME" : "column_name";
var lengthKey = dict.ContainsKey("CHARACTER_MAXIMUM_LENGTH") ? "CHARACTER_MAXIMUM_LENGTH" : "character_maximum_length";
var defaultKey = dict.ContainsKey("COLUMN_DEFAULT") ? "COLUMN_DEFAULT" : "column_default";
var typeKey = dict.ContainsKey("DATA_TYPE") ? "DATA_TYPE" : "data_type";
if (dict.TryGetValue(nameKey, out var col) && col != null)
{
columns[col.ToString()!] = dict.TryGetValue(lengthKey, out var length) && length is not null and not DBNull
? Convert.ToInt32(length, System.Globalization.CultureInfo.InvariantCulture)
: null;
columns[col.ToString()!] = new SqlSeedColumn(
dict.TryGetValue(lengthKey, out var length) && length is not null and not DBNull
? Convert.ToInt32(length, System.Globalization.CultureInfo.InvariantCulture)
: null,
dict.TryGetValue(defaultKey, out var columnDefault) && columnDefault is not null and not DBNull
? columnDefault.ToString()
: null,
dict.TryGetValue(typeKey, out var dataType) ? dataType?.ToString() : null);
}
}
// MCP create_table tabloyu yalnizca seed scripti olarak yazar; DB Migrate kurana kadar

View file

@ -51,12 +51,13 @@ public static partial class PostgreSqlTableScript
/// <summary>
/// Henüz DB Migrate'te kurulmamış tablonun kolonlarını SQL Server seed scriptinden
/// (<c>sql/object/{Tablo}.sql</c>) okur: ad ve metin kolonunun karakter sınırı (<c>MAX</c> için -1,
/// <c>INFORMATION_SCHEMA</c> ile aynı). Dosya yoksa ya da <c>CREATE TABLE</c> tanınmazsa boş döner.
/// (<c>sql/object/{Tablo}.sql</c>) okur: ad, metin kolonunun karakter sınırı (<c>MAX</c> için -1,
/// <c>INFORMATION_SCHEMA</c> ile aynı), veri tipi ve <c>DEFAULT</c> ifadesi. Dosya yoksa ya da <c>CREATE TABLE</c>
/// tanınmazsa boş döner.
/// </summary>
public static Dictionary<string, int?> ReadSeedColumns(IConfiguration? configuration, string tableName)
public static Dictionary<string, SqlSeedColumn> ReadSeedColumns(IConfiguration? configuration, string tableName)
{
var columns = new Dictionary<string, int?>(StringComparer.OrdinalIgnoreCase);
var columns = new Dictionary<string, SqlSeedColumn>(StringComparer.OrdinalIgnoreCase);
var path = Path.Combine(
SeedPathResolver.GetPath(configuration, SeedPathResolver.SqlFolder, SeedPathResolver.ObjectFolder),
$"{tableName}.sql");
@ -82,13 +83,18 @@ public static partial class PostgreSqlTableScript
continue;
var size = match.Groups["size"].Value.Trim();
columns[match.Groups["name"].Value] = size.Length == 0
var maxLength = size.Length == 0
? null
: size.Equals("MAX", StringComparison.OrdinalIgnoreCase)
? -1
: int.TryParse(size, out var length) && match.Groups["type"].Value.Contains("char", StringComparison.OrdinalIgnoreCase)
? length
: null;
: (int?)null;
columns[match.Groups["name"].Value] = new SqlSeedColumn(
maxLength,
match.Groups["default"].Success ? match.Groups["default"].Value.Trim() : null,
match.Groups["type"].Value);
}
return columns;
@ -100,7 +106,7 @@ public static partial class PostgreSqlTableScript
[GeneratedRegex(@"^\s*(CONSTRAINT\b|\))", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)]
private static partial Regex SeedColumnEndRegex();
[GeneratedRegex(@"^\s*\[(?<name>[^\]]+)\]\s+\[?(?<type>[A-Za-z0-9]+)\]?\s*(?:\(\s*(?<size>[^)]*)\))?", RegexOptions.CultureInvariant)]
[GeneratedRegex(@"^\s*\[(?<name>[^\]]+)\]\s+\[?(?<type>[A-Za-z0-9]+)\]?\s*(?:\(\s*(?<size>[^)]*)\))?(?:.*?\bDEFAULT\s+(?<default>.+?)\s*,?\s*$)?", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)]
private static partial Regex SeedColumnLineRegex();
public static bool TryConvert(string sqlServerScript, out string postgreSqlScript)

View file

@ -0,0 +1,56 @@
using System;
using System.Globalization;
using System.Text.RegularExpressions;
namespace Sozsoft.Platform.Data.Seeds;
/// <summary>
/// Tablonun bir kolonu: veri tipi, metin kolonunun karakter siniri (<c>MAX</c> icin -1) ve <c>DEFAULT</c> ifadesi.
/// Kaynak veritabani katalogu (<c>INFORMATION_SCHEMA.COLUMNS</c>) ya da henuz kurulmamis tablonun seed
/// scriptidir (<see cref="PostgreSqlTableScript.ReadSeedColumns"/>).
/// </summary>
public sealed partial record SqlSeedColumn(int? Length, string? Default, string? DataType)
{
/// <summary>
/// <c>DEFAULT</c> sabit bir degerse (sayi, metin, mantiksal) formda kullanilacak karsiligi; fonksiyon
/// (<c>NEWID()</c>, <c>GETUTCDATE()</c>, <c>now()</c>) ya da ifade ise null. Iki saglayicinin katalog
/// bicimi de cozulur: SQL Server <c>((1))</c>, <c>(N'Adet')</c>; PostgreSQL <c>'TRY'::character varying</c>,
/// <c>true</c>. Mantiksal kolonda (<c>bit</c>/<c>boolean</c>) 1/0 <c>true</c>/<c>false</c> olur.
/// </summary>
public string? ConstantValue()
{
var isBoolean = DataType is not null &&
(DataType.Equals("bit", StringComparison.OrdinalIgnoreCase) || DataType.Equals("boolean", StringComparison.OrdinalIgnoreCase));
var value = Default?.Trim();
if (string.IsNullOrEmpty(value))
return null;
value = PostgreSqlCastRegex().Replace(value, string.Empty).Trim();
while (value.Length > 1 && value[0] == '(' && value[^1] == ')')
value = value[1..^1].Trim();
var text = TextLiteralRegex().Match(value);
if (text.Success)
value = text.Groups["text"].Value.Replace("''", "'");
else if (!decimal.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out _) &&
!bool.TryParse(value, out _))
return null;
if (!isBoolean)
return value;
return value switch
{
"1" => "true",
"0" => "false",
_ => bool.TryParse(value, out var flag) ? (flag ? "true" : "false") : null
};
}
[GeneratedRegex(@"::[\w\s]+(?:\(\d+\))?$")]
private static partial Regex PostgreSqlCastRegex();
[GeneratedRegex(@"^N?'(?<text>(?:[^']|'')*)'$", RegexOptions.IgnoreCase)]
private static partial Regex TextLiteralRegex();
}

View file

@ -214,6 +214,20 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
dallanır.
- SQL değişikliği doğrulanırken PG eşi de bir PostgreSQL veritabanında çalıştırılır (iki kez —
idempotent). Ayrıntı ve dönüşüm tablosu: `lowcode.instructions.md` §8.3.1.
17. **Her prompt sonunda optimizasyon + ölü kod temizliği** → kullanıcı "optimize et, ölü kodları
kaldır" yazmaz; her iş bitmeden, kullanıcı istemese de o işte dokunulan kod üzerinde yapılır:
kullanılmayan `using`/üye/parametre/tip/dil anahtarı silinir (tip silmeden önce repo geneli
tarama, "Definition of done"), aynı mantığın ikinci kopyası ortak metoda indirilir, gereksiz
tekrar sorgu/dosya okuması kaldırılır, kod/değer **statik yazılmaz** — tablo adı
`TableNameResolver`'dan, değer tablo/seed/ayar verisinden dinamik bulunur. Son mesajda ne
temizlendiği tek satırla söylenir.
18. **Yeni kaydın form varsayılanı** → Wizard ve MCP ile üretilen her listede form varsayılanı
kolonun veritabanındaki sabit `DEFAULT` değeridir; deploy onu tablodan (katalog ya da seed
scripti) okuyup `FormFieldsDefaultValueJson`'a yazar, değer koda gömülmez. Bu yüzden tablo
şu `DEFAULT`'larla kurulur: `IsActive` → `1` (true), ölçü birimi (`*UomId`) → `'Adet'`, para birimi
(`*CurrencyId`/`*Currency`) → `'TRY'` (lookup'ın anahtarı neyse); talepte başka sabit varsayılan
varsa (Süre = 60) o da kolonun `DEFAULT`'udur. Alana özel değer wizard öğesinin `DefaultValue`'su ile
verilir. Ayrıntı: `lowcode.instructions.md` §4.3.5.1.
### Cross-cutting: touching one thing means touching these too

View file

@ -69486,20 +69486,6 @@
"Key": "App.Mcp.Error.DevRequestAnalysisRequired",
"Value": "Analiz boş olamaz."
},
{
"Id": "c8039b7b-e33c-5a20-950b-772e6620e568",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Mcp.Error.DevRequestMenuCodeRequired",
"Value": "menuCode is required: pass the menu location of the request, i.e. the code of the branch or screen under the root menu (App.Inventory.Definitions). The analysis is written to that branch's section of the module document."
},
{
"Id": "1c11fb6e-9011-5de0-b7c7-b3d9227c00c7",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Mcp.Error.DevRequestMenuCodeRequired",
"Value": "menuCode zorunludur: talebin menü yerini, yani kök menünün altındaki dalın ya da ekranın kodunu (App.Inventory.Definitions) gönderin. Analiz bu dalın modül dokümanı bölümüne yazılır."
},
{
"Id": "aa72e998-f4a1-5873-95ef-1fcfe0b601f9",
"CultureName": "en",

View file

@ -291,6 +291,7 @@ export interface WizardSeedFileItemDto {
cascadeRelationField?: string
cascadeFilterOperator?: string
cascadeEmptyFields?: string
defaultValue?: string
}
export interface WizardSeedFileGroupDto {

View file

@ -801,6 +801,7 @@ const Wizard = () => {
cascadeRelationField: it.cascadeRelationField,
cascadeFilterOperator: it.cascadeFilterOperator,
cascadeEmptyFields: it.cascadeEmptyFields,
defaultValue: it.defaultValue,
}) as WizardGroupItem,
),
}))
@ -1181,6 +1182,7 @@ const Wizard = () => {
cascadeRelationField: item.cascadeRelationField,
cascadeFilterOperator: item.cascadeFilterOperator,
cascadeEmptyFields: item.cascadeEmptyFields,
defaultValue: item.defaultValue,
}
}),
})),

View file

@ -59,6 +59,8 @@ export interface WizardGroupItem {
cascadeRelationField?: string
cascadeFilterOperator?: string
cascadeEmptyFields?: string
/** Yeni kaydin form degeri; bossa deploy kolonun sabit DEFAULT'unu yazar. Duzenlemede korunur. */
defaultValue?: string
}
export interface WizardGroup {