Mcp üzerinden hazırlanan listelerin Default Value değeri
TRY, true/false, 60, Adet
This commit is contained in:
parent
ce5d7764d1
commit
3af82ecf94
14 changed files with 269 additions and 38 deletions
29
.github/instructions/lowcode.instructions.md
vendored
29
.github/instructions/lowcode.instructions.md
vendored
|
|
@ -1647,6 +1647,33 @@ numarası için `Sequence` (`CustomValueType: 5`, §9.9) kullan.
|
||||||
> `QueryHelper.GetFormattedValue` tarafından sessizce yanlış biçimlenir — kolon tipiyle aynı
|
> `QueryHelper.GetFormattedValue` tarafından sessizce yanlış biçimlenir — kolon tipiyle aynı
|
||||||
> `DbType` numarasını yaz (§3).
|
> `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`
|
### 4.3.6 Doğrulama — `ValidationRuleJson`
|
||||||
|
|
||||||
Alan başına DevExtreme doğrulama kuralları dizisi. Wizard `IsRequired: true` alanlara `required`
|
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"`) |
|
| Tablo | `bit NOT NULL DEFAULT 1` (`create_table`'da iş kolonu olarak, `isNullable: false`, `defaultValue: "1"`) |
|
||||||
| Liste | Görünür kolon, `dxCheckBox` |
|
| 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) |
|
| Widget | Toplam · Aktif · Pasif kartları (§4.6.1 madde 2) |
|
||||||
| Demo veri | Satırlar `IsActive: true` ile yazılır |
|
| Demo veri | Satırlar `IsActive: true` ile yazılır |
|
||||||
| Dil | `App.Listform.ListformField.IsActive` (var olan anahtar) |
|
| Dil | `App.Listform.ListformField.IsActive` (var olan anahtar) |
|
||||||
|
|
|
||||||
|
|
@ -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. |
|
| `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. |
|
| `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. |
|
| `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). |
|
| `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). |
|
| `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. |
|
| `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. |
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService, IMc
|
||||||
public async Task<McpCreateTableResultDto> CreateTableAsync(
|
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_...).")]
|
[Description("Tablo adi; harf/rakam/alt cizgi. Adlandirma icin get_dev_guide'daki tablo onek kuralina uy (ornegin Adm_T_...).")]
|
||||||
string tableName,
|
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,
|
List<McpTableColumnDto> columns,
|
||||||
[Description("Tam audit kolonlari eklensin mi. Kullanici acikca istemedikce true birak.")]
|
[Description("Tam audit kolonlari eklensin mi. Kullanici acikca istemedikce true birak.")]
|
||||||
bool fullAudited = true,
|
bool fullAudited = true,
|
||||||
|
|
@ -97,7 +97,7 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService, IMc
|
||||||
=> await developAppService.GetWizardAsync(fileName);
|
=> await developAppService.GetWizardAsync(fileName);
|
||||||
|
|
||||||
[McpServerTool(Name = McpToolNames.DeployWizard, Destructive = true, Idempotent = false)]
|
[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(
|
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.")]
|
[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,
|
string wizard,
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,13 @@ public class ListFormWizardDto
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public WizardScreenOverlay ScreenOverlay { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Wizard'in ilk deploy edildigi an. Dosya adi tarih tasimadigi icin seeder dosyalari bu
|
/// 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
|
/// damgaya gore siralar; birbirine bagli wizard'lar (once Customers, sonra Tasks) uretildikleri
|
||||||
|
|
@ -313,6 +320,8 @@ public class ListFormWizardDto
|
||||||
dto.InsertFieldsDefaultValueJson = isCreatedField
|
dto.InsertFieldsDefaultValueJson = isCreatedField
|
||||||
? WizardConsts.DefaultInsertFieldsDefaultValueJson(KeyFieldDbSourceType)
|
? WizardConsts.DefaultInsertFieldsDefaultValueJson(KeyFieldDbSourceType)
|
||||||
: WizardConsts.DefaultInsertFieldsJsonOnlyId(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.EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null;
|
||||||
dto.SubFormsJson = subForms.Count > 0 ? JsonSerializer.Serialize(subForms) : null;
|
dto.SubFormsJson = subForms.Count > 0 ? JsonSerializer.Serialize(subForms) : null;
|
||||||
dto.WidgetsJson = widgets.Count > 0 ? JsonSerializer.Serialize(widgets) : null;
|
dto.WidgetsJson = widgets.Count > 0 ? JsonSerializer.Serialize(widgets) : null;
|
||||||
|
|
@ -339,6 +348,25 @@ public class ListFormWizardDto
|
||||||
return dto;
|
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>
|
/// <summary>
|
||||||
/// Wizard gruplarindaki her alani ListFormField sozlesmesine cevirir. Alan sirasi gruplarin
|
/// Wizard gruplarindaki her alani ListFormField sozlesmesine cevirir. Alan sirasi gruplarin
|
||||||
/// sirasini izler; anahtar alan listede gizlenir ve duzenleme formuna alinmaz.
|
/// 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)
|
private List<WizardColumnGroupInputDto> BuildGroups(GridOptionsEditDto listForm, IReadOnlyList<ColumnFormatEditDto> fields)
|
||||||
{
|
{
|
||||||
var editingForm = listForm.EditingFormDto ?? [];
|
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 ?? [])
|
var captions = (Groups ?? [])
|
||||||
.SelectMany(g => g.Items ?? [])
|
.SelectMany(g => g.Items ?? [])
|
||||||
.Where(i => !string.IsNullOrWhiteSpace(i.FieldName))
|
.Where(i => !string.IsNullOrWhiteSpace(i.FieldName))
|
||||||
|
|
@ -509,6 +541,7 @@ public class ListFormWizardDto
|
||||||
CascadeRelationField = lookup.CascadeRelationField,
|
CascadeRelationField = lookup.CascadeRelationField,
|
||||||
CascadeFilterOperator = string.IsNullOrWhiteSpace(lookup.CascadeParentFields) ? null : lookup.CascadeFilterOperator,
|
CascadeFilterOperator = string.IsNullOrWhiteSpace(lookup.CascadeParentFields) ? null : lookup.CascadeFilterOperator,
|
||||||
CascadeEmptyFields = lookup.CascadeEmptyFields,
|
CascadeEmptyFields = lookup.CascadeEmptyFields,
|
||||||
|
DefaultValue = formDefaults.GetValueOrDefault(field.FieldName ?? string.Empty),
|
||||||
EnglishCaption = previous?.EnglishCaption,
|
EnglishCaption = previous?.EnglishCaption,
|
||||||
TurkishCaption = previous?.TurkishCaption,
|
TurkishCaption = previous?.TurkishCaption,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,13 @@ public class WizardColumnItemInputDto
|
||||||
public string DisplayExpr { get; set; }
|
public string DisplayExpr { get; set; }
|
||||||
public string LookupQuery { 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>
|
/// <summary>Cocuk alanda: degeri lookup sorgusuna <c>@param0…</c> olarak giden ebeveyn alan(lar), virgulle.</summary>
|
||||||
public string CascadeParentFields { get; set; }
|
public string CascadeParentFields { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ public class WizardSeedFileDto
|
||||||
nameof(WizardColumnItemInputDto.ValueExpr), nameof(WizardColumnItemInputDto.DisplayExpr),
|
nameof(WizardColumnItemInputDto.ValueExpr), nameof(WizardColumnItemInputDto.DisplayExpr),
|
||||||
nameof(WizardColumnItemInputDto.LookupQuery), nameof(WizardColumnItemInputDto.CascadeParentFields),
|
nameof(WizardColumnItemInputDto.LookupQuery), nameof(WizardColumnItemInputDto.CascadeParentFields),
|
||||||
nameof(WizardColumnItemInputDto.CascadeRelationField), nameof(WizardColumnItemInputDto.CascadeFilterOperator),
|
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>
|
/// <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)
|
if (JsonNode.Parse(json) is not JsonObject root)
|
||||||
return null;
|
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)))
|
if (!root.ContainsKey(nameof(Wizard)))
|
||||||
root = new JsonObject { [nameof(Wizard)] = root };
|
root = new JsonObject { [nameof(Wizard)] = root };
|
||||||
|
|
||||||
|
|
@ -319,6 +330,8 @@ public class WizardSeedFileDto
|
||||||
if (wizard == null)
|
if (wizard == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
wizard.UnknownKeys = UnknownKeys(root, wizardNode);
|
||||||
|
|
||||||
var listForm = root[nameof(ListForm)] as JsonObject;
|
var listForm = root[nameof(ListForm)] as JsonObject;
|
||||||
var fields = root[nameof(Fields)] as JsonArray;
|
var fields = root[nameof(Fields)] as JsonArray;
|
||||||
if (listForm == null && fields == null)
|
if (listForm == null && fields == null)
|
||||||
|
|
@ -339,6 +352,8 @@ public class WizardSeedFileDto
|
||||||
if (fields != null)
|
if (fields != null)
|
||||||
FillMissingGroups(wizard, sections, wizardNode);
|
FillMissingGroups(wizard, sections, wizardNode);
|
||||||
|
|
||||||
|
MoveFieldDefaultValues(wizard, fields);
|
||||||
|
|
||||||
wizard.ScreenOverlay = new WizardScreenOverlay
|
wizard.ScreenOverlay = new WizardScreenOverlay
|
||||||
{
|
{
|
||||||
ListForm = listForm,
|
ListForm = listForm,
|
||||||
|
|
@ -349,6 +364,61 @@ public class WizardSeedFileDto
|
||||||
return wizard;
|
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>
|
/// <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)
|
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) =>
|
private static bool ContainsKey(JsonObject node, string key) => FindKey(node, key) != null;
|
||||||
node.Any(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
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>
|
/// <summary>`Menu`/`Language` basliklarini duzlestirir ve dosyadaki adlari sozlesme adlarina cevirir.</summary>
|
||||||
private static void FlattenWizard(JsonObject wizardNode)
|
private static void FlattenWizard(JsonObject wizardNode)
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,16 @@ public class ListFormWizardAppService(
|
||||||
|
|
||||||
var previous = isEdit ? await GetFile(editFileName!) : null;
|
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();
|
var wizardName = input.WizardName?.Trim();
|
||||||
if (string.IsNullOrWhiteSpace(wizardName))
|
if (string.IsNullOrWhiteSpace(wizardName))
|
||||||
throw new UserFriendlyException("Wizard adı zorunludur.");
|
throw new UserFriendlyException("Wizard adı zorunludur.");
|
||||||
|
|
@ -314,6 +324,14 @@ public class ListFormWizardAppService(
|
||||||
? await IsQueryMainTableSoftDeletedAsync(input)
|
? await IsQueryMainTableSoftDeletedAsync(input)
|
||||||
: tableColumns.ContainsKey("IsDeleted");
|
: tableColumns.ContainsKey("IsDeleted");
|
||||||
isCreated = tableColumns.ContainsKey("CreatorId");
|
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))
|
foreach (var item in input.Groups.SelectMany(g => g.Items))
|
||||||
item.CaptionName = await ResolveLanguageKeyCasingAsync(rows, item.CaptionName);
|
item.CaptionName = await ResolveLanguageKeyCasingAsync(rows, item.CaptionName);
|
||||||
listFormDto = input.BuildListForm(isDeleted, isCreated);
|
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
|
/// 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.
|
/// katalogdan okunur: sinirsiz kolon (SQL Server MAX = -1, PostgreSQL text = bos) kabul edilir.
|
||||||
/// </summary>
|
/// </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
|
// Kolona bagli gorsel alani yuklenebilir olmali: goruntuleyici ile kurulan alan kayitta
|
||||||
// bos kalir ya da kopyalanan degeri degistirilemez hale getirir.
|
// bos kalir ya da kopyalanan degeri degistirilemez hale getirir.
|
||||||
|
|
@ -3004,8 +3022,8 @@ public class ListFormWizardAppService(
|
||||||
.SelectMany(g => g.Items)
|
.SelectMany(g => g.Items)
|
||||||
.Where(i => string.Equals(i.EditorType, ImageUploadEditorType, StringComparison.OrdinalIgnoreCase) &&
|
.Where(i => string.Equals(i.EditorType, ImageUploadEditorType, StringComparison.OrdinalIgnoreCase) &&
|
||||||
!HasUploadUrl(i.EditorOptions) &&
|
!HasUploadUrl(i.EditorOptions) &&
|
||||||
tableColumns.TryGetValue(i.FieldName ?? string.Empty, out var length) && length > 0)
|
tableColumns.TryGetValue(i.FieldName ?? string.Empty, out var column) && column.Length > 0)
|
||||||
.Select(i => $"{i.FieldName} ({tableColumns[i.FieldName]})")
|
.Select(i => $"{i.FieldName} ({tableColumns[i.FieldName].Length})")
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (limited.Count > 0)
|
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>
|
/// <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)
|
if (commandType == SelectCommandTypeEnum.Query || commandType == SelectCommandTypeEnum.StoredProcedure)
|
||||||
return [];
|
return [];
|
||||||
|
|
@ -3142,8 +3160,8 @@ public class ListFormWizardAppService(
|
||||||
|
|
||||||
// Şema/tablo adları kullanıcıdan geldiği için sorguya parametre olarak bağlanır.
|
// Şema/tablo adları kullanıcıdan geldiği için sorguya parametre olarak bağlanır.
|
||||||
var query = dbType == DataSourceTypeEnum.Postgresql
|
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, column_default, data_type 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";
|
||||||
|
|
||||||
var parameters = new Dictionary<string, object>
|
var parameters = new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
|
|
@ -3153,7 +3171,7 @@ public class ListFormWizardAppService(
|
||||||
|
|
||||||
var rows = await repo.QueryAsync(query, connectionString, parameters);
|
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)
|
foreach (var row in rows)
|
||||||
{
|
{
|
||||||
if (row is not IDictionary<string, object> dict)
|
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 nameKey = dict.ContainsKey("COLUMN_NAME") ? "COLUMN_NAME" : "column_name";
|
||||||
var lengthKey = dict.ContainsKey("CHARACTER_MAXIMUM_LENGTH") ? "CHARACTER_MAXIMUM_LENGTH" : "character_maximum_length";
|
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)
|
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
|
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)
|
? Convert.ToInt32(length, System.Globalization.CultureInfo.InvariantCulture)
|
||||||
: null;
|
: 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
|
// MCP create_table tabloyu yalnizca seed scripti olarak yazar; DB Migrate kurana kadar
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,13 @@ public static partial class PostgreSqlTableScript
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Henüz DB Migrate'te kurulmamış tablonun kolonlarını SQL Server seed scriptinden
|
/// 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>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ı). Dosya yoksa ya da <c>CREATE TABLE</c> tanınmazsa boş döner.
|
/// <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>
|
/// </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(
|
var path = Path.Combine(
|
||||||
SeedPathResolver.GetPath(configuration, SeedPathResolver.SqlFolder, SeedPathResolver.ObjectFolder),
|
SeedPathResolver.GetPath(configuration, SeedPathResolver.SqlFolder, SeedPathResolver.ObjectFolder),
|
||||||
$"{tableName}.sql");
|
$"{tableName}.sql");
|
||||||
|
|
@ -82,13 +83,18 @@ public static partial class PostgreSqlTableScript
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var size = match.Groups["size"].Value.Trim();
|
var size = match.Groups["size"].Value.Trim();
|
||||||
columns[match.Groups["name"].Value] = size.Length == 0
|
var maxLength = size.Length == 0
|
||||||
? null
|
? null
|
||||||
: size.Equals("MAX", StringComparison.OrdinalIgnoreCase)
|
: size.Equals("MAX", StringComparison.OrdinalIgnoreCase)
|
||||||
? -1
|
? -1
|
||||||
: int.TryParse(size, out var length) && match.Groups["type"].Value.Contains("char", StringComparison.OrdinalIgnoreCase)
|
: int.TryParse(size, out var length) && match.Groups["type"].Value.Contains("char", StringComparison.OrdinalIgnoreCase)
|
||||||
? length
|
? 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;
|
return columns;
|
||||||
|
|
@ -100,7 +106,7 @@ public static partial class PostgreSqlTableScript
|
||||||
[GeneratedRegex(@"^\s*(CONSTRAINT\b|\))", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)]
|
[GeneratedRegex(@"^\s*(CONSTRAINT\b|\))", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)]
|
||||||
private static partial Regex SeedColumnEndRegex();
|
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();
|
private static partial Regex SeedColumnLineRegex();
|
||||||
|
|
||||||
public static bool TryConvert(string sqlServerScript, out string postgreSqlScript)
|
public static bool TryConvert(string sqlServerScript, out string postgreSqlScript)
|
||||||
|
|
|
||||||
56
api/src/Sozsoft.Platform.Domain/Data/SqlSeedColumn.cs
Normal file
56
api/src/Sozsoft.Platform.Domain/Data/SqlSeedColumn.cs
Normal 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();
|
||||||
|
}
|
||||||
14
claude.md
14
claude.md
|
|
@ -214,6 +214,20 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
|
||||||
dallanır.
|
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 —
|
- 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.
|
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
|
### Cross-cutting: touching one thing means touching these too
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69486,20 +69486,6 @@
|
||||||
"Key": "App.Mcp.Error.DevRequestAnalysisRequired",
|
"Key": "App.Mcp.Error.DevRequestAnalysisRequired",
|
||||||
"Value": "Analiz boş olamaz."
|
"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",
|
"Id": "aa72e998-f4a1-5873-95ef-1fcfe0b601f9",
|
||||||
"CultureName": "en",
|
"CultureName": "en",
|
||||||
|
|
|
||||||
|
|
@ -291,6 +291,7 @@ export interface WizardSeedFileItemDto {
|
||||||
cascadeRelationField?: string
|
cascadeRelationField?: string
|
||||||
cascadeFilterOperator?: string
|
cascadeFilterOperator?: string
|
||||||
cascadeEmptyFields?: string
|
cascadeEmptyFields?: string
|
||||||
|
defaultValue?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WizardSeedFileGroupDto {
|
export interface WizardSeedFileGroupDto {
|
||||||
|
|
|
||||||
|
|
@ -801,6 +801,7 @@ const Wizard = () => {
|
||||||
cascadeRelationField: it.cascadeRelationField,
|
cascadeRelationField: it.cascadeRelationField,
|
||||||
cascadeFilterOperator: it.cascadeFilterOperator,
|
cascadeFilterOperator: it.cascadeFilterOperator,
|
||||||
cascadeEmptyFields: it.cascadeEmptyFields,
|
cascadeEmptyFields: it.cascadeEmptyFields,
|
||||||
|
defaultValue: it.defaultValue,
|
||||||
}) as WizardGroupItem,
|
}) as WizardGroupItem,
|
||||||
),
|
),
|
||||||
}))
|
}))
|
||||||
|
|
@ -1181,6 +1182,7 @@ const Wizard = () => {
|
||||||
cascadeRelationField: item.cascadeRelationField,
|
cascadeRelationField: item.cascadeRelationField,
|
||||||
cascadeFilterOperator: item.cascadeFilterOperator,
|
cascadeFilterOperator: item.cascadeFilterOperator,
|
||||||
cascadeEmptyFields: item.cascadeEmptyFields,
|
cascadeEmptyFields: item.cascadeEmptyFields,
|
||||||
|
defaultValue: item.defaultValue,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ export interface WizardGroupItem {
|
||||||
cascadeRelationField?: string
|
cascadeRelationField?: string
|
||||||
cascadeFilterOperator?: string
|
cascadeFilterOperator?: string
|
||||||
cascadeEmptyFields?: string
|
cascadeEmptyFields?: string
|
||||||
|
/** Yeni kaydin form degeri; bossa deploy kolonun sabit DEFAULT'unu yazar. Duzenlemede korunur. */
|
||||||
|
defaultValue?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WizardGroup {
|
export interface WizardGroup {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue