Wizard Mcp kuralları değiştirildi.
This commit is contained in:
parent
5560d3bb8c
commit
a0f359df67
18 changed files with 272 additions and 58 deletions
|
|
@ -1249,7 +1249,7 @@ soneklerini alır.
|
||||||
| **Public › Sales Orders** | `App.Orders.SalesOrders` (alt form Sales Order Item) | `Sas_H_Order` + `Sas_H_OrderItem` | host | **Onay akışı + alt kalem + toplam + diyalog** birlikte kullanılan tam örnek (§12.6). |
|
| **Public › Sales Orders** | `App.Orders.SalesOrders` (alt form Sales Order Item) | `Sas_H_Order` + `Sas_H_OrderItem` | host | **Onay akışı + alt kalem + toplam + diyalog** birlikte kullanılan tam örnek (§12.6). |
|
||||||
| **Public › Blog Category / Posts** | `App.BlogManagement.Category` · `.Posts` | `Sas_H_BlogCategory` · `Sas_H_BlogPost` | host | Çok dilli içerik (`ContentTr`/`ContentEn`), slug, yayın durumu, sayaç alanları; public `/blog` bu tablolardan okur, yayınlanmış yazılar sitemap'e girer. |
|
| **Public › Blog Category / Posts** | `App.BlogManagement.Category` · `.Posts` | `Sas_H_BlogCategory` · `Sas_H_BlogPost` | host | Çok dilli içerik (`ContentTr`/`ContentEn`), slug, yayın durumu, sayaç alanları; public `/blog` bu tablolardan okur, yayınlanmış yazılar sitemap'e girer. |
|
||||||
| **Public › Demos** | `App.Demos` | `Sas_H_Demo` | host | Public `/demo` formundan gelen talepler — public form → tablo akışının örneği. |
|
| **Public › Demos** | `App.Demos` | `Sas_H_Demo` | host | Public `/demo` formundan gelen talepler — public form → tablo akışının örneği. |
|
||||||
| **Dev Requests** | `App.DevRequests` | `Sas_H_DevRequest` | host | **Kanban/Todo düzeninin** referansı (`DefaultLayout: todo`): `Status`, `Priority`, `SortOrder`, `Tags`, `Assignees`, `SubTasks`, `Timesheets`. MCP geliştirme döngüsünün kuyruğudur (`Ready to Start` → `Staging`; yalnızca `start_dev_request` başlatır; açıklamadaki base64 görseller MCP'ye resim içeriği olarak gider, not `append_dev_request_note` ile eklenir; `lowcode.instructions.md` §0.11). |
|
| **Dev Requests** | `App.DevRequests` | `Sas_H_DevRequest` | host | **Kanban/Todo düzeninin** referansı (`DefaultLayout: todo`): `Status`, `Priority`, `SortOrder`, `Tags`, `Assignees`, `SubTasks`, `Timesheets`. MCP geliştirme döngüsünün kuyruğudur (`Ready to Start` → `Testing`, `Staging`'e kullanıcı alır; araç çubuğunda DB Migrate butonu vardır — `UiEvalService.ApiDbMigrate()`, `App.Setup.Migrate`; yalnızca `start_dev_request` başlatır; açıklamadaki base64 görseller MCP'ye resim içeriği olarak gider, not `append_dev_request_note` ile eklenir; `lowcode.instructions.md` §0.11). |
|
||||||
| **Tenants** | `AbpTenantManagement.Tenants` | `AbpTenants` | host | Kiracı kaydı, bağlantı dizesi diyaloğu (`TenantsConnectionString`), alt form olarak şubeler; yazma `list-form-dynamic-api/tenant-*`. Ekranların `IsTenant` davranışının kaynağı. |
|
| **Tenants** | `AbpTenantManagement.Tenants` | `AbpTenants` | host | Kiracı kaydı, bağlantı dizesi diyaloğu (`TenantsConnectionString`), alt form olarak şubeler; yazma `list-form-dynamic-api/tenant-*`. Ekranların `IsTenant` davranışının kaynağı. |
|
||||||
| **Branches** | `App.Branches` | `Sas_T_Branch` | tenant | Şube listesi. Ekranı `IsBranch = true` yaparsan filtre bu tablodan gelir; `BranchSeed` diyaloğu şube verisini kurar. |
|
| **Branches** | `App.Branches` | `Sas_T_Branch` | tenant | Şube listesi. Ekranı `IsBranch = true` yaparsan filtre bu tablodan gelir; `BranchSeed` diyaloğu şube verisini kurar. |
|
||||||
| **Setting Definitions** | `App.SettingDefinitions` | `Sas_H_SettingDefinition` | host | Yeni uygulama ayarı: `Code`, `MainGroupKey`/`SubGroupKey`, `DataType`, `SelectOptions`, `DefaultValue`, `Providers`, `RequiredPermissionName`, `IsEncrypted`, `IsVisibleToClients`. Hazır tanımlar `data/App.SettingDefinitions.json`'dan gelir. Ayarlanabilir olması gereken değeri koda gömme. |
|
| **Setting Definitions** | `App.SettingDefinitions` | `Sas_H_SettingDefinition` | host | Yeni uygulama ayarı: `Code`, `MainGroupKey`/`SubGroupKey`, `DataType`, `SelectOptions`, `DefaultValue`, `Providers`, `RequiredPermissionName`, `IsEncrypted`, `IsVisibleToClients`. Hazır tanımlar `data/App.SettingDefinitions.json`'dan gelir. Ayarlanabilir olması gereken değeri koda gömme. |
|
||||||
|
|
|
||||||
56
.github/instructions/lowcode.instructions.md
vendored
56
.github/instructions/lowcode.instructions.md
vendored
|
|
@ -111,7 +111,7 @@ Uydurma. Şu üçünü mutlaka kontrol et:
|
||||||
| JSON alan adları | **PascalCase** (`Wizard`, `ListFormCode`, `Groups`) — seeder `PropertyNameCaseInsensitive` okur ama dosyalar PascalCase üretilir |
|
| JSON alan adları | **PascalCase** (`Wizard`, `ListFormCode`, `Groups`) — seeder `PropertyNameCaseInsensitive` okur ama dosyalar PascalCase üretilir |
|
||||||
| Custom component dosyası | Kök alanlar PascalCase; `Props` **içindeki** designer dokümanı camelCase (`visualDesigner`, `nodes`, `sourceMode`) |
|
| Custom component dosyası | Kök alanlar PascalCase; `Props` **içindeki** designer dokümanı camelCase (`visualDesigner`, `nodes`, `sourceMode`) |
|
||||||
| Enum'lar | Sayı olarak yazılır (§3) |
|
| Enum'lar | Sayı olarak yazılır (§3) |
|
||||||
| `GeneratedAt` | ISO-8601 UTC (`2026-08-26T10:15:00Z`) — yalnızca bilgi amaçlı. **Yalnızca `crud/` ve `data/` dosyalarında vardır**; wizard seed dosyasında karşılığı `Wizard.SeededAt` alanıdır |
|
| `GeneratedAt` | ISO-8601 UTC (`2026-08-26T10:15:00Z`). **Yalnızca `crud/` ve `data/` dosyalarında vardır**; wizard seed dosyasında karşılığı `Wizard.SeededAt` alanıdır. `data/`: dosyanın oluşturulma anı, yalnızca bilgi amaçlı — ilk yazımda dolar, satır ekleme/silme onu değiştirmez (ekleyip geri kaldıran işlem git'te iz bırakmaz). `crud/`: üretim damgası, migrate kararında kullanılır (§9.1) |
|
||||||
| İç içe JSON | `EditorOptions`, `EditorScript`, `LookupQuery` → JSON **string** olarak kaçışlanır |
|
| İç içe JSON | `EditorOptions`, `EditorScript`, `LookupQuery` → JSON **string** olarak kaçışlanır |
|
||||||
| Satır sonu | LF |
|
| Satır sonu | LF |
|
||||||
|
|
||||||
|
|
@ -503,13 +503,13 @@ ister ve kiracı kullanıcısına hiçbiri açılmaz.
|
||||||
| `get_dev_guide` | Bu dosyanın (`lowcode`) ya da `reference`'ın başlık listesini / bir bölümünü döner | Bölüm numarayla istenir (`4.3`); aynı numarayı iki başlık taşımamalıdır |
|
| `get_dev_guide` | Bu dosyanın (`lowcode`) ya da `reference`'ın başlık listesini / bir bölümünü döner | Bölüm numarayla istenir (`4.3`); aynı numarayı iki başlık taşımamalıdır |
|
||||||
| `create_table` | Yeni SQL Server tablosu kurar, `sql/object/{Tablo}.sql` dosyasını yazar | Ek olarak `App.SqlQueryManager` ister; `Id`/`TenantId`/audit kolonlarını kendi ekler (`fullAudited`, `multiTenant` varsayılan açık); var olan tabloyu reddeder. View/SP/fonksiyon kurulamaz |
|
| `create_table` | Yeni SQL Server tablosu kurar, `sql/object/{Tablo}.sql` dosyasını yazar | Ek olarak `App.SqlQueryManager` ister; `Id`/`TenantId`/audit kolonlarını kendi ekler (`fullAudited`, `multiTenant` varsayılan açık); var olan tabloyu reddeder. View/SP/fonksiyon kurulamaz |
|
||||||
| `list_wizards` · `get_wizard` | Wizard dosyalarını listeler (menü yolu, bağımlılar) · dosyayı diskteki hâliyle döner | Var olan menü kökünü/izin grubunu bulmak için önce `list_wizards` |
|
| `list_wizards` · `get_wizard` | Wizard dosyalarını listeler (menü yolu, bağımlılar) · dosyayı diskteki hâliyle döner | Var olan menü kökünü/izin grubunu bulmak için önce `list_wizards` |
|
||||||
| `deploy_wizard` | Wizard cevabından ekranın wizard dosyasını ve menü/yetki/dil seed satırlarını yazar; veritabanına yazmaz (§4.0) | Girdi §4.4'teki düz cevap ya da `get_wizard` çıktısıyla aynı dosya biçimi; enum'lar sayı. `replaceFileName` = `EditFileName` (§4.5). İstek demo veri taşıyorsa `SeedData: true` (§0.10.1). Çıkıştaki `isPending: true` ekranın henüz kurulmadığını söyler — kullanıcı Wizard Manager'da DB Migrate çalıştırır |
|
| `deploy_wizard` | Wizard cevabından ekranın wizard dosyasını ve menü/yetki/dil seed satırlarını yazar; veritabanına yazmaz (§4.0) | Girdi §4.4'teki düz cevap ya da `get_wizard` çıktısıyla aynı dosya biçimi; enum'lar sayı. `replaceFileName` = `EditFileName` (§4.5). İstek demo veri taşıyorsa `SeedData: true` + `seedRows` (§0.10.1). Çıkıştaki `isPending: true` ekranın henüz kurulmadığını söyler — kullanıcı Wizard Manager'da DB Migrate çalıştırır; model migrate'i beklemez |
|
||||||
| `delete_wizard` | Wizard'ı ve yalnızca onun ürettiği kayıtları siler; `dropTables: true` ekranın tablosunu da düşürür | Bağımlı wizard varsa reddeder. Tablo kullanıcı açıkça onaylamadan düşürülmez; `App.SqlQueryManager` ister (§4.5) |
|
| `delete_wizard` | Wizard'ı ve yalnızca onun ürettiği kayıtları siler; `dropTables: true` ekranın tablosunu da düşürür | Bağımlı wizard varsa reddeder. Tablo kullanıcı açıkça onaylamadan düşürülmez; `App.SqlQueryManager` ister (§4.5) |
|
||||||
| `start_dev_request` | `App.DevRequests` talebini üstlenir: `Ready to Start` durumundaysa `In Progress` durumuna alır, değilse reddeder | Ek olarak `App.DevRequests.Update` ister. Açıklamadaki görseller ayrı resim içeriği olarak gelir (§0.11) |
|
| `start_dev_request` | `App.DevRequests` talebini üstlenir: `Ready to Start` durumundaysa `In Progress` durumuna alır, değilse reddeder | Ek olarak `App.DevRequests.Update` ister. Açıklamadaki görseller ayrı resim içeriği olarak gelir (§0.11) |
|
||||||
| `get_dev_request` | Talebi durumuna dokunmadan okur (aynı metin + resim içerikleri) | Yarım kalan talebe dönmek için; `App.DevRequests` ister |
|
| `get_dev_request` | Talebi durumuna dokunmadan okur (aynı metin + resim içerikleri) | Yarım kalan talebe dönmek için; `App.DevRequests` ister |
|
||||||
| `append_dev_request_note` | Talep açıklamasının sonuna HTML ekler | Sonuç notu için; `Description`'ı `update_row` ile yazma (§0.11) |
|
| `append_dev_request_note` | Talep açıklamasının sonuna HTML ekler | Sonuç notu için; `Description`'ı `update_row` ile yazma (§0.11) |
|
||||||
| `add_dev_request_subtasks` | `SubTasks` listesine tamamlanmış satırlar ekler | Atanan = bağlanan kullanıcı, bitiş = bugün (sunucu yazar); `SubTasks`'ı `update_row` ile yazma (§0.11) |
|
| `add_dev_request_subtasks` | `SubTasks` listesine tamamlanmış satırlar ekler | Atanan = bağlanan kullanıcı, bitiş = bugün (sunucu yazar); `SubTasks`'ı `update_row` ile yazma (§0.11) |
|
||||||
| `verify_wizard` | DB Migrate ile kurulmuş ekranı veri yazmadan doğrular (migrate bekleyen dosyada `install` kontrolü başarısız döner, diğerleri yapılmaz): menü, yetki tanımı, ekran sorgusu (List) ya da bileşen (Custom), seed kapanışı | `passed` yalnızca engelleyici bir kontrol kalırsa `false`; `seed_closure` engellemez ama rapora yazılır (§0.11) |
|
| `verify_wizard` | DB Migrate ile kurulmuş ekranı veri yazmadan doğrular (migrate bekleyen dosyada `install` kontrolü başarısız döner, diğerleri yapılmaz): menü, yetki tanımı, ekran sorgusu (List) ya da bileşen (Custom), seed kapanışı | İsteğe bağlı: kullanıcı migrate sonrası isterse. Talep döngüsünün (§0.11) adımı değildir. `passed` yalnızca engelleyici bir kontrol kalırsa `false` |
|
||||||
| `list_components` · `get_component` · `save_component` · `delete_component` | Custom component okuma/yazma (ada göre upsert) | `save_component` visual designer bileşenini reddeder — yalnız Code modu (§7.1.1) |
|
| `list_components` · `get_component` · `save_component` · `delete_component` | Custom component okuma/yazma (ada göre upsert) | `save_component` visual designer bileşenini reddeder — yalnız Code modu (§7.1.1) |
|
||||||
|
|
||||||
**Yetkiler.** MCP'nin iki yetkisi vardır: `.Invoke` (bağlantı + okuma) ve `.Write` (her
|
**Yetkiler.** MCP'nin iki yetkisi vardır: `.Invoke` (bağlantı + okuma) ve `.Write` (her
|
||||||
|
|
@ -524,25 +524,24 @@ araçla yapmaya çalışma, eksik yetkiyi kullanıcıya olduğu gibi bildir ve d
|
||||||
İstek örnek/demo satır taşıyorsa (prompt'taki tablo ya da liste, ekran görüntüsündeki satırlar,
|
İstek örnek/demo satır taşıyorsa (prompt'taki tablo ya da liste, ekran görüntüsündeki satırlar,
|
||||||
eklenen dosya) bu satırlar ekranla birlikte seed edilir; migrate çalıştığında liste boş gelmez.
|
eklenen dosya) bu satırlar ekranla birlikte seed edilir; migrate çalıştığında liste boş gelmez.
|
||||||
|
|
||||||
1. `deploy_wizard` cevabına `SeedData: true` yaz. Ekranın `SeedFilePath`'i
|
1. `deploy_wizard` cevabına `SeedData: true` yaz, satırların hepsini aynı çağrıda `seedRows` ile
|
||||||
`data/{ListFormCode}.json` olur, `SeedSyncInsert/Update/Delete` açılır (§9.15).
|
gönder (alan adından değere nesne dizisi). Ekranın `SeedFilePath`'i `data/{ListFormCode}.json`
|
||||||
2. Deploy ekranı kurmaz; kullanıcıdan Wizard Manager'da **DB Migrate** çalıştırmasını iste.
|
olur, `SeedSyncInsert/Update/Delete` açılır (§9.15); satırlar deploy anında bu dosyaya yazılır.
|
||||||
`list_wizards`'ta dosyanın `isPending` değeri `false` olunca (ya da `verify_wizard` geçince)
|
`Guid` anahtarı sunucu üretir; `TenantId` ve audit alanlarını migrate doldurur — yazma. Aynı
|
||||||
her satırı `insert_row` ile ekle. Satır ekranın insert sözleşmesinden geçer
|
içerikli satır dosyada varsa (tekrar deploy) yeniden eklenmez.
|
||||||
ve `ListFormSeedDataSynchronizer` onu `configs/seeds/host/data/{ListFormCode}.json` dosyasına
|
2. DB Migrate'i bekleme. Migrate wizard seeder ile ekranı kurar, ardından `ListFormSeedDataApplier`
|
||||||
yazar (kiracı bağlamında `tenants/{TenantId}/data/`).
|
dosyadaki satırları ekler (anahtarı olmayanı ekler, var olana dokunmaz).
|
||||||
3. Migrate sırasında wizard seeder ekranı kurar, ardından `ListFormSeedDataApplier` dosyadaki
|
3. Migrate'ten sonra ekrandan girilen satırlar `ListFormSeedDataSynchronizer` ile aynı dosyaya yazılır
|
||||||
satırları ekler (anahtarı olmayanı ekler, var olana dokunmaz).
|
(kiracı bağlamında `tenants/{TenantId}/data/`).
|
||||||
|
|
||||||
Kurallar:
|
Kurallar:
|
||||||
- Dosyayı elle yazma; satır ekranın sorgusundan okunduğu için anahtar, `TenantId` ve audit
|
- Dosyayı elle yazma; `seedRows` alan adlarını ekranın alanlarına göre doğrular, bilinmeyen alanı reddeder.
|
||||||
alanları doğru biçimde gelir.
|
|
||||||
- Görsel yalnızca ekranın şablonu değildir: içinde görünen **her satır** okunur ve demo veri
|
- Görsel yalnızca ekranın şablonu değildir: içinde görünen **her satır** okunur ve demo veri
|
||||||
olarak eklenir (standing default 6'daki "piksel sözleşmesi değildir" kuralı düzen içindir, veri için değil).
|
olarak eklenir (standing default 6'daki "piksel sözleşmesi değildir" kuralı düzen içindir, veri için değil).
|
||||||
- Görselden okunamayan değer uydurulmaz: zorunlu alan boşsa kullanıcıya sor.
|
- Görselden okunamayan değer uydurulmaz: zorunlu alan boşsa kullanıcıya sor.
|
||||||
- Lookup alanının değeri kaynak tablodaki anahtardır; kaynakta yoksa önce o ekrana satır eklenir
|
- Lookup alanının değeri kaynak tablodaki anahtardır; kaynakta yoksa önce o ekrana satır eklenir
|
||||||
(o ekranın `SeedFilePath`'i yoksa satır yalnızca bu veritabanında kalır — raporda belirt).
|
(o ekranın `SeedFilePath`'i yoksa satır yalnızca bu veritabanında kalır — raporda belirt).
|
||||||
- İstek demo veri taşımıyorsa `SeedData` yazılmaz; `verify_wizard` testi için satır eklenmez.
|
- İstek demo veri taşımıyorsa `SeedData` ve `seedRows` yazılmaz; test için satır eklenmez.
|
||||||
|
|
||||||
Okuma araçları (`list_lists`, `describe_list`, `search_schema`, `query_list`, `run_select`,
|
Okuma araçları (`list_lists`, `describe_list`, `search_schema`, `query_list`, `run_select`,
|
||||||
`list_queries`, `run_query`) keşif turunda (§0.3) tablo/kolon/lookup kaynağını bulmak içindir;
|
`list_queries`, `run_query`) keşif turunda (§0.3) tablo/kolon/lookup kaynağını bulmak içindir;
|
||||||
|
|
@ -582,18 +581,17 @@ talebin metnini döndürür. Başlık birden fazla talebe uyuyorsa Id ister. `St
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 1. Kuyruğu oku (yalnızca toplu) | `query_list` — `ListFormCode: App.DevRequests`, filtre `["Status","=","Ready to Start"]`, sıralama `SortOrder` | — |
|
| 1. Kuyruğu oku (yalnızca toplu) | `query_list` — `ListFormCode: App.DevRequests`, filtre `["Status","=","Ready to Start"]`, sıralama `SortOrder` | — |
|
||||||
| 2. Talebi üstlen | `start_dev_request` — Id ya da tam başlık. Yarım kalmış talebe dönüşte `get_dev_request` | In Progress |
|
| 2. Talebi üstlen | `start_dev_request` — Id ya da tam başlık. Yarım kalmış talebe dönüşte `get_dev_request` | In Progress |
|
||||||
| 3. Üret | §0.3 keşif → `create_table` / `deploy_wizard` / `save_component`; talep demo veri taşıyorsa `SeedData: true` + `insert_row` (§0.10.1); bu dosyanın kuralları aynen geçerlidir | — |
|
| 3. Üret | §0.3 keşif (depodan/araçlardan; kullanıcıya soru yok) → `create_table` / `deploy_wizard` / `save_component`; talep demo veri taşıyorsa `SeedData: true` + `seedRows` (§0.10.1); bu dosyanın kuralları aynen geçerlidir | — |
|
||||||
| 4. Test et | `update_row` → `Testing`, ardından üretilen her wizard için `verify_wizard` | Testing |
|
| 4. Teslim | Sonuç kaydı + `update_row` → `Testing`. DB Migrate beklenmez; talep burada biter | Testing |
|
||||||
| 5a. Geçti | `update_row` → `Staging` + sonuç kaydı | Staging |
|
| 5. Test | Kullanıcı DB Migrate çalıştırır, ekranı elle test eder ve talebi kendisi `Staging`'e alır (geri dönüşte `In Progress`). MCP bu adımı yapmaz | Staging |
|
||||||
| 5b. Kaldı | `update_row` → `In Progress` + sonuç kaydı; düzelt ve 4'e dön ya da bırak | In Progress |
|
|
||||||
|
|
||||||
**Sonuç kaydı** şema değiştirmeden mevcut alanlara yazılır:
|
**Sonuç kaydı** şema değiştirmeden mevcut alanlara yazılır:
|
||||||
- `SubTasks` — her üretilen artefakt bir satır, `add_dev_request_subtasks` ile yalnızca başlık
|
- `SubTasks` — her üretilen artefakt bir satır, `add_dev_request_subtasks` ile yalnızca başlık
|
||||||
verilerek (`"deploy_wizard: Mrp.Orders.json"`). Araç satırı tamamlanmış yazar, atanan kişiyi
|
verilerek (`"deploy_wizard: Mrp.Orders.json"`). Araç satırı tamamlanmış yazar, atanan kişiyi
|
||||||
bağlanan kullanıcı, bitiş tarihini bugün yapar ve var olan satırları korur. `SubTasks`
|
bağlanan kullanıcı, bitiş tarihini bugün yapar ve var olan satırları korur. `SubTasks`
|
||||||
`update_row` ile yazılmaz.
|
`update_row` ile yazılmaz.
|
||||||
- `Description` — `append_dev_request_note` ile sonuna `<h4>MCP</h4>` başlığıyla `verify_wizard`
|
- `Description` — `append_dev_request_note` ile sonuna `<h4>MCP</h4>` başlığıyla kısa özet:
|
||||||
özeti: geçen/kalan kontroller, `seed_closure` uyarıları. `Description` hiçbir zaman `update_row`
|
üretilenler ve DB Migrate bekleyen wizard'lar. `Description` hiçbir zaman `update_row`
|
||||||
ile yazılmaz — base64 görselleri taşır ve yeniden yazmak onları siler.
|
ile yazılmaz — base64 görselleri taşır ve yeniden yazmak onları siler.
|
||||||
|
|
||||||
**Görseller.** Talebe yapıştırılan ekran görüntüleri açıklamada base64 durur; araç onları metinden
|
**Görseller.** Talebe yapıştırılan ekran görüntüleri açıklamada base64 durur; araç onları metinden
|
||||||
|
|
@ -602,18 +600,19 @@ görseli yeniden istemezsin. Görsel talebin parçasıdır: ekran düzenini (§0
|
||||||
değildir) ve içindeki satırları taşır; satırlar demo veridir (§0.10.1).
|
değildir) ve içindeki satırları taşır; satırlar demo veridir (§0.10.1).
|
||||||
|
|
||||||
**Kurallar**
|
**Kurallar**
|
||||||
|
- Talep tarifin kendisidir: kullanıcıya soru sorulmaz, belirsiz noktada §0.6'nın önerilen
|
||||||
|
varsayılanı seçilir ve sonuç notuna yazılır. Döngü DB Migrate'i beklemez.
|
||||||
- Talep §0.6 keşif turunu cevaplayacak kadar net değilse üretme; `Backlog`'a geri al ve eksik
|
- Talep §0.6 keşif turunu cevaplayacak kadar net değilse üretme; `Backlog`'a geri al ve eksik
|
||||||
soruları `Description` sonuna yaz. Tabloya yazma hedefi, onaycı ve hesap formülü talepten
|
soruları `Description` sonuna yaz. Tabloya yazma hedefi, onaycı ve hesap formülü talepten
|
||||||
okunamıyorsa varsayılmaz.
|
okunamıyorsa varsayılmaz.
|
||||||
- Çerçeve dışı bir ihtiyaç (§0.8) çıkarsa talebi `In Progress`'te bırak ve kullanıcıya sor.
|
- Çerçeve dışı bir ihtiyaç (§0.8) çıkarsa talebi `In Progress`'te bırak ve kullanıcıya sor.
|
||||||
- `verify_wizard` veri yazmaz; test için ekrana satır ekleme — SeedSync açık ekranda seed dosyasına iz bırakır. Talebin kendi demo verisi test satırı değildir, §0.10.1 ile eklenir.
|
- Test için ekrana satır ekleme — SeedSync açık ekranda seed dosyasına iz bırakır. Talebin kendi demo verisi test satırı değildir, §0.10.1 ile eklenir.
|
||||||
- `Staging` son durumdur: ekran bu ortamda o anda kullanılabilir, çünkü deploy canlı veritabanına yazar.
|
- MCP talebi `Staging`'e almaz: deploy yalnızca dosya yazar, ekran migrate'ten sonra vardır ve testi kullanıcı yapar.
|
||||||
|
|
||||||
**Migrate** döngünün parçası değildir ve MCP'den tetiklenmez. Parti bitince yetkili host
|
**Migrate** döngünün parçası değildir ve MCP'den tetiklenmez. Parti bitince yetkili host
|
||||||
kullanıcısı `/api/setup/migrate` akışını elle çalıştırır (`Setup.Migrate`; Redis'i temizler ve
|
kullanıcısı Wizard Manager'daki DB Migrate'i (`/api/setup/migrate`, `Setup.Migrate`) çalıştırır;
|
||||||
bütün kiracıları dolaşır). Gerekli olduğu durumlar: ayrı veritabanı kullanan kiracılara
|
migrate ekranları, menü/yetki/dil satırlarını ve demo verisini kurar, Redis'i temizler ve bütün
|
||||||
tablo/script taşımak, seed dosyalarından başka bir ortam ya da sıfırlanmış veritabanı kurmak.
|
kiracıları dolaşır. Rapor bu adımı tek satırla belirtir.
|
||||||
Parti raporunda `seed_closure` uyarısı veren ekranlar ayrıca belirtilir; migrate onları kuramaz.
|
|
||||||
|
|
||||||
## 1. Hangi istek → hangi artefakt
|
## 1. Hangi istek → hangi artefakt
|
||||||
|
|
||||||
|
|
@ -1839,6 +1838,9 @@ Kurallar:
|
||||||
olmayan bir ad da yazılabilir. Form ekranının araç çubuğu da aynı ikon adlarını kullanır.
|
olmayan bir ad da yazılabilir. Form ekranının araç çubuğu da aynı ikon adlarını kullanır.
|
||||||
- Toolbar butonu **seçili satırlarla** çalışır; `SelectionJson` uygun modda (`single`/`multiple`)
|
- Toolbar butonu **seçili satırlarla** çalışır; `SelectionJson` uygun modda (`single`/`multiple`)
|
||||||
olmalıdır. İş akışı varsa wizard bunu zaten `single` yapar.
|
olmalıdır. İş akışı varsa wizard bunu zaten `single` yapar.
|
||||||
|
- Toolbar butonu Grid, Card ve Tree'nin yanında **Todo panosunda** da çizilir; pano satır seçimi
|
||||||
|
taşımadığı için orada yalnızca satırdan bağımsız `Url` ve `OnClick` butonları görünür
|
||||||
|
(`DialogName` görünmez).
|
||||||
- Satır bazlı aksiyon istiyorsan `ButtonPosition: 0` kullan; buton komut sütununda görünür.
|
- Satır bazlı aksiyon istiyorsan `ButtonPosition: 0` kullan; buton komut sütununda görünür.
|
||||||
- **`IsVisible` ve `VisibleExpression` yalnızca satır butonlarında (`ButtonPosition: 0`)
|
- **`IsVisible` ve `VisibleExpression` yalnızca satır butonlarında (`ButtonPosition: 0`)
|
||||||
çalışır**; toolbar butonu her zaman görünür (görünürlüğü `AuthName` belirler).
|
çalışır**; toolbar butonu her zaman görünür (görünürlüğü `AuthName` belirler).
|
||||||
|
|
|
||||||
|
|
@ -1406,9 +1406,9 @@ liste süzgeci ve çağrı kapısı aynı kuralı kullanır.
|
||||||
| `get_dev_guide` | Üretim sözleşmesi: `lowcode` / `reference` belgelerinin başlık listesi ya da istenen bölümü (numarayla, örn. `4.2`). Çok büyük bir üst bölüm yalnızca giriş metni + alt başlıklarıyla döner. |
|
| `get_dev_guide` | Üretim sözleşmesi: `lowcode` / `reference` belgelerinin başlık listesi ya da istenen bölümü (numarayla, örn. `4.2`). Çok büyük bir üst bölüm yalnızca giriş metni + alt başlıklarıyla döner. |
|
||||||
| `create_table` | Yeni tabloyu SQL Query Manager tablo tasarımcısıyla aynı script biçimiyle kurar (`McpTableCreator`): `Id` + `TenantId` + tam audit kolonları şablondan gelir, istemci yalnızca iş kolonlarını verir; tip ve varsayılan değer beyaz listeden geçer, istemci SQL yazamaz. Script `{kapsam}/sql/object/{Tablo}.sql` dosyasına yazılır. Yalnızca oluşturur — tablo varsa reddeder; yalnızca SQL Server. `.Write` + `App.SqlQueryManager` ister. |
|
| `create_table` | Yeni tabloyu SQL Query Manager tablo tasarımcısıyla aynı script biçimiyle kurar (`McpTableCreator`): `Id` + `TenantId` + tam audit kolonları şablondan gelir, istemci yalnızca iş kolonlarını verir; tip ve varsayılan değer beyaz listeden geçer, istemci SQL yazamaz. Script `{kapsam}/sql/object/{Tablo}.sql` dosyasına yazılır. Yalnızca oluşturur — tablo varsa reddeder; yalnızca SQL Server. `.Write` + `App.SqlQueryManager` 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": …}`) ya da düz cevaplardır; ikisi de `WizardSeedFileDto.FromSeedJson`'dan geçer. Wizard ekranı gibi yalnızca seed dosyalarını yazar; ekran DB Migrate ile kurulur ve çıkıştaki `isPending` o zamana kadar `true` kalır (`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 — migrate sonrasında satırlar `insert_row` ile eklenir; `ListFormSeedDataSynchronizer` onları `configs/seeds/host/data/` altına yazar, migrate ekranla birlikte geri yükler (`lowcode.instructions.md` §0.10.1). |
|
| `deploy_wizard` | Wizard'ı Wizard ekranıyla aynı yoldan (`IListFormWizardAppService.Create`) deploy eder. Girdi seed dosyası biçimi (`{"Wizard": …}`) ya da düz cevaplardır; ikisi de `WizardSeedFileDto.FromSeedJson`'dan geçer. 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). |
|
||||||
| `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). `App.DevRequests` geliştirme döngüsünün test adımıdı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. `.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. `.Write` + `App.DevRequests.Update` ister. |
|
||||||
| `get_dev_request` | Talebi durumuna dokunmadan, `start_dev_request` ile aynı biçimde (metin + resim içerikleri) okur; yarım kalan talebe dönmek için. `App.DevRequests` ister. |
|
| `get_dev_request` | Talebi durumuna dokunmadan, `start_dev_request` ile aynı biçimde (metin + resim içerikleri) okur; yarım kalan talebe dönmek için. `App.DevRequests` ister. |
|
||||||
| `add_dev_request_subtasks` | Talebin `SubTasks` listesine tamamlanmış satırlar ekler: model yalnızca başlığı verir, atanan kişi bağlanan kullanıcının adı (`userName`), bitiş tarihi bugün (`yyyy-MM-dd`) olarak sunucuda yazılır; var olan satırlar korunur. `.Write` + `App.DevRequests.Update` ister. |
|
| `add_dev_request_subtasks` | Talebin `SubTasks` listesine tamamlanmış satırlar ekler: model yalnızca başlığı verir, atanan kişi bağlanan kullanıcının adı (`userName`), bitiş tarihi bugün (`yyyy-MM-dd`) olarak sunucuda yazılır; var olan satırlar korunur. `.Write` + `App.DevRequests.Update` ister. |
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,12 @@ public class McpWizardDeployRequestDto
|
||||||
|
|
||||||
/// <summary>Doluysa guncellemedir: bu dosya ve urettigi kayitlar silinip yeniden uretilir.</summary>
|
/// <summary>Doluysa guncellemedir: bu dosya ve urettigi kayitlar silinip yeniden uretilir.</summary>
|
||||||
public string? ReplaceFileName { get; set; }
|
public string? ReplaceFileName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Demo satirlar: alan adindan degere JSON nesne dizisi. Ekranin veri dosyasina
|
||||||
|
/// (<c>data/{ListFormCode}.json</c>) deploy aninda yazilir, migrate ekranla birlikte ekler.
|
||||||
|
/// </summary>
|
||||||
|
public string? SeedRows { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Sozsoft.Mcp.Dtos;
|
using Sozsoft.Mcp.Dtos;
|
||||||
using Sozsoft.Mcp.Services;
|
using Sozsoft.Mcp.Services;
|
||||||
using Sozsoft.Platform;
|
using Sozsoft.Platform;
|
||||||
|
using Sozsoft.Platform.Data.Seeds;
|
||||||
using Sozsoft.Platform.DeveloperKit;
|
using Sozsoft.Platform.DeveloperKit;
|
||||||
using Sozsoft.Platform.Entities;
|
using Sozsoft.Platform.Entities;
|
||||||
using Sozsoft.Platform.Enums;
|
using Sozsoft.Platform.Enums;
|
||||||
|
|
@ -37,7 +41,8 @@ public class McpDevelopAppService(
|
||||||
IListFormSelectAppService listFormSelectAppService,
|
IListFormSelectAppService listFormSelectAppService,
|
||||||
IRepository<Menu, Guid> menuRepository,
|
IRepository<Menu, Guid> menuRepository,
|
||||||
IRepository<PermissionDefinitionRecord, Guid> permissionRepository,
|
IRepository<PermissionDefinitionRecord, Guid> permissionRepository,
|
||||||
IRepository<DevRequest, Guid> devRequestRepository)
|
IRepository<DevRequest, Guid> devRequestRepository,
|
||||||
|
IConfiguration configuration)
|
||||||
: McpAppService(serverConfigProvider), IMcpDevelopAppService
|
: McpAppService(serverConfigProvider), IMcpDevelopAppService
|
||||||
{
|
{
|
||||||
private const string DefaultGuideDocument = "lowcode";
|
private const string DefaultGuideDocument = "lowcode";
|
||||||
|
|
@ -160,13 +165,103 @@ public class McpDevelopAppService(
|
||||||
var wizard = ParseWizard(input.Wizard);
|
var wizard = ParseWizard(input.Wizard);
|
||||||
wizard.EditFileName = string.IsNullOrWhiteSpace(input.ReplaceFileName) ? null : input.ReplaceFileName.Trim();
|
wizard.EditFileName = string.IsNullOrWhiteSpace(input.ReplaceFileName) ? null : input.ReplaceFileName.Trim();
|
||||||
|
|
||||||
|
// Satirlar deploy'dan once dogrulanir; gecersiz girdi yarim bir deploy birakmaz.
|
||||||
|
var seedRows = ParseSeedRows(input.SeedRows, wizard);
|
||||||
|
|
||||||
await wizardAppService.Create(wizard);
|
await wizardAppService.Create(wizard);
|
||||||
|
|
||||||
var files = await wizardAppService.GetFiles();
|
var files = await wizardAppService.GetFiles();
|
||||||
|
var file = files.FirstOrDefault(file => string.Equals(file.WizardName, wizard.WizardName?.Trim(), StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
return files.FirstOrDefault(file => string.Equals(file.WizardName, wizard.WizardName?.Trim(), StringComparison.OrdinalIgnoreCase));
|
if (file != null && seedRows.Count > 0)
|
||||||
|
await WriteSeedRowsAsync(file.FileName, seedRows);
|
||||||
|
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Demo satirlarini okur ve ekranin alanlarina gore dogrular. Satirlar yalnizca SeedData acik
|
||||||
|
/// liste ekraninda kabul edilir: migrate onlari ekranin veri dosyasindan ekler.
|
||||||
|
/// </summary>
|
||||||
|
private List<Dictionary<string, JsonElement>> ParseSeedRows(string? json, ListFormWizardDto wizard)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(json))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
if (wizard.ComponentKind == WizardComponentKindEnum.Custom || !wizard.SeedData)
|
||||||
|
throw new UserFriendlyException(L[McpErrorCodes.SeedRowsNotAllowed]);
|
||||||
|
|
||||||
|
List<Dictionary<string, JsonElement>>? rows;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rows = JsonSerializer.Deserialize<List<Dictionary<string, JsonElement>>>(json);
|
||||||
|
}
|
||||||
|
catch (JsonException)
|
||||||
|
{
|
||||||
|
rows = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rows is null || rows.Any(row => row is null))
|
||||||
|
throw new UserFriendlyException(L[McpErrorCodes.SeedRowsInvalid]);
|
||||||
|
|
||||||
|
var fields = wizard.Groups.SelectMany(group => group.Items).Select(item => item.FieldName)
|
||||||
|
.Append(wizard.KeyFieldName)
|
||||||
|
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||||
|
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
var unknown = rows.SelectMany(row => row.Keys).Where(key => !fields.Contains(key))
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
|
||||||
|
if (unknown.Count > 0)
|
||||||
|
throw new UserFriendlyException(L[McpErrorCodes.SeedRowsUnknownFields, string.Join(", ", unknown), string.Join(", ", fields)]);
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Demo satirlarini ekranin veri dosyasina (<c>ListForm.SeedFilePath</c>) yazar; veritabanina
|
||||||
|
/// dokunmaz. Migrate ekrani kurduktan sonra <c>ListFormSeedDataApplier</c> satirlari ekler ve
|
||||||
|
/// kiraci/audit alanlarini doldurur. Guid anahtar burada uretilir: dosya her uygulandiginda ayni
|
||||||
|
/// kayda karsilik gelir. Dosyada ayni icerikli satir varsa (tekrar deploy) yeniden eklenmez.
|
||||||
|
/// </summary>
|
||||||
|
private async Task WriteSeedRowsAsync(string fileName, List<Dictionary<string, JsonElement>> rows)
|
||||||
|
{
|
||||||
|
var listForm = (await wizardAppService.GetFile(fileName)).ListForm;
|
||||||
|
var relativePath = listForm?.SeedFilePath?.Replace('\\', '/').Trim('/');
|
||||||
|
if (listForm == null || string.IsNullOrWhiteSpace(relativePath) || SeedPathResolver.IsSeedFolderPath(relativePath))
|
||||||
|
throw new UserFriendlyException(L[McpErrorCodes.SeedRowsNotAllowed]);
|
||||||
|
|
||||||
|
var path = SeedPathResolver.GetScopePath(configuration, CurrentTenant.Id, relativePath.Split('/'));
|
||||||
|
var seedFile = File.Exists(path)
|
||||||
|
? JsonSerializer.Deserialize<ListFormSeedDataFileDto>(await File.ReadAllTextAsync(path), ListFormSeedDataFileDto.JsonOptions)
|
||||||
|
: null;
|
||||||
|
seedFile ??= new ListFormSeedDataFileDto { ListFormCode = listForm.ListFormCode, KeyFieldName = listForm.KeyFieldName };
|
||||||
|
|
||||||
|
var keyFieldName = seedFile.KeyFieldName;
|
||||||
|
var existing = seedFile.Rows.Select(row => RowContent(row, keyFieldName)).ToHashSet(StringComparer.Ordinal);
|
||||||
|
|
||||||
|
foreach (var row in rows)
|
||||||
|
{
|
||||||
|
var values = row.ToDictionary(item => item.Key, item => (object)item.Value);
|
||||||
|
if (!existing.Add(RowContent(values, keyFieldName)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (listForm.KeyFieldDbSourceType == DbType.Guid && !values.Keys.Contains(keyFieldName, StringComparer.OrdinalIgnoreCase))
|
||||||
|
values[keyFieldName] = GuidGenerator.Create();
|
||||||
|
|
||||||
|
seedFile.Rows.Add(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
|
||||||
|
await File.WriteAllTextAsync(path, ListFormSeedDataFileDto.Serialize(seedFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Satirin anahtar disindaki icerigi; tekrar deploy'da ayni satiri tanimak icin.</summary>
|
||||||
|
private static string RowContent(Dictionary<string, object> row, string keyFieldName) =>
|
||||||
|
string.Join('\u001f', row
|
||||||
|
.Where(item => !string.Equals(item.Key, keyFieldName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.OrderBy(item => item.Key, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(item => $"{item.Key.ToLowerInvariant()}={JsonSerializer.Serialize(item.Value)}"));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ekranin tablosu ancak <paramref name="dropTables"/> acikken ve Wizard Manager'daki onayla ayni
|
/// Ekranin tablosu ancak <paramref name="dropTables"/> acikken ve Wizard Manager'daki onayla ayni
|
||||||
/// kosullarda (secilebilir aday) dusurulur; onayi kullanicidan almak istemcinin isidir.
|
/// kosullarda (secilebilir aday) dusurulur; onayi kullanicidan almak istemcinin isidir.
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ public static class McpErrorCodes
|
||||||
public const string DevGuideUnavailable = Prefix + "DevGuideUnavailable";
|
public const string DevGuideUnavailable = Prefix + "DevGuideUnavailable";
|
||||||
public const string DevGuideSectionNotFound = Prefix + "DevGuideSectionNotFound";
|
public const string DevGuideSectionNotFound = Prefix + "DevGuideSectionNotFound";
|
||||||
public const string InvalidWizard = Prefix + "InvalidWizard";
|
public const string InvalidWizard = Prefix + "InvalidWizard";
|
||||||
|
public const string SeedRowsInvalid = Prefix + "SeedRowsInvalid";
|
||||||
|
public const string SeedRowsNotAllowed = Prefix + "SeedRowsNotAllowed";
|
||||||
|
public const string SeedRowsUnknownFields = Prefix + "SeedRowsUnknownFields";
|
||||||
public const string ComponentNameRequired = Prefix + "ComponentNameRequired";
|
public const string ComponentNameRequired = Prefix + "ComponentNameRequired";
|
||||||
public const string ComponentCodeRequired = Prefix + "ComponentCodeRequired";
|
public const string ComponentCodeRequired = Prefix + "ComponentCodeRequired";
|
||||||
public const string ComponentNotFound = Prefix + "ComponentNotFound";
|
public const string ComponentNotFound = Prefix + "ComponentNotFound";
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ internal static class McpServerInfoDefaults
|
||||||
"Agree on screen type, data source, module and permissions with the user before deploying. " +
|
"Agree on screen type, data source, module and permissions with the user before deploying. " +
|
||||||
"Development requests (App.DevRequests) follow get_dev_guide section 0.11: claim each one with " +
|
"Development requests (App.DevRequests) follow get_dev_guide section 0.11: claim each one with " +
|
||||||
"start_dev_request, which only accepts requests in Ready to Start; images pasted into the request arrive as image content and are part of the request (layout and demo rows). " +
|
"start_dev_request, which only accepts requests in Ready to Start; images pasted into the request arrive as image content and are part of the request (layout and demo rows). " +
|
||||||
|
"A request is its own brief: do not ask questions and do not wait for DB Migrate; deploy (demo rows go in deploy_wizard seedRows), move the request to Testing and finish. " +
|
||||||
"When a tool reports a missing permission, tell the user which permission is missing and stop; " +
|
"When a tool reports a missing permission, tell the user which permission is missing and stop; " +
|
||||||
"do not try to reach the same result through another tool.";
|
"do not try to reach the same result through another tool.";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using ModelContextProtocol.Server;
|
using ModelContextProtocol.Server;
|
||||||
|
|
||||||
namespace Sozsoft.Mcp.Tools;
|
namespace Sozsoft.Mcp.Tools;
|
||||||
|
|
@ -20,7 +20,8 @@ public static class McpDevelopPrompts
|
||||||
"Once get_dev_guide ile lowcode 0.11 bolumunu oku ve oradaki adimlari uygula. " +
|
"Once get_dev_guide ile lowcode 0.11 bolumunu oku ve oradaki adimlari uygula. " +
|
||||||
"Talebi start_dev_request ile ustlen. Arac reddederse (talep Ready to Start degil, bulunamadi ya da " +
|
"Talebi start_dev_request ile ustlen. Arac reddederse (talep Ready to Start degil, bulunamadi ya da " +
|
||||||
"birden fazla eslesme var) hicbir sey uretme, baska bir talebe gecme: nedenini bildir ve dur. " +
|
"birden fazla eslesme var) hicbir sey uretme, baska bir talebe gecme: nedenini bildir ve dur. " +
|
||||||
"Sonunda rapor ver: uretilen artefaktlar, verify_wizard sonucu, talebin son durumu.";
|
"Talep tarifin kendisidir: soru sorma, DB Migrate'i bekleme; talebi Testing'e alip bitir. " +
|
||||||
|
"Sonunda rapor ver: uretilen artefaktlar, talebin son durumu ve DB Migrate gerektigi.";
|
||||||
|
|
||||||
[McpServerPrompt(Name = McpPromptNames.ProcessReadyRequests)]
|
[McpServerPrompt(Name = McpPromptNames.ProcessReadyRequests)]
|
||||||
[Description("Ready to Start durumundaki tum gelistirme taleplerini SortOrder sirasiyla isler.")]
|
[Description("Ready to Start durumundaki tum gelistirme taleplerini SortOrder sirasiyla isler.")]
|
||||||
|
|
@ -28,6 +29,6 @@ public static class McpDevelopPrompts
|
||||||
=> "App.DevRequests kuyrugundaki Ready to Start taleplerini query_list ile SortOrder sirasiyla oku ve tek tek isle. " +
|
=> "App.DevRequests kuyrugundaki Ready to Start taleplerini query_list ile SortOrder sirasiyla oku ve tek tek isle. " +
|
||||||
"Once get_dev_guide ile lowcode 0.11 bolumunu oku ve oradaki adimlari uygula. " +
|
"Once get_dev_guide ile lowcode 0.11 bolumunu oku ve oradaki adimlari uygula. " +
|
||||||
"Her talebi start_dev_request ile ustlen; reddedilen talebi atla ve rapora yaz. " +
|
"Her talebi start_dev_request ile ustlen; reddedilen talebi atla ve rapora yaz. " +
|
||||||
"Sonunda parti raporu ver: talep basina uretilen artefaktlar, verify_wizard sonucu, son durum; " +
|
"Talep tarifin kendisidir: soru sorma, DB Migrate'i bekleme; her talebi Testing'e alip digerine gec. " +
|
||||||
"seed_closure uyarisi olan ekranlari ve migrate gerekip gerekmedigini ayrica belirt.";
|
"Sonunda parti raporu ver: talep basina uretilen artefaktlar ve son durum; DB Migrate gerektigini tek satirda belirt.";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,13 +64,15 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService)
|
||||||
=> 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; 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.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; DB Migrate calistiktan sonra (isPending false, verify_wizard gecer) her satiri insert_row ile ekle: satirlar seed klasorundeki data/{ListFormCode}.json dosyasina yazilir ve migrate ile ekranla birlikte geri yuklenir; SeedData olmadan eklenen satir yalnizca bu veritabaninda kalir. replaceFileName verilirse o wizard'in dosyalari yeniden yazilir, onceki kayitlarin yerini migrate'te yenileri alir; ekran wizard cevaplarindan yeniden turetildigi icin tasarimcida yapilmis ve wizard'da karsiligi olmayan ayarlar kaybolur. 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. 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; ekran wizard cevaplarindan yeniden turetildigi icin tasarimcida yapilmis ve wizard'da karsiligi olmayan ayarlar kaybolur. 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\": {...}}, get_wizard cikisi gibi) ya da duz wizard cevaplari. Enum alanlari sayi olarak yazilir.")]
|
[Description("Wizard JSON'u: seed dosyasi bicimi ({\"Wizard\": {...}}, get_wizard cikisi gibi) ya da duz wizard cevaplari. Enum alanlari sayi olarak yazilir.")]
|
||||||
string wizard,
|
string wizard,
|
||||||
[Description("Guncellemede yerine gecilecek dosyanin adi (list_wizards cikisindaki fileName). Yeni wizard icin bos birak.")]
|
[Description("Guncellemede yerine gecilecek dosyanin adi (list_wizards cikisindaki fileName). Yeni wizard icin bos birak.")]
|
||||||
string? replaceFileName = null)
|
string? replaceFileName = null,
|
||||||
=> await developAppService.DeployWizardAsync(new McpWizardDeployRequestDto { Wizard = wizard, ReplaceFileName = replaceFileName });
|
[Description("Demo satirlar: JSON nesne dizisi, anahtarlar ekranin alan adlari ([{\"Name\": \"...\"}]). Guid anahtar, TenantId ve audit alanlarini yazma; sunucu ve migrate doldurur. Yalnizca SeedData true olan liste ekraninda.")]
|
||||||
|
string? seedRows = null)
|
||||||
|
=> await developAppService.DeployWizardAsync(new McpWizardDeployRequestDto { Wizard = wizard, ReplaceFileName = replaceFileName, SeedRows = seedRows });
|
||||||
|
|
||||||
[McpServerTool(Name = McpToolNames.DeleteWizard, Destructive = true, Idempotent = true)]
|
[McpServerTool(Name = McpToolNames.DeleteWizard, Destructive = true, Idempotent = true)]
|
||||||
[Description("Bir wizard'i ve yalnizca onun urettigi kayitlari siler; baska yerde kullanilan kayitlar korunur ve raporda gosterilir. Ekranin veri aynasi (data/{ListFormCode}.json) ekranla birlikte gider. Bagimli wizard'i olan bir wizard silinemez, once bagimlilar silinir. Ekranin tablosu varsayilan olarak kalir; dropTables true ise tablo DROP edilir, CRUD endpoint'leri ve sql/object + crud seed dosyalari da silinir. Tablo yalnizca create_table ya da tablo tasarimcisiyla olusturulmussa (sql/object scripti varsa) ve baska ekran, Custom Endpoint ya da bilesen kullanmiyorsa dusurulur; aksi halde raporda neden korundugu yazar. Tablo silmek geri alinamaz ve App.SqlQueryManager yetkisi ister: dropTables true gondermeden once kullaniciya tablonun ve icindeki verinin silinecegini soyle ve acik onay al.")]
|
[Description("Bir wizard'i ve yalnizca onun urettigi kayitlari siler; baska yerde kullanilan kayitlar korunur ve raporda gosterilir. Ekranin veri aynasi (data/{ListFormCode}.json) ekranla birlikte gider. Bagimli wizard'i olan bir wizard silinemez, once bagimlilar silinir. Ekranin tablosu varsayilan olarak kalir; dropTables true ise tablo DROP edilir, CRUD endpoint'leri ve sql/object + crud seed dosyalari da silinir. Tablo yalnizca create_table ya da tablo tasarimcisiyla olusturulmussa (sql/object scripti varsa) ve baska ekran, Custom Endpoint ya da bilesen kullanmiyorsa dusurulur; aksi halde raporda neden korundugu yazar. Tablo silmek geri alinamaz ve App.SqlQueryManager yetkisi ister: dropTables true gondermeden once kullaniciya tablonun ve icindeki verinin silinecegini soyle ve acik onay al.")]
|
||||||
|
|
@ -82,7 +84,7 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService)
|
||||||
=> await developAppService.DeleteWizardAsync(fileName, dropTables);
|
=> await developAppService.DeleteWizardAsync(fileName, dropTables);
|
||||||
|
|
||||||
[McpServerTool(Name = McpToolNames.VerifyWizard, ReadOnly = true)]
|
[McpServerTool(Name = McpToolNames.VerifyWizard, ReadOnly = true)]
|
||||||
[Description("Deploy edilip DB Migrate ile kurulmus bir wizard'i veri yazmadan dogrular (migrate bekleyen wizard'da install kontrolu basarisiz doner ve diger kontroller yapilmaz): menu kaydi (var mi, etkin mi, URL'si wizard'la ayni mi), menunun istedigi yetki tanimi, liste ekraninda ekranin sorgusu (cagiranin yetkisiyle tek satir), Custom yolunda bilesen (var mi, etkin mi, rotasi menuyle ayni mi) ve seed kapanisi (migrate ya da baska ortamda eksik kalacak bagimlilik). passed yalnizca blocking kontrollerden biri kalirsa false olur; seed_closure engellemez ama raporlanmalidir. deploy_wizard'dan sonra ve bir gelistirme talebini Staging durumuna almadan once cagir.")]
|
[Description("Deploy edilip DB Migrate ile kurulmus bir wizard'i veri yazmadan dogrular (migrate bekleyen wizard'da install kontrolu basarisiz doner ve diger kontroller yapilmaz): menu kaydi (var mi, etkin mi, URL'si wizard'la ayni mi), menunun istedigi yetki tanimi, liste ekraninda ekranin sorgusu (cagiranin yetkisiyle tek satir), Custom yolunda bilesen (var mi, etkin mi, rotasi menuyle ayni mi) ve seed kapanisi (migrate ya da baska ortamda eksik kalacak bagimlilik). passed yalnizca blocking kontrollerden biri kalirsa false olur; seed_closure engellemez ama raporlanmalidir. Istege baglidir: kullanici migrate sonrasi dogrulama isterse cagir; gelistirme talebi dongusunun adimi degildir.")]
|
||||||
public async Task<McpVerifyResultDto> VerifyWizardAsync(
|
public async Task<McpVerifyResultDto> VerifyWizardAsync(
|
||||||
[Description("Dogrulanacak wizard dosyasinin adi (list_wizards ya da deploy_wizard cikisindaki fileName).")]
|
[Description("Dogrulanacak wizard dosyasinin adi (list_wizards ya da deploy_wizard cikisindaki fileName).")]
|
||||||
string fileName)
|
string fileName)
|
||||||
|
|
@ -103,7 +105,7 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService)
|
||||||
=> ToContent(await developAppService.GetDevRequestAsync(request));
|
=> ToContent(await developAppService.GetDevRequestAsync(request));
|
||||||
|
|
||||||
[McpServerTool(Name = McpToolNames.AppendDevRequestNote, Destructive = false, Idempotent = false)]
|
[McpServerTool(Name = McpToolNames.AppendDevRequestNote, Destructive = false, Idempotent = false)]
|
||||||
[Description("Talebin HTML aciklamasinin sonuna ekleme yapar; var olan metne ve gorsellere dokunmaz. Aciklama gomulu gorsel tasidigi icin Description'i update_row ile yeniden yazma, sonuc notunu (<h4>MCP</h4> + verify_wizard ozeti) bu aracla ekle.")]
|
[Description("Talebin HTML aciklamasinin sonuna ekleme yapar; var olan metne ve gorsellere dokunmaz. Aciklama gomulu gorsel tasidigi icin Description'i update_row ile yeniden yazma, sonuc notunu (<h4>MCP</h4> + uretilenler ve DB Migrate bekleyen wizard'lar) bu aracla ekle.")]
|
||||||
public async Task<string> AppendDevRequestNoteAsync(
|
public async Task<string> AppendDevRequestNoteAsync(
|
||||||
[Description("Talebin Id'si (GUID) ya da tam basligi.")]
|
[Description("Talebin Id'si (GUID) ya da tam basligi.")]
|
||||||
string request,
|
string request,
|
||||||
|
|
|
||||||
|
|
@ -454,9 +454,6 @@ public class ListFormSeedDataSynchronizer(
|
||||||
return seedFile;
|
return seedFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task WriteSeedFileAsync(string filePath, ListFormSeedDataFileDto seedFile)
|
private static Task WriteSeedFileAsync(string filePath, ListFormSeedDataFileDto seedFile) =>
|
||||||
{
|
File.WriteAllTextAsync(filePath, ListFormSeedDataFileDto.Serialize(seedFile));
|
||||||
seedFile.GeneratedAt = DateTime.UtcNow;
|
|
||||||
await File.WriteAllTextAsync(filePath, ListFormSeedDataFileDto.Serialize(seedFile));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1029,7 +1029,16 @@ public class ListFormWizardAppService(
|
||||||
var outcome = rows.RemoveOwned(owned, (type, name) => usages.ContainsKey((type, name.ToLowerInvariant())));
|
var outcome = rows.RemoveOwned(owned, (type, name) => usages.ContainsKey((type, name.ToLowerInvariant())));
|
||||||
await rows.SaveAsync();
|
await rows.SaveAsync();
|
||||||
|
|
||||||
return [.. outcome.Select(r => r.Removed
|
// MCP demo satirlari deploy aninda ekranin veri aynasina yazilir; hic kurulmamis ekranin
|
||||||
|
// aynasi onunla gider. Kurulu ekranin aynasi veritabanindaki satirlarin kaydidir, kalir.
|
||||||
|
var mirror = new List<WizardDeleteLogItemDto>();
|
||||||
|
if (seed.Wizard.ComponentKind != WizardComponentKindEnum.Custom &&
|
||||||
|
!await _installationChecker.IsInstalledAsync(false, seed.Wizard.ResolveMenuCode(), seed.Wizard.ResolveListFormCode()))
|
||||||
|
{
|
||||||
|
_recordCleaner.DeleteSeedDataMirror(seed.ListForm?.SeedFilePath, mirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [.. mirror, .. outcome.Select(r => r.Removed
|
||||||
? new WizardDeleteLogItemDto { RecordType = r.Type, Name = r.Name, Status = WizardDeleteStatusEnum.Deleted }
|
? new WizardDeleteLogItemDto { RecordType = r.Type, Name = r.Name, Status = WizardDeleteStatusEnum.Deleted }
|
||||||
: new WizardDeleteLogItemDto
|
: new WizardDeleteLogItemDto
|
||||||
{
|
{
|
||||||
|
|
@ -2223,7 +2232,6 @@ public class ListFormWizardAppService(
|
||||||
}
|
}
|
||||||
|
|
||||||
existingFile.Rows = merged;
|
existingFile.Rows = merged;
|
||||||
existingFile.GeneratedAt = Clock.Now.ToUniversalTime();
|
|
||||||
|
|
||||||
return ImportEncoding.GetBytes(ListFormSeedDataFileDto.Serialize(existingFile));
|
return ImportEncoding.GetBytes(ListFormSeedDataFileDto.Serialize(existingFile));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ public class WizardRecordCleaner(
|
||||||
/// Ekranin veri aynasi (<c>ListForm.SeedFilePath</c>) ekransiz uygulanamaz; ekranla birlikte
|
/// Ekranin veri aynasi (<c>ListForm.SeedFilePath</c>) ekransiz uygulanamaz; ekranla birlikte
|
||||||
/// gider.
|
/// gider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void DeleteSeedDataMirror(string? seedFilePath, List<WizardDeleteLogItemDto> report)
|
public void DeleteSeedDataMirror(string? seedFilePath, List<WizardDeleteLogItemDto> report)
|
||||||
{
|
{
|
||||||
var relativePath = seedFilePath?.Replace('\\', '/').Trim('/');
|
var relativePath = seedFilePath?.Replace('\\', '/').Trim('/');
|
||||||
if (string.IsNullOrWhiteSpace(relativePath) ||
|
if (string.IsNullOrWhiteSpace(relativePath) ||
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,6 @@ public sealed class WizardSeedRowStore
|
||||||
foreach (var listFormCode in dirty)
|
foreach (var listFormCode in dirty)
|
||||||
{
|
{
|
||||||
var (path, file) = files[listFormCode];
|
var (path, file) = files[listFormCode];
|
||||||
file.GeneratedAt = DateTime.UtcNow;
|
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
|
||||||
await File.WriteAllTextAsync(path, ListFormSeedDataFileDto.Serialize(file));
|
await File.WriteAllTextAsync(path, ListFormSeedDataFileDto.Serialize(file));
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ using Sozsoft.Platform.Entities;
|
||||||
using Sozsoft.Platform.Enums;
|
using Sozsoft.Platform.Enums;
|
||||||
using Sozsoft.Platform.ListForms;
|
using Sozsoft.Platform.ListForms;
|
||||||
using Sozsoft.Platform.Localization;
|
using Sozsoft.Platform.Localization;
|
||||||
|
using Sozsoft.Platform.Permissions;
|
||||||
using Sozsoft.Platform.Queries;
|
using Sozsoft.Platform.Queries;
|
||||||
using Volo.Abp.Data;
|
using Volo.Abp.Data;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
|
|
@ -11725,6 +11726,18 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
GroupPanelJson = DefaultGroupPanelJson(),
|
GroupPanelJson = DefaultGroupPanelJson(),
|
||||||
SelectionJson = DefaultSelectionSingleJson,
|
SelectionJson = DefaultSelectionSingleJson,
|
||||||
ColumnOptionJson = DefaultColumnOptionJson(),
|
ColumnOptionJson = DefaultColumnOptionJson(),
|
||||||
|
// MCP talepleri yalnizca seed dosyasi yazar; kurulum icin kuyruktan cikmadan migrate calistirilir.
|
||||||
|
CommandColumnJson = JsonSerializer.Serialize(new CommandColumnDto[] {
|
||||||
|
new() {
|
||||||
|
ButtonPosition = UiCommandButtonPositionTypeEnum.Toolbar,
|
||||||
|
Hint = "App.Platform.StartMessage",
|
||||||
|
Text = "App.ListForm.DbMigrate",
|
||||||
|
AuthName = PlatformPermissions.Setup.Migrate,
|
||||||
|
OnClick = "UiEvalService.ApiDbMigrate();",
|
||||||
|
Icon = "import",
|
||||||
|
IsVisible = true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
PermissionJson = DefaultPermissionJson(listFormName),
|
PermissionJson = DefaultPermissionJson(listFormName),
|
||||||
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.DevRequest)),
|
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.DevRequest)),
|
||||||
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
|
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,11 @@ public class ListFormSeedDataFileDto
|
||||||
/// <summary>Satirlarin eslestigi anahtar alan (ListForm.KeyFieldName).</summary>
|
/// <summary>Satirlarin eslestigi anahtar alan (ListForm.KeyFieldName).</summary>
|
||||||
public string KeyFieldName { get; set; } = string.Empty;
|
public string KeyFieldName { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>Dosyanin en son yazildigi an (UTC) — yalnizca bilgi amaclidir.</summary>
|
/// <summary>
|
||||||
|
/// Dosyanin olusturuldugu an (UTC) — yalnizca bilgi amaclidir. Ilk yazimda <see cref="Serialize"/>
|
||||||
|
/// doldurur, sonraki yazimlar degistirmez: satir ekleyip ayni satiri kaldiran bir islem (wizard
|
||||||
|
/// deploy + silme) dosyayi birebir onceki haline dondurur, git'te iz birakmaz.
|
||||||
|
/// </summary>
|
||||||
public DateTime GeneratedAt { get; set; }
|
public DateTime GeneratedAt { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -48,6 +52,11 @@ public class ListFormSeedDataFileDto
|
||||||
/// kacirilmadan yazilir (<see cref="SeedJsonText"/>) ve dosya depodaki digerleri gibi satir sonuyla
|
/// kacirilmadan yazilir (<see cref="SeedJsonText"/>) ve dosya depodaki digerleri gibi satir sonuyla
|
||||||
/// biter — dosya bastan yazildiginda sahte fark olusmaz.
|
/// biter — dosya bastan yazildiginda sahte fark olusmaz.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Serialize(ListFormSeedDataFileDto file) =>
|
public static string Serialize(ListFormSeedDataFileDto file)
|
||||||
SeedJsonText.RestoreSurrogatePairs(JsonSerializer.Serialize(file, JsonOptions)) + "\n";
|
{
|
||||||
|
if (file.GeneratedAt == default)
|
||||||
|
file.GeneratedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return SeedJsonText.RestoreSurrogatePairs(JsonSerializer.Serialize(file, JsonOptions)) + "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
claude.md
12
claude.md
|
|
@ -241,10 +241,10 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
|
||||||
adım ekleme. Ayrıntı: `lowcode.instructions.md` §4.0.
|
adım ekleme. Ayrıntı: `lowcode.instructions.md` §4.0.
|
||||||
- **MCP ile demo veri** → geliştirme isteği örnek satır taşıyorsa (prompt'taki tablo/liste, ekran
|
- **MCP ile demo veri** → geliştirme isteği örnek satır taşıyorsa (prompt'taki tablo/liste, ekran
|
||||||
görüntüsü) ekran `deploy_wizard`'a `SeedData: true` ile gider (`SeedFilePath = data/{ListFormCode}.json`
|
görüntüsü) ekran `deploy_wizard`'a `SeedData: true` ile gider (`SeedFilePath = data/{ListFormCode}.json`
|
||||||
+ `SeedSync*` açık, `ListFormWizardDto.BuildListForm`); kullanıcı DB Migrate çalıştırıp ekran
|
+ `SeedSync*` açık, `ListFormWizardDto.BuildListForm`) ve satırlar aynı çağrıda `seedRows` ile
|
||||||
kurulduktan sonra (`isPending: false`) satırlar `insert_row` ile eklenir ve
|
`configs/seeds/host/data/{ListFormCode}.json` dosyasına yazılır (`McpDevelopAppService`; alan adları
|
||||||
senkronizasyon onları `configs/seeds/host/data/{ListFormCode}.json` dosyasına yazar; migrate
|
ekrana göre doğrulanır, `Guid` anahtarı sunucu üretir). Migrate ekranı kurar, ardından satırları
|
||||||
ekranla birlikte seed eder. Dosya elle yazılmaz, görselden okunamayan değer uydurulmaz.
|
ekler; MCP migrate'i beklemez. Talep döngüsü `Testing`'de biter, `Staging`'e kullanıcı alır. Dosya elle yazılmaz, görselden okunamayan değer uydurulmaz.
|
||||||
`SeedData` wizard ekranında sorulmaz ama düzenlemede korunur (`RefreshFrom` + UI modeli).
|
`SeedData` wizard ekranında sorulmaz ama düzenlemede korunur (`RefreshFrom` + UI modeli).
|
||||||
Ayrıntı: `lowcode.instructions.md` §0.10.1.
|
Ayrıntı: `lowcode.instructions.md` §0.10.1.
|
||||||
- **Talepteki görsel** → `App.DevRequests` açıklamasına yapıştırılan görsel base64 `data:` URI olarak
|
- **Talepteki görsel** → `App.DevRequests` açıklamasına yapıştırılan görsel base64 `data:` URI olarak
|
||||||
|
|
@ -365,7 +365,9 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
|
||||||
`WizardSeedFileDto.ToSeedJson` ile yazılır; düz `JsonSerializer.Serialize` + `File.WriteAllText`
|
`WizardSeedFileDto.ToSeedJson` ile yazılır; düz `JsonSerializer.Serialize` + `File.WriteAllText`
|
||||||
kullanılmaz. System.Text.Json emojiyi her zaman vekil çift kaçışına çevirir; dosya baştan
|
kullanılmaz. System.Text.Json emojiyi her zaman vekil çift kaçışına çevirir; dosya baştan
|
||||||
yazıldığında bütün emojiler sahte fark üretir. İkisi de `SeedJsonText.RestoreSurrogatePairs`'ten
|
yazıldığında bütün emojiler sahte fark üretir. İkisi de `SeedJsonText.RestoreSurrogatePairs`'ten
|
||||||
geçer.
|
geçer. Veri dosyasının `GeneratedAt` değeri oluşturma anıdır: `Serialize` yalnızca boşsa doldurur,
|
||||||
|
hiçbir yazma yolu onu güncellemez — ekleyip geri kaldıran işlem (wizard deploy + silme) dosyayı
|
||||||
|
birebir önceki hâline döndürür. `crud/` dosyalarının damgası ayrıdır ve karar verir (aşağıda).
|
||||||
- **`crud/{Entity}.json`** → uygulama kuralı `CrudEndpointSeedApplier`'dadır ve damga
|
- **`crud/{Entity}.json`** → uygulama kuralı `CrudEndpointSeedApplier`'dadır ve damga
|
||||||
karşılaştırmalıdır: eksik endpoint eklenir, mevcut kayıt yalnızca dosyanın `GeneratedAt` değeri
|
karşılaştırmalıdır: eksik endpoint eklenir, mevcut kayıt yalnızca dosyanın `GeneratedAt` değeri
|
||||||
kaydın `LastModificationTime`/`CreationTime` değerinden yeniyse güncellenir/silinir. Migrate
|
kaydın `LastModificationTime`/`CreationTime` değerinden yeniyse güncellenir/silinir. Migrate
|
||||||
|
|
|
||||||
|
|
@ -66910,6 +66910,48 @@
|
||||||
"Key": "App.Mcp.Error.InvalidWizard",
|
"Key": "App.Mcp.Error.InvalidWizard",
|
||||||
"Value": "Wizard JSON okunamadı. Seed dosyası biçimini ({\"Wizard\": {...}}) ya da düz wizard cevaplarını gönderin."
|
"Value": "Wizard JSON okunamadı. Seed dosyası biçimini ({\"Wizard\": {...}}) ya da düz wizard cevaplarını gönderin."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Id": "9221bf6b-577c-5d08-a95e-7a22d9fd9c3b",
|
||||||
|
"CultureName": "en",
|
||||||
|
"ResourceName": "Platform",
|
||||||
|
"Key": "App.Mcp.Error.SeedRowsInvalid",
|
||||||
|
"Value": "seedRows could not be read. Send a JSON array of objects that map field names to values."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "bcee973d-f521-5fe6-8fa0-817bc70329e8",
|
||||||
|
"CultureName": "tr",
|
||||||
|
"ResourceName": "Platform",
|
||||||
|
"Key": "App.Mcp.Error.SeedRowsInvalid",
|
||||||
|
"Value": "seedRows okunamadı. Alan adından değere nesnelerden oluşan bir JSON dizisi gönderin."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "8ad5b888-cbbb-5085-838b-5e32f5ac8cef",
|
||||||
|
"CultureName": "en",
|
||||||
|
"ResourceName": "Platform",
|
||||||
|
"Key": "App.Mcp.Error.SeedRowsNotAllowed",
|
||||||
|
"Value": "seedRows can only be used on a list screen (ComponentKind 0) with SeedData true."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "61428bfd-3dad-5c2d-b060-e77b62372685",
|
||||||
|
"CultureName": "tr",
|
||||||
|
"ResourceName": "Platform",
|
||||||
|
"Key": "App.Mcp.Error.SeedRowsNotAllowed",
|
||||||
|
"Value": "seedRows yalnızca SeedData true olan liste ekranında (ComponentKind 0) kullanılabilir."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "412674a3-8458-5b26-b9f3-236cd3ec0f76",
|
||||||
|
"CultureName": "en",
|
||||||
|
"ResourceName": "Platform",
|
||||||
|
"Key": "App.Mcp.Error.SeedRowsUnknownFields",
|
||||||
|
"Value": "seedRows contains fields that are not on the screen: {0}. Screen fields: {1}."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "bb733499-5c0e-5693-aab9-f290dfef9a4e",
|
||||||
|
"CultureName": "tr",
|
||||||
|
"ResourceName": "Platform",
|
||||||
|
"Key": "App.Mcp.Error.SeedRowsUnknownFields",
|
||||||
|
"Value": "seedRows ekranda olmayan alanlar içeriyor: {0}. Ekranın alanları: {1}."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Id": "fe038e1e-68b6-5cfe-ad9e-42c8e58f01bb",
|
"Id": "fe038e1e-68b6-5cfe-ad9e-42c8e58f01bb",
|
||||||
"CultureName": "en",
|
"CultureName": "en",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import type { GridDto, TodoOptionDto } from '@/proxy/form/models'
|
import type { GridDto, TodoOptionDto } from '@/proxy/form/models'
|
||||||
|
import { UiCommandButtonPositionTypeEnum } from '@/proxy/form/models'
|
||||||
import type { IdentityUserDto } from '@/proxy/admin/models'
|
import type { IdentityUserDto } from '@/proxy/admin/models'
|
||||||
import type { DataGridRef } from 'devextreme-react/data-grid'
|
import type { DataGridRef } from 'devextreme-react/data-grid'
|
||||||
import type CustomStore from 'devextreme/data/custom_store'
|
import type CustomStore from 'devextreme/data/custom_store'
|
||||||
|
|
@ -310,6 +311,16 @@ const TodoBoardContent = ({
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
const { checkPermission } = usePermission()
|
const { checkPermission } = usePermission()
|
||||||
const isPwaMode = usePWA()
|
const isPwaMode = usePWA()
|
||||||
|
const toolbarCommands = useMemo(
|
||||||
|
() =>
|
||||||
|
(gridDto.gridOptions.commandColumnDto ?? []).filter(
|
||||||
|
(action) =>
|
||||||
|
action.buttonPosition === UiCommandButtonPositionTypeEnum.Toolbar &&
|
||||||
|
(action.url || action.onClick) &&
|
||||||
|
checkPermission(action.authName),
|
||||||
|
),
|
||||||
|
[gridDto.gridOptions.commandColumnDto, checkPermission],
|
||||||
|
)
|
||||||
const uncategorized = translate('::App.ListFormTodoBoard.Uncategorized')
|
const uncategorized = translate('::App.ListFormTodoBoard.Uncategorized')
|
||||||
|
|
||||||
const lookupValuesForField = useCallback(
|
const lookupValuesForField = useCallback(
|
||||||
|
|
@ -513,6 +524,29 @@ const TodoBoardContent = ({
|
||||||
onClick: refreshData,
|
onClick: refreshData,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{/* Ekranin CommandColumnJson'daki Toolbar butonlari (orn. DB Migrate); Grid/Card ile ayni tanim.
|
||||||
|
Pano satir secimi tasimadigi icin yalnizca satirdan bagimsiz eylemler (Url, OnClick) calisir. */}
|
||||||
|
{toolbarCommands.map((action, index) => (
|
||||||
|
<ToolbarItem
|
||||||
|
key={`${action.text}-${index}`}
|
||||||
|
location="after"
|
||||||
|
widget="dxButton"
|
||||||
|
locateInMenu="auto"
|
||||||
|
showText="always"
|
||||||
|
options={{
|
||||||
|
icon: action.icon,
|
||||||
|
text: translate('::' + action.text),
|
||||||
|
hint: translate('::' + action.hint),
|
||||||
|
onClick: () => {
|
||||||
|
if (action.url) {
|
||||||
|
window.open(action.url, isPwaMode ? '_self' : action.urlTarget)
|
||||||
|
} else if (action.onClick) {
|
||||||
|
eval(action.onClick)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
{checkPermission('App.Listforms.Listform.Update') && (
|
{checkPermission('App.Listforms.Listform.Update') && (
|
||||||
<ToolbarItem
|
<ToolbarItem
|
||||||
location="after"
|
location="after"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue