Md dosyaları düzenleme ve ölü kodlar kaldırıldı

This commit is contained in:
Sedat ÖZTÜRK 2026-09-29 09:14:07 +03:00
parent ae226d359b
commit 677a62bd79
11 changed files with 148 additions and 118 deletions

View file

@ -362,8 +362,10 @@ MCP (`/mcp`, `Sozsoft.Mcp` module) — expose ListForm data/queries to an extern
(Claude, ChatGPT, or an OAuth-registered MCP client) without new code: configure a server row (Claude, ChatGPT, or an OAuth-registered MCP client) without new code: configure a server row
on the **MCP Servers** screen (`App.DeveloperKit.McpServers`, §12.2 of on the **MCP Servers** screen (`App.DeveloperKit.McpServers`, §12.2 of
`lowcode-reference.instructions.md`) with its allowed tools and tenant scope; queries always run `lowcode-reference.instructions.md`) with its allowed tools and tenant scope; queries always run
on the calling tenant's own database. Tenant users are read-only over MCP (schema tools, on the calling tenant's own database. Tenant users read and write data over MCP but cannot develop
`query_list`, `run_select`); writing and development tools are host-only. A (`McpToolNames.TenantTools`: schema tools, `query_list`, `run_select`, `insert_row`/`update_row`/`delete_row`
— row writes go through the screen's C/U/D contract and need `.Write`); development tools,
`list_queries` and `run_query` are host-only. A
request to "let an agent query/update X" is a Decision Flow §1 (ListForm) request first — MCP request to "let an agent query/update X" is a Decision Flow §1 (ListForm) request first — MCP
only gates which of the existing screens/queries an already-authorized client may reach; it only gates which of the existing screens/queries an already-authorized client may reach; it
never grants access beyond the calling user's own ListForm/query permissions. Ayrıntı: never grants access beyond the calling user's own ListForm/query permissions. Ayrıntı:
@ -879,7 +881,7 @@ Default is `List`, so older seed files that lack it keep working.
| Kind | Produces | Menu URL | Child permissions | | Kind | Produces | Menu URL | Child permissions |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `List` | ListForm + ListFormFields + Route + Menu + Permissions + language keys | `/admin/list/{ListFormCode}` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | `List` | ListForm + ListFormFields + Menu + Permissions + language keys (no Route record; the generic `/admin/list/{code}` route serves it) | `/admin/list/{ListFormCode}` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
| `Custom` | Menu + Permissions + language keys; the screen is the selected Custom Component | the component's `RoutePath` | `.Create`, `.Update`, `.Delete` only | | `Custom` | Menu + Permissions + language keys; the screen is the selected Custom Component | the component's `RoutePath` | `.Create`, `.Update`, `.Delete` only |
`Export` / `Import` / `Note` exist only in the ListForm ecosystem. Never propose them on the `Export` / `Import` / `Note` exist only in the ListForm ecosystem. Never propose them on the
@ -891,7 +893,7 @@ embedded elsewhere as a SubGrid/part. Default is `true`.
### 32.4 Permission group selection ### 32.4 Permission group selection
The wizard's permission group comes from a select list backed by `GetWizardPermissionGroups`. The wizard's permission group comes from a select list backed by `ListFormWizardAppService.GetPermissionGroups` (`/api/app/list-form-wizard/permission-groups`).
Display names are read from the language key whose name equals the group name. Display names are read from the language key whose name equals the group name.
- Selecting an existing group fills `PermissionGroupEn/Tr` (seed file: `Language.PermissionGroupEn/Tr`); - Selecting an existing group fills `PermissionGroupEn/Tr` (seed file: `Language.PermissionGroupEn/Tr`);

View file

@ -31,7 +31,7 @@ Kural:
- Nullable, proje bazında ve bilinçli olarak açılır (`<Nullable>enable</Nullable>`). - Nullable, proje bazında ve bilinçli olarak açılır (`<Nullable>enable</Nullable>`).
Şu an açık olanlar: `Sozsoft.Platform.Application`, `Sozsoft.Notifications.*`, Şu an açık olanlar: `Sozsoft.Platform.Application`, `Sozsoft.Notifications.*`,
test projeleri. `Sozsoft.Mcp.*`, test projeleri.
- **Entity taşıyan projelerde** (`*.Domain`) nullable açılacaksa, aynı PR'da - **Entity taşıyan projelerde** (`*.Domain`) nullable açılacaksa, aynı PR'da
`dotnet ef migrations add` çıktısı gözden geçirilir; şema değişikliği isteniyorsa `dotnet ef migrations add` çıktısı gözden geçirilir; şema değişikliği isteniyorsa
kabul edilir, istenmiyorsa kolon zorunluluğu `PlatformDbContext` içinde kabul edilir, istenmiyorsa kolon zorunluluğu `PlatformDbContext` içinde

View file

@ -482,7 +482,8 @@ ya da ziyaretçiye açık yeni bir fiziksel sayfa ürettiğinde.
**Genel varsayılanlar kayıtta değil ayardadır:** site adresi, site adı, varsayılan başlık ve **Genel varsayılanlar kayıtta değil ayardadır:** site adresi, site adı, varsayılan başlık ve
açıklama, paylaşım görseli, Twitter hesabı, diller, robots yönergesi, Google doğrulaması, açıklama, paylaşım görseli, Twitter hesabı, diller, robots yönergesi, Google doğrulaması,
sosyal hesaplar ve sitemap anahtarı `App.SiteManagement.Seo.*` ayarlarındadır sosyal hesaplar, varsayılan anahtar kelimeler (`DefaultKeywords`), sitemap anahtarı (`SitemapEnabled`) ve
sitemap dışı yollar (`SitemapExcludePaths`) `App.SiteManagement.Seo.*` ayarlarındadır
(`configs/seeds/host/data/App.SettingDefinitions.json`). Bir değer bütün site için geçerliyse (`configs/seeds/host/data/App.SettingDefinitions.json`). Bir değer bütün site için geçerliyse
oraya yazılır, her yola tekrarlanmaz. Site kökü (`/`) hiçbir kayıt taşımaz; doğrudan bu oraya yazılır, her yola tekrarlanmaz. Site kökü (`/`) hiçbir kayıt taşımaz; doğrudan bu
varsayılanlardan beslenir. varsayılanlardan beslenir.
@ -605,7 +606,8 @@ talebin metnini döndürür. Başlık birden fazla talebe uyuyorsa Id ister. `St
- `Timesheets` — **sunucu yazar, model hiçbir şey yapmaz.** `get_dev_request` / `start_dev_request` - `Timesheets` — **sunucu yazar, model hiçbir şey yapmaz.** `get_dev_request` / `start_dev_request`
talebi kullanıcının etkin talebi yapar; ardından yapılan her MCP yazma işlemi (`create_table`, talebi kullanıcının etkin talebi yapar; ardından yapılan her MCP yazma işlemi (`create_table`,
`deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, `insert_row` / `deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, `insert_row` /
`update_row` / `delete_row`, `save_dev_request_analysis`) o talebe bir satır ekler `update_row` / `delete_row`, `save_dev_request_analysis`, `append_dev_request_note`,
`add_dev_request_subtasks`) o talebe bir satır ekler
(`IMcpDevRequestTimesheetRecorder`). Açıklama `App.Mcp.Timesheet.*` dil anahtarından **Türkçe** (`IMcpDevRequestTimesheetRecorder`). Açıklama `App.Mcp.Timesheet.*` dil anahtarından **Türkçe**
üretilir ("Hr_T_Doctor tablosu oluşturuldu"), süre önceki satırdan ya da talebin açıldığı andan bu üretilir ("Hr_T_Doctor tablosu oluşturuldu"), süre önceki satırdan ya da talebin açıldığı andan bu
yana ölçülür (en az 1 dakika, saat olarak), çalışan bağlanan kullanıcı, tarih bugündür. yana ölçülür (en az 1 dakika, saat olarak), çalışan bağlanan kullanıcı, tarih bugündür.
@ -901,7 +903,7 @@ hiçbir şey silmez**. Tek çıktısı seed dosyalarıdır:
| `wizard/{WizardName}.json` | Ekranın `ListForm`/`Fields` sözleşmesi, wizard cevapları, `InsertedRecords`, `Pending` | | `wizard/{WizardName}.json` | Ekranın `ListForm`/`Fields` sözleşmesi, wizard cevapları, `InsertedRecords`, `Pending` |
| `data/App.Menus.Module.json`, `data/App.Menus.Menu.json` | Modül, üst menü, ekranın menüsü | | `data/App.Menus.Module.json`, `data/App.Menus.Menu.json` | Modül, üst menü, ekranın menüsü |
| `data/Abp.Identity.PermissionGroups.json`, `data/Abp.Identity.Permissions.json` | İzin grubu, okuma yetkisi ve alt yetkileri | | `data/Abp.Identity.PermissionGroups.json`, `data/Abp.Identity.Permissions.json` | İzin grubu, okuma yetkisi ve alt yetkileri |
| `data/App.Languages.LanguageText.json` | Menü, başlık, açıklama, grup ve alan başlıklarının EN + TR metinleri (`Id` iş anahtarından v5 GUID, `SeedRowIds.LanguageText`) | | `data/App.Languages.LanguageText.json` | Menü, başlık, açıklama, grup, alan başlıkları ve `Language.Texts` anahtarlarının (widget başlıkları) EN + TR metinleri (`Id` iş anahtarından v5 GUID, `SeedRowIds.LanguageText`) |
Satırları `WizardSeedRowStore` yazar; anahtarlar `WizardSeedRowKeys`'ten gelir (export aynı Satırları `WizardSeedRowStore` yazar; anahtarlar `WizardSeedRowKeys`'ten gelir (export aynı
listeyle toplar). **Sahiplik:** bir satır ne veritabanında ne dosyada varsa ya da önceki sürüm ona listeyle toplar). **Sahiplik:** bir satır ne veritabanında ne dosyada varsa ya da önceki sürüm ona
@ -942,7 +944,8 @@ sürümünü taşır.
"Menu": { "MenuCode": "…", "MenuOrder": 2, "MenuUrl": "…", "MenuIcon": "…", "Menu": { "MenuCode": "…", "MenuOrder": 2, "MenuUrl": "…", "MenuIcon": "…",
"MenuParentPath": [ { "Code": "…", "Icon": "…", "En": "…", "Tr": "…" } ], // yalnızca derin yolda "MenuParentPath": [ { "Code": "…", "Icon": "…", "En": "…", "Tr": "…" } ], // yalnızca derin yolda
"MenuParentCode": "…", "MenuParentIcon": "…" }, // "CreateMenu": false ise eklenir "MenuParentCode": "…", "MenuParentIcon": "…" }, // "CreateMenu": false ise eklenir
"Language": { "MenuEn": "…", /* Menu/Title/Desc/MenuParent/PermissionGroup · EN + TR */ }, "Language": { "MenuEn": "…", /* Menu/Title/Desc/MenuParent/PermissionGroup · EN + TR */
"Texts": [ { "Key": "…", "En": "…", "Tr": "…" } ] }, // Texts yalnızca doluysa
"Groups": [ { "Items": [ { "FieldName": "…", "CaptionName": "…", "Groups": [ { "Items": [ { "FieldName": "…", "CaptionName": "…",
"En": "…", "Tr": "…" } ] } ] // grup Caption/ColCount yok "En": "…", "Tr": "…" } ] } ] // grup Caption/ColCount yok
}, },
@ -993,7 +996,7 @@ düzenleme izinleri, görünüm option blokları, alt formlar, widget'lar, iş a
Dosyada wizard alanları üç başlık altında toplanır — `Menu` (menü kaydı), `Language` (dil Dosyada wizard alanları üç başlık altında toplanır — `Menu` (menü kaydı), `Language` (dil
metinleri), `Groups` (alan başlıklarının dil karşılıkları); geri kalanı kök seviyededir. metinleri), `Groups` (alan başlıklarının dil karşılıkları); geri kalanı kök seviyededir.
Gruplama ile `ListFormCode → WizardCode` ve `MenuParentModuleId → ModuleId` adlandırmaları Gruplama ile `ListFormCode → WizardCode`, `MenuParentModuleId → ModuleId` ve `LanguageTexts → Language.Texts` adlandırmaları
yalnızca **dosya biçimidir**; C# yalnızca **dosya biçimidir**; C#
sözleşmesi (`ListFormWizardDto`) düzdür ve dosya okunurken düzleştirilir sözleşmesi (`ListFormWizardDto`) düzdür ve dosya okunurken düzleştirilir
(`WizardSeedFileDto.FromSeedJson` ↔ `ToSeedJson`). Aşağıdaki tablolar C# alan adlarını kullanır. (`WizardSeedFileDto.FromSeedJson` ↔ `ToSeedJson`). Aşağıdaki tablolar C# alan adlarını kullanır.
@ -1671,8 +1674,9 @@ Silme ucu (`DeleteFile`) her kaydın akıbetini (`Deleted` / `Kept` + kullananla
Düzenleme (`EditFileName`) bu sınıfı çağırmaz; önceki sürümün kayıtlarını migrate kaldırır (§4.0). Düzenleme (`EditFileName`) bu sınıfı çağırmaz; önceki sürümün kayıtlarını migrate kaldırır (§4.0).
Wizard'ın yarattığı modül `InsertedRecords.ModuleIds` ile izlenir. Wizard'ın yarattığı modül `InsertedRecords.ModuleIds` ile izlenir.
Silme yolunda ekranın veri aynası (`ListForm.SeedFilePath` → `data/{ListFormCode}.json` ya da Kurulu wizard silinirken ekranın veri aynası (`ListForm.SeedFilePath` → `data/{ListFormCode}.json` ya da
klasörü) ekranla birlikte silinir; ekransız uygulanamaz. klasörü) ekranla birlikte silinir; ekransız uygulanamaz. Migrate bekleyen wizard'da ayna yalnızca ekran
hiç kurulmamışsa silinir (MCP demo satırları); kurulu ekranın aynası veritabanındaki satırların kaydıdır, kalır.
**Ekranın tablosu** wizard'ın ürettiği bir kayıt değildir (tasarımcı ya da `create_table` ile **Ekranın tablosu** wizard'ın ürettiği bir kayıt değildir (tasarımcı ya da `create_table` ile
ayrıca kurulur, `InsertedRecords`'ta yoktur) ve **kendiliğinden silinmez**. Silme onayı önce ayrıca kurulur, `InsertedRecords`'ta yoktur) ve **kendiliğinden silinmez**. Silme onayı önce
@ -2124,8 +2128,9 @@ opsiyonel `ApprovalDateFieldName`, `ApprovalDescriptionFieldName`, `ApprovalIsFi
dönsün). Onay düğümleri (`Criteria`) görsel akış tasarımcısında kurulur ve `ListFormWorkflow` dönsün). Onay düğümleri (`Criteria`) görsel akış tasarımcısında kurulur ve `ListFormWorkflow`
kayıtlarına gider (§4.7). kayıtlarına gider (§4.7).
**Adım 12 — Deploy.** Sol tarafta tüm adımların özeti, sağda üretim log'u. Üretim sırası — **Adım 12 — Deploy.** Sol tarafta tüm adımların özeti, sağda üretim log'u. Log, deploy'un seed
seed dosyası uygulanırken `WizardDataSeeder`'ın izlediği sıranın aynısıdır: dosyalarına yazdığı bölümleri sırayla gösterir; migrate'te `WizardDataSeeder` ekrana özgü kayıtları,
ardından `ListFormSeedDataApplier` menü/yetki/dil satırlarını kurar (§4.0):
1. Konfigürasyon doğrulama 1. Konfigürasyon doğrulama
2. Menü kaydı (`CreateMenu: false` ise atlanır) 2. Menü kaydı (`CreateMenu: false` ise atlanır)
@ -2134,10 +2139,11 @@ seed dosyası uygulanırken `WizardDataSeeder`'ın izlediği sıranın aynısıd
5. List yolunda: veri kaynağı → ListForm → alan grupları · Custom yolunda: bileşen bağlama 5. List yolunda: veri kaynağı → ListForm → alan grupları · Custom yolunda: bileşen bağlama
6. Deploy + tamamlandı 6. Deploy + tamamlandı
Başarıda sihirbaz `/admin/list/{ListFormCode}`'a yönlendirir ve seed dosyası Başarıda sihirbaz "Migrate bekliyor" bildirimiyle Wizard Manager'a döner (ekran henüz kurulu
`configs/seeds/{kapsam}/wizard/` altına yazılmış olur. **Düzenleme modu** Wizard Manager'dan değildir; DB Migrate ile kurulur) ve seed dosyası `configs/seeds/{kapsam}/wizard/` altına yazılmış
`EditFileName` ile açılır: aynı adımlar dolu gelir, kaydetmede önce eski dosya ve olur. **Düzenleme modu** Wizard Manager'dan `EditFileName` ile açılır: aynı adımlar dolu gelir,
`InsertedRecords` kayıtları silinir (§4.5). kaydetmede dosyalar cevaptan yeniden yazılır; önceki sürümün kayıtları `Pending.Replaced`'a alınır,
veritabanına dokunulmaz — kaldırma ve yeniden kurulum DB Migrate'tedir (§4.0).
--- ---
@ -2471,7 +2477,7 @@ Preset mevcut JSON ile **birleşir**, diğer ayarları silmez; aynı anahtar var
| TagBox anında seçim | `showSelectionControls`, `applyValueMode:instantly`, `searchEnabled` | | TagBox anında seçim | `showSelectionControls`, `applyValueMode:instantly`, `searchEnabled` |
| GridBox tek/çok seçim | `columns`, `selectionMode`, `filterRowVisible`, `height`, `width` | | GridBox tek/çok seçim | `columns`, `selectionMode`, `filterRowVisible`, `height`, `width` |
| Çoklu görsel | `width`, `height`, `multiple`, `accept:image/*` | | Çoklu görsel | `width`, `height`, `multiple`, `accept:image/*` |
| HTML tam araç çubuğu | `toolbar.items` (tam liste), `toolbar.multiline`, `mediaResizing`, `imageUpload` | | HTML tam araç çubuğu | `htmlEditorOptions.ts` varsayılanı: `toolbar.items` (tam liste), `toolbar.multiline`, `mediaResizing`, `imageUpload` (`tabs: file/url`, base64), `tableResizing`, `tableContextMenu` — boş `editorOptions` da aynı varsayılanı alır |
| Yükseklik 100 / 200 | `{"height":100}` · `{"height":200}` | | Yükseklik 100 / 200 | `{"height":100}` · `{"height":200}` |
| Barkod okutma butonu | `buttons[]` — kamera ikonlu buton; `onClick` = `"@SCAN_BARCODE"` token'ı. Yalnız `dxTextBox`. Token'ı `editingForm.ts` kamera diyaloğuna bağlar, okunan kod alana yazılır. HTTPS şart. | | Barkod okutma butonu | `buttons[]` — kamera ikonlu buton; `onClick` = `"@SCAN_BARCODE"` token'ı. Yalnız `dxTextBox`. Token'ı `editingForm.ts` kamera diyaloğuna bağlar, okunan kod alana yazılır. HTTPS şart. |
| Kamerayla foto çek | `{"accept":"image/*","capture":"environment"}` — yalnız `dxImageUpload`. Mobilde dosya seçici yerine **yalnızca** kamera açılır (`user` = ön kamera); masaüstünde yok sayılır. Ayarlanmazsa dokunmatik cihazda dosya seçicinin yanına ayrı bir kamera butonu gelir, yani ikisi birden kullanılabilir — bu kalıp kamerayı **zorunlu** kılmak içindir. | | Kamerayla foto çek | `{"accept":"image/*","capture":"environment"}` — yalnız `dxImageUpload`. Mobilde dosya seçici yerine **yalnızca** kamera açılır (`user` = ön kamera); masaüstünde yok sayılır. Ayarlanmazsa dokunmatik cihazda dosya seçicinin yanına ayrı bir kamera butonu gelir, yani ikisi birden kullanılabilir — bu kalıp kamerayı **zorunlu** kılmak içindir. |
@ -2489,7 +2495,7 @@ Preset mevcut JSON ile **birleşir**, diğer ayarları silmez; aynı anahtar var
| Telefon | `EditorOptions.Phone()` | global format + maske + örnek | | Telefon | `EditorOptions.Phone()` | global format + maske + örnek |
| Kaydırıcı | `EditorOptions.Slider()` | `{"tooltip":{"enabled":true}}` | | Kaydırıcı | `EditorOptions.Slider()` | `{"tooltip":{"enabled":true}}` |
| Görsel yükleme | `EditorOptions.ImageUpload(multiple: true, 80, 80)` | | | Görsel yükleme | `EditorOptions.ImageUpload(multiple: true, 80, 80)` | |
| Zengin metin | `EditorOptions.Html(240)` | tam araç çubuğu + `encodeHtml` | | Zengin metin | `EditorOptions.Html(240)` | `htmlEditorOptions.ts` varsayılanıyla aynı bloklar (tam araç çubuğu, `imageUpload`, `mediaResizing`, `tableResizing`, `tableContextMenu`; biri değişirse diğeri de değişir) + `encodeHtml` + `elementAttr` `min-height:240px` (sabit yükseklik değil; içerikle büyür) |
Akıcı ekler: `.Placeholder()`, `.MaxLength()`, `.Height(int\|string)`, `.Width(int\|string)`, Akıcı ekler: `.Placeholder()`, `.MaxLength()`, `.Height(int\|string)`, `.Width(int\|string)`,
`.Format()`, `.FixedPointFormat(p)`, `.DisplayFormat()`, `.DateSerializationFormat()`, `.Format()`, `.FixedPointFormat(p)`, `.DisplayFormat()`, `.DateSerializationFormat()`,

View file

@ -533,7 +533,7 @@ eskisi gibi çalışır.
| `ComponentKind` | Üretilen | Menü URL'i | Yetkiler | | `ComponentKind` | Üretilen | Menü URL'i | Yetkiler |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `List` | ListForm + ListFormField + Route + Menu + Permission + dil anahtarları | `/admin/list/{ListFormCode}` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` | | `List` | ListForm + ListFormField (+ iş akışı) + Menu + Permission + dil anahtarları (rota üretilmez; genel `/admin/list/{ListFormCode}` rotası kullanılır) | `/admin/list/{ListFormCode}` | `.Create`, `.Update`, `.Delete`, `.Export`, `.Import`, `.Note` |
| `Custom` | Menü + Permission + dil anahtarları; ekran seçilen Custom Component'tir | Component'in `RoutePath` değeri | Yalnızca `.Create`, `.Update`, `.Delete` (Export/Import/Note ListForm'a özgüdür) | | `Custom` | Menü + Permission + dil anahtarları; ekran seçilen Custom Component'tir | Component'in `RoutePath` değeri | Yalnızca `.Create`, `.Update`, `.Delete` (Export/Import/Note ListForm'a özgüdür) |
**Menüsüz wizard (`CreateMenu = false`).** Menü (ve gerekiyorsa üst menü) kaydı hiç üretilmez; **Menüsüz wizard (`CreateMenu = false`).** Menü (ve gerekiyorsa üst menü) kaydı hiç üretilmez;
@ -542,7 +542,7 @@ ekranda SubGrid/parça olarak kullanılmak üzere tanımlanır. Alan varsayılan
alanı taşımayan eski seed dosyaları etkilenmez. alanı taşımayan eski seed dosyaları etkilenmez.
**İzin grubu seçimi.** Menü adımında izin grubu bir seçim listesinden gelir **İzin grubu seçimi.** Menü adımında izin grubu bir seçim listesinden gelir
(`GetWizardPermissionGroups`). Görünen adlar, grup adıyla aynı olan dil anahtarının metinlerinden (`ListFormWizardAppService.GetPermissionGroups`, `/api/app/list-form-wizard/permission-groups`). Görünen adlar, grup adıyla aynı olan dil anahtarının metinlerinden
okunur; seçim yapıldığında `PermissionGroupEn/Tr` forma doldurulur. Yeni bir grup okunur; seçim yapıldığında `PermissionGroupEn/Tr` forma doldurulur. Yeni bir grup
tanımlanırsa grup adıyla aynı dil anahtarına bu metinler yazılır; mevcut grup seçilip alanlar boş tanımlanırsa grup adıyla aynı dil anahtarına bu metinler yazılır; mevcut grup seçilip alanlar boş
bırakılırsa sunucu veritabanındaki değeri geri yazar. Böylece seed dosyası her durumda iki dilli bırakılırsa sunucu veritabanındaki değeri geri yazar. Böylece seed dosyası her durumda iki dilli
@ -556,12 +556,15 @@ Var olan bir ekranı düzenlemek için `/admin/listform/edit/{listFormCode}` —
yapılandırması sekmeli bir editörde yönetilir (Veritabanı, Sütunlar, Filtreler, Düzenleme, yapılandırması sekmeli bir editörde yönetilir (Veritabanı, Sütunlar, Filtreler, Düzenleme,
Yetkiler, Alt Form, Pivot, Tree, Gantt, Scheduler, Todo, Widget, Workflow, Durum, Grafik sekmeleri). Yetkiler, Alt Form, Pivot, Tree, Gantt, Scheduler, Todo, Widget, Workflow, Durum, Grafik sekmeleri).
**Wizard File Manager** (`/admin/listform/wizard` liste ekranı) üretilmiş seed dosyalarını yönetir: **Wizard File Manager** (`/admin/listform/wizardManager`; sihirbazın kendisi `/admin/listform/wizard`) üretilmiş seed dosyalarını yönetir:
liste/kart görünümü arasında geçiş (tercih diğer listelerle aynı yerde, `admin.lists.states` liste/kart görünümü arasında geçiş (tercih diğer listelerle aynı yerde, `admin.lists.states`
altında saklanır), arama, düzenleme (dosyanın yerine geçen yeni bir çalıştırma), silme, veritabanı altında saklanır), arama, düzenleme (dosyanın yerine geçen yeni bir çalıştırma), silme, veritabanı
migrate tetikleme, dışa aktarma ve içe aktarma. Liste, wizard'ın ilk deploy damgasına migrate tetikleme, dışa aktarma ve içe aktarma. Liste, wizard'ın ilk deploy damgasına
(`Wizard.SeededAt`) göre **tersine** sıralıdır — en son üretilen ekran en üstte durur; damgası (`Wizard.SeededAt`) göre **tersine** sıralıdır — en son üretilen ekran en üstte durur; damgası
okunamayan dosyalar sona düşer. Butonlar `App.Listforms.Wizard.*` yetkileriyle gizlenir; asıl okunamayan dosyalar sona düşer. Silme, bağlı wizard'ı olan dosyada reddedilir; onay diyaloğu önce
`DeleteAnalysis` ile düşürülebilecek tabloyu sorar, sonuç her kaydın akıbetiyle (`Deleted` / `Kept` +
kullananlar / `NotFound`) rapor olarak gösterilir (`WizardRecordCleaner`, `WizardTableCleaner`;
`lowcode.instructions.md` §4.5). Butonlar `App.Listforms.Wizard.*` yetkileriyle gizlenir; asıl
kontrol `ListFormWizardAppService` üzerindedir. kontrol `ListFormWizardAppService` üzerindedir.
### 7.7. İçe/dışa aktarma ### 7.7. İçe/dışa aktarma
@ -869,8 +872,8 @@ tıklamak seçim yapar, sayfayı değiştirmez — tıklama yakalama evresinde d
**Diğer notlar.** `PlatformIcon` tasarımcı dokümanındaki ikon adını çözer; `selectComponents.ts` **Diğer notlar.** `PlatformIcon` tasarımcı dokümanındaki ikon adını çözer; `selectComponents.ts`
`Select.componentAs` için saklanan adı (`ReactSelect`, `CreatableSelect`, `AsyncSelect`) gerçek `Select.componentAs` için saklanan adı (`ReactSelect`, `CreatableSelect`, `AsyncSelect`) gerçek
bileşene çevirir — kanvas ve üretilen bileşenin aynı adı aynı şekilde yorumlamasını sağlayan tek bileşene çevirir — kanvas ve üretilen bileşenin aynı adı aynı şekilde yorumlamasını sağlayan tek
nokta budur. Yeni bileşen `configs/seeds/host/data/App.DeveloperKit.CustomComponents/{Id}.json` nokta budur. Yeni bileşen `configs/seeds/host/data/App.DeveloperKit.CustomComponents/` klasöründe
içindeki bir satır olarak başlar. kendi `{Id}.json` satır dosyası olarak başlar.
**Dinamik servis yaşam döngüsü:** `DynamicServiceCompiler` kodu derler → **Dinamik servis yaşam döngüsü:** `DynamicServiceCompiler` kodu derler →
`DynamicAssemblyRegistrationService` assembly'yi tenant bağlamıyla kaydeder → `DynamicAssemblyRegistrationService` assembly'yi tenant bağlamıyla kaydeder →
@ -917,8 +920,9 @@ kendi aralarında 1'den. `PlatformPermissionAppService` sıralama anahtarını k
zincirinden kurar, böylece çocuk her zaman ebeveyninin altında kalır. Değerler seed dosyalarındaki zincirinden kurar, böylece çocuk her zaman ebeveyninin altında kalır. Değerler seed dosyalarındaki
`Order` alanında tutulur ve Permissions / Permission Groups ekranlarından düzenlenebilir. `Order` alanında tutulur ve Permissions / Permission Groups ekranlarından düzenlenebilir.
Wizard deploy'u yeni grubu ve grubun yeni kök yetkisini (seed satırı olarak) veritabanı ile seed Wizard deploy'u yeni grubu ve grubun yeni kök yetkisini (seed satırı olarak) veritabanı ile seed
dosyasındaki kardeşlerin en büyük sırasının bir fazlasıyla, alt yetkileri Create/Update/Delete/Export/Import/Note dizilimiyle dosyasındaki kardeşlerin en büyük sırasının bir fazlasıyla, alt yetkileri `WizardSeedRowKeys.ChildPermissions` dizilimiyle
1'den yazar (`NextPermissionOrder`, `AbpPermissionsExtensions`). (List: Create/Update/Delete/Export/Import/Note, Custom: Create/Update/Delete) 1'den yazar
(`ListFormWizardAppService.WritePermissionGroupAsync` / `WritePermissionRowsAsync`).
Aksiyon yetkisi olan alt gruplar (UI tarafındaki karşılıkları `constants/permission.constant.ts` Aksiyon yetkisi olan alt gruplar (UI tarafındaki karşılıkları `constants/permission.constant.ts`
içindedir; oradaki kontroller yalnızca butonları gizler, asıl kontrol AppService'lerdedir): içindedir; oradaki kontroller yalnızca butonları gizler, asıl kontrol AppService'lerdedir):
@ -948,7 +952,7 @@ içindedir; oradaki kontroller yalnızca butonları gizler, asıl kontrol AppSer
| **Sozsoft.MailQueue** | Şablon (Scriban) tabanlı gövde üretimi, ek dosya yaşam döngüsü, kuyruk çalıştırma ve günlükleme. | | **Sozsoft.MailQueue** | Şablon (Scriban) tabanlı gövde üretimi, ek dosya yaşam döngüsü, kuyruk çalıştırma ve günlükleme. |
| **Sozsoft.Sender** | Amazon SES (mail), Posta Güvercini (SMS), WhatsApp Cloud API, Rocket.Chat göndericileri. | | **Sozsoft.Sender** | Amazon SES (mail), Posta Güvercini (SMS), WhatsApp Cloud API, Rocket.Chat göndericileri. |
| **Sozsoft.SqlQueryManager** | SQL nesne yönetimi, sorgu çalıştırma, tablo/kolon metadata'sı. | | **Sozsoft.SqlQueryManager** | SQL nesne yönetimi, sorgu çalıştırma, tablo/kolon metadata'sı. |
| **Sozsoft.Mcp** | MCP (Model Context Protocol) sunucusu: `/mcp` Streamable HTTP ucu, kiracı bazlı araç seti, şema keşfi, sorgu, veri yazma ve (host) tablo/ekran/bileşen geliştirme. Kiracı kullanıcısı yalnızca veri okur. Bkz. §13.9. | | **Sozsoft.Mcp** | MCP (Model Context Protocol) sunucusu: `/mcp` Streamable HTTP ucu, kiracı bazlı araç seti, şema keşfi, sorgu, veri yazma ve (host) tablo/ekran/bileşen geliştirme. Kiracı kullanıcısı veri okur ve ekranın C/U/D sözleşmesinden geçerek satır yazar; geliştirme araçları yalnızca host'tadır. Bkz. §13.9. |
### 10.2. Uygulama servisleri (`api/src/Sozsoft.Platform.Application`) ### 10.2. Uygulama servisleri (`api/src/Sozsoft.Platform.Application`)
@ -1003,7 +1007,7 @@ DeveloperKit > Custom Components (Visual Designer) üzerinden değişir. Aynı y
ile paylaşan custom component kazanır; karşılığı olan dosyası bulunmayan rota kaydı ise hiç ile paylaşan custom component kazanır; karşılığı olan dosyası bulunmayan rota kaydı ise hiç
yüklenmez (`hasPhysicalComponent`) — seeder yalnızca eklediği için eski kayıtlar veritabanında yüklenmez (`hasPhysicalComponent`) — seeder yalnızca eklediği için eski kayıtlar veritabanında
kalsa bile ekran patlamaz. Seed: `configs/seeds/host/data/App.DeveloperKit.CustomComponents/{Id}.json`; kalsa bile ekran patlamaz. Seed: `configs/seeds/host/data/App.DeveloperKit.CustomComponents/{Id}.json`;
bileşenin ayrı dosyası yoktur, her bileşen bu dosyada bir satırdır. ekran klasör modundadır, her bileşen kendi satır dosyasındadır (dosya adı satırın `Id`'si).
Runtime kapsamı sınırlıdır: bileşen kodundaki `import` satırları derlemede temizlenir, Runtime kapsamı sınırlıdır: bileşen kodundaki `import` satırları derlemede temizlenir,
kullanılabilenler `React`, `ui` kit, `PlatformViewHost`, `apiService`, `axios`, `DOMPurify`, kullanılabilenler `React`, `ui` kit, `PlatformViewHost`, `apiService`, `axios`, `DOMPurify`,
@ -1089,7 +1093,7 @@ Veriden beslenen public sayfalar (`/products`, `/checkout`, `/payment`, `/succes
| Parça | Nerede | Ne taşır | | Parça | Nerede | Ne taşır |
| --- | --- | --- | | --- | --- | --- |
| Genel varsayılanlar | `App.SiteManagement.Seo.*` ayarları (Ayarlar ekranı, yetki `App.SiteManagement.Seo`) | Site adresi, site adı, varsayılan başlık/açıklama/paylaşım görseli, Twitter hesabı, diller, robots yönergesi, Google doğrulaması, sosyal hesaplar, sitemap anahtarı | | Genel varsayılanlar | `App.SiteManagement.Seo.*` ayarları (Ayarlar ekranı, yetki `App.SiteManagement.Seo`) | Site adresi, site adı, varsayılan başlık/açıklama/paylaşım görseli, Twitter hesabı, diller, robots yönergesi, Google doğrulaması, sosyal hesaplar, varsayılan anahtar kelimeler (`DefaultKeywords`), sitemap anahtarı (`SitemapEnabled`), sitemap dışı yollar (`SitemapExcludePaths`) |
| Yol bazlı alanlar | Yolu tanımlayan kaydın `Seo*` kolonları: `Route` (`Sas_H_Route`, ekran **Menü Yönetimi › Route**) ve `CustomComponent` (`Sas_H_CustomComponent`, ekran **DeveloperKit › Custom Components**) | Yolun başlığı, açıklaması, anahtar kelimeleri, paylaşım görseli, kanonik adresi, `SeoNoIndex`, sitemap davranışı ve ek JSON-LD | | Yol bazlı alanlar | Yolu tanımlayan kaydın `Seo*` kolonları: `Route` (`Sas_H_Route`, ekran **Menü Yönetimi › Route**) ve `CustomComponent` (`Sas_H_CustomComponent`, ekran **DeveloperKit › Custom Components**) | Yolun başlığı, açıklaması, anahtar kelimeleri, paylaşım görseli, kanonik adresi, `SeoNoIndex`, sitemap davranışı ve ek JSON-LD |
| İstemci | `components/shared/SeoHead.tsx` | `title`, `description`, `robots`, `canonical`, `og:`/`twitter:` kartı, `og:locale:alternate` ve JSON-LD | | İstemci | `components/shared/SeoHead.tsx` | `title`, `description`, `robots`, `canonical`, `og:`/`twitter:` kartı, `og:locale:alternate` ve JSON-LD |
@ -1109,7 +1113,11 @@ Sayfanın kendi `SeoHead`'i, kabuğun (`PublicLayout`) `fallback` kaydını her
`sitemap.xml` ve `robots.txt` aynı servisten üretilir (`SeoController`, anonim). Sitemap'in `sitemap.xml` ve `robots.txt` aynı servisten üretilir (`SeoController`, anonim). Sitemap'in
kaynakları: `Pub` menüleri, aktif custom component rotaları, yayınlanmış blog yazıları ve kaynakları: `Pub` menüleri, aktif custom component rotaları, yayınlanmış blog yazıları ve
yolu tanımlayan kayıtların `Seo*` alanları; `/admin` yolları, parametreli rotalar (`/blog/:id`) ve yolu tanımlayan kayıtların `Seo*` alanları; `/admin` yolları, parametreli rotalar (`/blog/:id`) ve
`SeoNoIndex` işaretli yollar elenir. Arama motorları bu iki dosyayı **sitenin** kök dizininde aradığı için UI sunucusu her iki `SeoNoIndex` işaretli ya da `SeoIncludeInSitemap = false` olan yollar elenir.
`App.SiteManagement.Seo.SitemapExcludePaths` (satır başına bir yol, sonu `*` ise önek) hem sitemap'ten
düşer hem `robots.txt`'e `Disallow` olarak yazılır; `robots.txt` ayrıca `/admin/`, `/auth/`,
`/checkout`, `/payment`, `/success` yollarını her zaman kapatır. `SitemapEnabled` kapalıyken
`sitemap.xml` 404 döner ve robots'a `Sitemap:` satırı yazılmaz. Arama motorları bu iki dosyayı **sitenin** kök dizininde aradığı için UI sunucusu her iki
yolu da API'ye geçirir (`vite.config.ts` > `seoProxy`, hem `server` hem `preview`); ayrı bir ters yolu da API'ye geçirir (`vite.config.ts` > `seoProxy`, hem `server` hem `preview`); ayrı bir ters
vekil kuralı gerekmez. `VITE_API_URL` tanımlı değilse proxy kurulmaz ve `ui/public/robots.txt` vekil kuralı gerekmez. `VITE_API_URL` tanımlı değilse proxy kurulmaz ve `ui/public/robots.txt`
içindeki statik varsayılan geçerli kalır. içindeki statik varsayılan geçerli kalır.
@ -1276,21 +1284,23 @@ Bildirimin tamamı Administration menüsünde `App.Administration.Notifications`
**Bildirim Türleri**, **Bildirim Kuralları**, **Bildirimler**, **Bildirim Şablonları**. Grup **Bildirim Türleri**, **Bildirim Kuralları**, **Bildirimler**, **Bildirim Şablonları**. Grup
Agenda'nın üstündedir; Saas altında bildirim ekranı **yoktur**. Agenda'nın üstündedir; Saas altında bildirim ekranı **yoktur**.
Tablolar kiracı kapsamındadır (`Adm_T_NotificationType`, `Adm_T_NotificationRule`, Tablolar kiracı kapsamındadır (`Adm_T_NotificationTemplate`, `Adm_T_NotificationType`,
`Adm_T_Notification`; üçü de `IMultiTenant`). Her kiracı kendi türünü, kuralını ve kuyruğunu `Adm_T_NotificationRule`, `Adm_T_Notification`; dördü de `IMultiTenant`). Her kiracı kendi türünü, kuralını ve kuyruğunu
görür; host kaydı (`TenantId = null`) yalnızca host oturumunda görünür. Yeni bir kiracı görür; host kaydı (`TenantId = null`) yalnızca host oturumunda görünür. Yeni bir kiracı
oluşturulduğunda varsayılan tür ve kural kümesi o kiracıya kopyalanır oluşturulduğunda varsayılan tür ve kural kümesi o kiracıya kopyalanır
(`NotificationTenantDefaultsSeedContributor`): kaynak host kapsamındaki (`NotificationTenantDefaultsSeedContributor`): kaynak host kapsamındaki
`data/App.Notifications.Notification{Types,Rules}.json` dosyalarıdır, satırlar **yeni `data/App.Notifications.Notification{Types,Rules}.json` dosyalarıdır, satırlar **yeni
kimliklerle** yazılır ve eşleşme ad üzerinden yapıldığı için ikinci çalıştırma bir şey eklemez. kimliklerle** yazılır ve eşleşme ad üzerinden yapıldığı için ikinci çalıştırma bir şey eklemez;
şablonlar kopyalanmaz.
**Bildirimler** ekranı (`App.Notifications.Notification`) hem kuyruk günlüğü hem gönderim **Bildirimler** ekranı (`App.Notifications.Notification`) hem kuyruk günlüğü hem gönderim
ekranıdır: liste kural motorunun ürettiklerini de gösterir, ekleme formu ise elle gönderimdir. ekranıdır: liste kural motorunun ürettiklerini de gösterir, ekleme formu ise elle gönderimdir.
Ayrı bir manuel gönderim kaydı yoktur — gönderimin kaydı bildirimin kendisidir. Ekleme anında Ayrı bir manuel gönderim kaydı yoktur — gönderimin kaydı bildirimin kendisidir. Ekleme anında
yazma işi `list-form-dynamic-api/notification-insert` ucuna gider (`InsertServiceAddress`); uç yazma işi `list-form-dynamic-api/notification-insert` ucuna gider (`InsertServiceAddress`); uç
seçilen alıcı × kanal açılımını `INotificationManager.SendManualNotificationAsync` ile kuyruğa seçilen alıcı × kanal açılımını `INotificationManager.SendManualNotificationAsync` ile kuyruğa
yazar — yani Bildirim Kuralları ekranındaki elle gönderimle **aynı yol**, tek fark alıcı yazar. Bildirim Kuralları ekranındaki `CreateNotification` diyaloğu ise aynı yöneticinin
kümesinin kurallardan değil ekrandan gelmesi. Güncelleme kapalıdır, silme kaydı kaldırır. `SendNotificationAsync` yolunu kullanır: türün kurallarını işletir ve kullanıcı tercihini dikkate
alır; bu uç alıcıyı ekrandan alır ve tercihi okumaz. Güncelleme kapalıdır, silme kaydı kaldırır.
Formdaki `NotificationChannel` ve `UserId` alanları listede tek değerlidir (her satır bir Formdaki `NotificationChannel` ve `UserId` alanları listede tek değerlidir (her satır bir
alıcı × kanal), formda `dxTagBox` ile çoklu seçilir; tipli DTO yolunda çoklu değeri alıcı × kanal), formda `dxTagBox` ile çoklu seçilir; tipli DTO yolunda çoklu değeri
@ -1414,12 +1424,14 @@ liste süzgeci ve çağrı kapısı aynı kuralı kullanır.
| `save_dev_request_analysis` | `Backlog` ya da `Analysis` durumundaki talebin analizini (HTML) `Analysis` kolonuna yazar — var olanı değiştirir — ve talebi `Analysis` durumuna alır; diğer durumları reddeder. `Description`'a dokunmaz. Analizin standardı `lowcode.instructions.md` §0.12. `.Write` + `App.DevRequests.Update` ister. | | `save_dev_request_analysis` | `Backlog` ya da `Analysis` durumundaki talebin analizini (HTML) `Analysis` kolonuna yazar — var olanı değiştirir — ve talebi `Analysis` durumuna alır; diğer durumları reddeder. `Description`'a dokunmaz. Analizin standardı `lowcode.instructions.md` §0.12. `.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. | | `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. |
| `append_dev_request_note` | Talebin `Analysis` kolonunun sonuna HTML ekler (üretim sonuç notu); `Description` talebin yazıldığı hâliyle kalır. İkisi de `update_row` ile yazılmaz — açıklama base64 görsel taşır. `.Write` + `App.DevRequests.Update` ister. | | `append_dev_request_note` | Talebin `Analysis` kolonunun sonuna HTML ekler (üretim sonuç notu); `Description` talebin yazıldığı hâliyle kalır. İkisi de `update_row` ile yazılmaz — açıklama base64 görsel taşır. `.Write` + `App.DevRequests.Update` ister. |
| `list_components` / `get_component` / `save_component` / `delete_component` | Custom component'ler `ICustomComponentAppService` üzerinden; seed senkronu ve `DataSources` çözümü aynen çalışır. `save_component` ada göre ekler/günceller, tasarımcı belgesi (`Props.visualDesigner`, `sourceMode ≠ code`) taşıyan bileşene kod yazmayı reddeder — kod belgeden üretildiği için tasarımcıdaki ilk kayıtta ezilirdi. |
**Timesheets.** Talebin `Timesheets` listesini sunucu doldurur (`IMcpDevRequestTimesheetRecorder`): **Timesheets.** Talebin `Timesheets` listesini sunucu doldurur (`IMcpDevRequestTimesheetRecorder`):
`get_dev_request` / `start_dev_request` talebi kullanıcının etkin talebi yapar (dağıtık önbellek, `get_dev_request` / `start_dev_request` talebi kullanıcının etkin talebi yapar (dağıtık önbellek,
`McpDevRequestActivityCacheItem`, 12 saat); sonraki her MCP yazma işlemi (`create_table`, `McpDevRequestActivityCacheItem`, 12 saat); sonraki her MCP yazma işlemi (`create_table`,
`deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, satır araçları, `deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, satır araçları,
`save_dev_request_analysis`) o talebe bir satır ekler. Açıklama `App.Mcp.Timesheet.*` anahtarından `save_dev_request_analysis`, `append_dev_request_note`, `add_dev_request_subtasks`) o talebe bir satır
ekler; talebi açan `start_dev_request` yazmaz. Açıklama `App.Mcp.Timesheet.*` anahtarından
Türkçe üretilir, süre önceki satırdan ya da talebin açıldığı andan ölçülür (en az 1 dakika, saat Türkçe üretilir, süre önceki satırdan ya da talebin açıldığı andan ölçülür (en az 1 dakika, saat
olarak), çalışan bağlanan kullanıcı, tarih bugündür. Etkin talep yoksa satır yazılmaz; bozuk bir olarak), çalışan bağlanan kullanıcı, tarih bugündür. Etkin talep yoksa satır yazılmaz; bozuk bir
`Timesheets` değeri işlemi geri almaz, yalnızca satır atlanır ve log'a düşer. `Timesheets` değeri işlemi geri almaz, yalnızca satır atlanır ve log'a düşer.
@ -1454,7 +1466,6 @@ değilse sunucu reddeder ve hiçbir şey üretilmez.
başlıkta komut yerine Id ya da düz metin kullan. Başlık birden fazla talebe uyuyorsa sunucu Id ister. başlıkta komut yerine Id ya da düz metin kullan. Başlık birden fazla talebe uyuyorsa sunucu Id ister.
- Düz metin de aynı yoldan geçer: sunucu talimatları modeli `start_dev_request`'e yönlendirir, - Düz metin de aynı yoldan geçer: sunucu talimatları modeli `start_dev_request`'e yönlendirir,
durum şartı yine sunucuda uygulanır. durum şartı yine sunucuda uygulanır.
| `list_components` / `get_component` / `save_component` / `delete_component` | Custom component'ler `ICustomComponentAppService` üzerinden; seed senkronu ve `DataSources` çözümü aynen çalışır. `save_component` ada göre ekler/günceller, tasarımcı belgesi (`Props.visualDesigner`, `sourceMode ≠ code`) taşıyan bileşene kod yazmayı reddeder — kod belgeden üretildiği için tasarımcıdaki ilk kayıtta ezilirdi. |
**Yetki modeli: MCP yetki vermez.** Kullanıcı MCP'de uygulamadaki yetkisini taşır; MCP'nin iki **Yetki modeli: MCP yetki vermez.** Kullanıcı MCP'de uygulamadaki yetkisini taşır; MCP'nin iki
yetkisi yalnızca kapıdır. Bir çağrı üç katmandan geçer ve her katman ayrı reddeder: yetkisi yalnızca kapıdır. Bir çağrı üç katmandan geçer ve her katman ayrı reddeder:
@ -1471,7 +1482,7 @@ yetkisi yalnızca kapıdır. Bir çağrı üç katmandan geçer ve her katman ay
| Yetki | Kim alabilir | Ne açar | Açmadığı / sınırı | | Yetki | Kim alabilir | Ne açar | Açmadığı / sınırı |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `App.DeveloperKit.McpServers` | Host, kiracı | MCP Servers ekranını görme (`.Create/.Update/.Delete/.Export/.Import` ekran işlemleri) | `/mcp` ucuna erişim vermez | | `App.DeveloperKit.McpServers` | Host, kiracı | MCP Servers ekranını görme (`.Create/.Update/.Delete/.Export/.Import` ekran işlemleri) | `/mcp` ucuna erişim vermez |
| `App.DeveloperKit.McpServers.Invoke` | Host, kiracı | `/mcp` bağlantısı ve bütün okuma araçları: `server_info`, `list_lists`, `describe_list`, `search_schema`, `query_list`; host'ta ayrıca `get_dev_guide`, `list_wizards`, `get_wizard`, `verify_wizard`, `list_components`, `get_component` | Hiçbir şey yazmaz. Okuma da ekran yetkisine bağlıdır: `R` yetkisi olmayan liste görünmez, sorgulanamaz. Ham SQL (`run_select`, `list_queries`, `run_query`) ayrıca `App.SqlQueryManager` ister | | `App.DeveloperKit.McpServers.Invoke` | Host, kiracı | `/mcp` bağlantısı ve bütün okuma araçları: `server_info`, `list_lists`, `describe_list`, `search_schema`, `query_list`; host'ta ayrıca `get_dev_guide`, `list_wizards`, `get_wizard`, `verify_wizard`, `get_dev_request`, `list_components`, `get_component` | Hiçbir şey yazmaz. Okuma da ekran yetkisine bağlıdır: `R` yetkisi olmayan liste görünmez, sorgulanamaz. Ham SQL (`run_select`, `list_queries`, `run_query`) ayrıca `App.SqlQueryManager` ister |
| `App.DeveloperKit.McpServers.Write` | Host, kiracı | MCP üzerinden her değişiklik. **Kiracıda:** `insert_row`, `update_row`, `delete_row`. **Host'ta:** bunlara ek olarak `create_table`, `deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, `start_dev_request`, `save_dev_request_analysis`, `append_dev_request_note`, `add_dev_request_subtasks` | Kendi başına bir şey yazdırmaz: satır araçları ekranın `C`/`U`/`D` yetkisini, geliştirme araçları Wizard / Custom Components / SQL Query Manager / `App.DevRequests.Update` yetkisini ayrıca ister. Kiracıda geliştirme araçlarını **açmaz** — kiracı bağlamında bu araçlar yetkiden bağımsız kapalıdır (`McpToolNames.TenantTools`). `Invoke` olmadan işe yaramaz | | `App.DeveloperKit.McpServers.Write` | Host, kiracı | MCP üzerinden her değişiklik. **Kiracıda:** `insert_row`, `update_row`, `delete_row`. **Host'ta:** bunlara ek olarak `create_table`, `deploy_wizard`, `delete_wizard`, `save_component`, `delete_component`, `start_dev_request`, `save_dev_request_analysis`, `append_dev_request_note`, `add_dev_request_subtasks` | Kendi başına bir şey yazdırmaz: satır araçları ekranın `C`/`U`/`D` yetkisini, geliştirme araçları Wizard / Custom Components / SQL Query Manager / `App.DevRequests.Update` yetkisini ayrıca ister. Kiracıda geliştirme araçlarını **açmaz** — kiracı bağlamında bu araçlar yetkiden bağımsız kapalıdır (`McpToolNames.TenantTools`). `Invoke` olmadan işe yaramaz |
**Araç → gereken yetkiler** (Invoke hepsinde aranır, tabloda tekrar yazılmadı) **Araç → gereken yetkiler** (Invoke hepsinde aranır, tabloda tekrar yazılmadı)
@ -1960,7 +1971,7 @@ configs/seeds/
│ │ # Abp.Identity.Permission{Groups,s}.json — yetki tanımları │ │ # Abp.Identity.Permission{Groups,s}.json — yetki tanımları
│ │ # App.Definitions.{CountryGroup,Country,City,District}.json — adres zinciri │ │ # App.Definitions.{CountryGroup,Country,City,District}.json — adres zinciri
│ │ # App.Definitions.{Currency,ContactTitle,AiBot}.json — para birimi, hitap, AI bot │ │ # App.Definitions.{Currency,ContactTitle,AiBot}.json — para birimi, hitap, AI bot
│ │ # App.Notifications.Notification{Types,Rules}.json — bildirim tipi → kuralı │ │ # App.Notifications.Notification{Templates,Types,Rules}.json — bildirim şablonu, tipi → kuralı
│ │ # App.Languages.{Language,LanguageText}.json — dil → metin (eksik LanguageKey metinle üretilir) │ │ # App.Languages.{Language,LanguageText}.json — dil → metin (eksik LanguageKey metinle üretilir)
│ │ # App.SettingDefinitions.json, App.BackgroundWorkers.RecurringJobs.json — ayar tanımları, zamanlanmış işler │ │ # App.SettingDefinitions.json, App.BackgroundWorkers.RecurringJobs.json — ayar tanımları, zamanlanmış işler
│ ├── sql/{object,execute}/ # .sql (SQL Server) │ ├── sql/{object,execute}/ # .sql (SQL Server)
@ -1970,8 +1981,9 @@ configs/seeds/
``` ```
> Bu dosyalar elle de düzenlenebilir; ilgili ekrandan tekrar kaydedildiğinde yeniden üretilirler. > Bu dosyalar elle de düzenlenebilir; ilgili ekrandan tekrar kaydedildiğinde yeniden üretilirler.
> Wizard dosyası `EditFileName` ile güncellenirse sunucu önce eski dosyayı ve ürettiği kayıtları > Wizard dosyası `EditFileName` ile güncellenirse deploy veritabanına dokunmaz: dosyalar cevaptan
> siler, sonra yenisini üretir. Wizard'ın ürettiği ekran **ListForm detayından** düzenlendiğinde > yeniden yazılır (ad değiştiyse eski dosya silinir), önceki sürümün kayıtları `Pending.Replaced`'a
> alınır ve DB Migrate onları kaldırıp ekranı yeniden kurar (`lowcode.instructions.md` §4.0). Wizard'ın ürettiği ekran **ListForm detayından** düzenlendiğinde
> de aynı dosya güncellenir (`WizardSeedSynchronizer`): `ListForm`/`Fields` bölümleri ve > de aynı dosya güncellenir (`WizardSeedSynchronizer`): `ListForm`/`Fields` bölümleri ve
> `Wizard` bölümündeki karşılıkları veritabanındaki güncel haliyle değiştirilir. > `Wizard` bölümündeki karşılıkları veritabanındaki güncel haliyle değiştirilir.

View file

@ -448,6 +448,7 @@ public class McpDevelopAppService(
var devRequest = await FindDevRequestAsync(request); var devRequest = await FindDevRequestAsync(request);
devRequest.Analysis = string.Concat(devRequest.Analysis, html.Trim()); devRequest.Analysis = string.Concat(devRequest.Analysis, html.Trim());
await devRequestRepository.UpdateAsync(devRequest, autoSave: true); await devRequestRepository.UpdateAsync(devRequest, autoSave: true);
await timesheetRecorder.RecordAsync(McpTimesheetTexts.AppendNote);
} }
/// <summary> /// <summary>
@ -497,6 +498,7 @@ public class McpDevelopAppService(
devRequest.SubTasks = subTasks.ToJsonString(); devRequest.SubTasks = subTasks.ToJsonString();
await devRequestRepository.UpdateAsync(devRequest, autoSave: true); await devRequestRepository.UpdateAsync(devRequest, autoSave: true);
await timesheetRecorder.RecordAsync(McpTimesheetTexts.AddSubTasks, items.Count);
} }
private static McpDevRequestDto ToDto(DevRequest devRequest) private static McpDevRequestDto ToDto(DevRequest devRequest)

View file

@ -9,6 +9,8 @@ public static class McpTimesheetTexts
private const string Prefix = "App.Mcp.Timesheet."; private const string Prefix = "App.Mcp.Timesheet.";
public const string Analysis = Prefix + "Analysis"; public const string Analysis = Prefix + "Analysis";
public const string AppendNote = Prefix + "AppendNote";
public const string AddSubTasks = Prefix + "AddSubTasks";
public const string CreateTable = Prefix + "CreateTable"; public const string CreateTable = Prefix + "CreateTable";
public const string DeployWizard = Prefix + "DeployWizard"; public const string DeployWizard = Prefix + "DeployWizard";
public const string DeleteWizard = Prefix + "DeleteWizard"; public const string DeleteWizard = Prefix + "DeleteWizard";

View file

@ -80,71 +80,57 @@ public static class EditorOptions
/// <remarks> /// <remarks>
/// <c>height</c> verilirse editor sabitlenir ve icerik kaydirilir; <c>min-height</c> ise /// <c>height</c> verilirse editor sabitlenir ve icerik kaydirilir; <c>min-height</c> ise
/// en az yuksekligi korurken yeni satirlarla buyumesine izin verir. /// en az yuksekligi korurken yeni satirlarla buyumesine izin verir.
/// Bloklar UI'daki <c>htmlEditorOptions.ts</c> varsayilaniyla birebir aynidir: istemci ic ice
/// bloklari tek seviye birlestirdigi icin buradaki <c>toolbar</c> varsayilanin yerine gecer.
/// </remarks> /// </remarks>
public static EditorOptionsBuilder Html(int minHeight = 200) public static EditorOptionsBuilder Html(int minHeight = 200)
=> New() => New()
.Raw("mediaResizing", "{\"enabled\":true}")
.Raw("imageUpload", "{\"tabs\":[\"file\",\"url\"],\"fileUploadMode\":\"base64\"}")
.Raw("toolbar", "{\"multiline\":true,\"items\":[" + string.Join(",", HtmlToolbarItems()) + "]}") .Raw("toolbar", "{\"multiline\":true,\"items\":[" + string.Join(",", HtmlToolbarItems()) + "]}")
.Raw("imageUpload", "{\"tabs\":[\"file\",\"url\"],\"fileUploadMode\":\"base64\"}")
.Raw("mediaResizing", "{\"enabled\":true}")
.Raw("tableResizing", "{\"enabled\":true}")
.Raw("tableContextMenu", "{\"enabled\":true}")
.Flag("encodeHtml", true) .Flag("encodeHtml", true)
.Raw("elementAttr", "{\"style\":\"min-height:" + EditorJson.Number(minHeight) + "px\"}"); .Raw("elementAttr", "{\"style\":\"min-height:" + EditorJson.Number(minHeight) + "px\"}");
private static IEnumerable<string> HtmlToolbarItems() private static readonly string[] HtmlToolbarNames =
{ [
var fontSizes = new[] { "8pt", "10pt", "12pt", "14pt", "18pt", "24pt", "36pt" }; "undo", "redo", "separator",
var fontFamilies = new[] "header", "size", "font", "separator",
{ "bold", "italic", "underline", "strike", "superscript", "subscript", "separator",
"Arial", "Courier New", "Georgia", "Impact", "color", "background", "separator",
"Lucida Console", "Tahoma", "Times New Roman", "Verdana" "alignLeft", "alignCenter", "alignRight", "alignJustify", "separator",
}; "orderedList", "bulletList", "decreaseIndent", "increaseIndent", "separator",
"blockquote", "codeBlock", "link", "image", "separator",
"insertTable", "insertHeaderRow", "insertRowAbove", "insertRowBelow", "deleteRow",
"insertColumnLeft", "insertColumnRight", "deleteColumn", "cellProperties", "tableProperties", "deleteTable",
"separator", "clear"
];
yield return Item("undo"); private static readonly string[] HtmlFontSizes = ["8pt", "10pt", "12pt", "14pt", "18pt", "24pt", "36pt"];
yield return Item("redo");
yield return Item("separator"); private static readonly string[] HtmlFontFamilies =
yield return Picker("size", fontSizes, "Font size"); [
yield return Picker("font", fontFamilies, "Font family"); "Arial", "Courier New", "Georgia", "Impact",
yield return Item("separator"); "Lucida Console", "Segoe UI", "Tahoma", "Times New Roman", "Verdana"
yield return Item("bold"); ];
yield return Item("italic");
yield return Item("strike"); private static readonly string[] HtmlHeaderValues = ["false", "1", "2", "3", "4", "5", "6"];
yield return Item("underline");
yield return Item("separator"); private static IEnumerable<string> HtmlToolbarItems()
yield return Item("alignLeft"); => HtmlToolbarNames.Select(name => name switch
yield return Item("alignCenter"); {
yield return Item("alignRight"); "size" => Picker(name, HtmlFontSizes.Select(EditorJson.Quote), "Font size"),
yield return Item("alignJustify"); "font" => Picker(name, HtmlFontFamilies.Select(EditorJson.Quote), "Font family"),
yield return Item("separator"); "header" => Picker(name, HtmlHeaderValues, "Header"),
yield return Item("orderedList"); _ => Item(name)
yield return Item("bulletList"); });
yield return Item("separator");
yield return "{\"name\":\"header\",\"acceptedValues\":[false,1,2,3,4,5]}";
yield return Item("separator");
yield return Item("color");
yield return Item("background");
yield return Item("separator");
yield return Item("link");
yield return Item("image");
yield return Item("separator");
yield return Item("clear");
yield return Item("codeBlock");
yield return Item("blockquote");
yield return Item("separator");
yield return Item("insertTable");
yield return Item("deleteTable");
yield return Item("insertRowAbove");
yield return Item("insertRowBelow");
yield return Item("deleteRow");
yield return Item("insertColumnLeft");
yield return Item("insertColumnRight");
yield return Item("deleteColumn");
yield return Item("cellProperties");
yield return Item("tableProperties");
}
private static string Item(string name) => "{\"name\":" + EditorJson.Quote(name) + "}"; private static string Item(string name) => "{\"name\":" + EditorJson.Quote(name) + "}";
/// <summary><paramref name="values"/> JSON olarak yazilmis degerlerdir (metin tirnakli, sayi/bool ciplak).</summary>
private static string Picker(string name, IEnumerable<string> values, string ariaLabel) private static string Picker(string name, IEnumerable<string> values, string ariaLabel)
=> "{\"name\":" + EditorJson.Quote(name) + => "{\"name\":" + EditorJson.Quote(name) +
",\"acceptedValues\":[" + string.Join(",", values.Select(EditorJson.Quote)) + "]" + ",\"acceptedValues\":[" + string.Join(",", values) + "]" +
",\"options\":{\"inputAttr\":{\"aria-label\":" + EditorJson.Quote(ariaLabel) + "}}}"; ",\"options\":{\"inputAttr\":{\"aria-label\":" + EditorJson.Quote(ariaLabel) + "}}}";
} }

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.PermissionManagement; using Volo.Abp.PermissionManagement;
@ -49,20 +48,5 @@ public static class AbpPermissionsExtensions
.Distinct() .Distinct()
.ToArray(); .ToArray();
} }
/// <summary>
/// Yetki ekranindaki sira (<see cref="PlatformConsts.Permissions.Order"/>) kardesler arasindadir;
/// yeni kayit en buyuk kardes sirasinin bir fazlasini alir, kardes yoksa 1. Bos birakilan sira
/// 0 olur ve kayit listenin en ustune cikar.
/// </summary>
public static int NextPermissionOrder(this IEnumerable<IHasExtraProperties> siblings)
{
return siblings.Select(s => s.GetProperty<int>(PlatformConsts.Permissions.Order)).DefaultIfEmpty(0).Max() + 1;
}
public static void SetPermissionOrder(this IHasExtraProperties record, int order)
{
record.SetProperty(PlatformConsts.Permissions.Order, order);
}
} }

View file

@ -176,14 +176,19 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
- **`scriptRecipes.ts` (TS) ↔ `Domain.Shared/Editors/*.cs`** — biri değişirse diğeri de değişir. - **`scriptRecipes.ts` (TS) ↔ `Domain.Shared/Editors/*.cs`** — biri değişirse diğeri de değişir.
İkisinin çıktısı **birebir aynı** olmak zorundadır; aksi hâlde seeder ile basılan script İkisinin çıktısı **birebir aynı** olmak zorundadır; aksi hâlde seeder ile basılan script
dialogda "elle düzenlenmiş" sayılır ve kural editörü kapanır. dialogda "elle düzenlenmiş" sayılır ve kural editörü kapanır.
- **`htmlEditorOptions.ts` ↔ `EditorOptions.Html`** — HtmlEditor varsayılanı iki yerde yazılır ve
bloklar birebir aynıdır. İstemci iç içe blokları tek seviye birleştirdiği için seed edilen
`toolbar` varsayılanın yerine geçer; biri değişip diğeri değişmezse seed'li ekranlar eski araç
çubuğunu gösterir.
- **Wizard seed dosyasında tekrar yok** → `Wizard` bölümü yalnızca ekrandan üretilemeyen bilgileri - **Wizard seed dosyasında tekrar yok** → `Wizard` bölümü yalnızca ekrandan üretilemeyen bilgileri
taşır. `ListForm`/`Fields` içinde karşılığı olan her alan (veri kaynağı, select, anahtar alan, taşır. `ListForm`/`Fields` içinde karşılığı olan her alan (veri kaynağı, select, anahtar alan,
kırılım/düzen/düzenleme bayrakları, görünüm option blokları, alt form, widget, iş akışı, alan kırılım/düzen/düzenleme bayrakları, görünüm option blokları, alt form, widget, iş akışı, alan
tanımları) dosyaya yazılmadan çıkarılır (`WizardSeedFileDto.ToSeedJson`) ve okurken geri tanımları) dosyaya yazılmadan çıkarılır (`WizardSeedFileDto.ToSeedJson`) ve okurken geri
doldurulur (`FromSeedJson`). Wizard'a yeni bir alan eklerken karşılığı ListForm'da varsa listeye ekle. doldurulur (`FromSeedJson`). Wizard'a yeni bir alan eklerken karşılığı ListForm'da varsa listeye ekle.
Dosyada kalan wizard alanları üç başlık altında toplanır — `Menu`, `Language`, `Groups` — ve Dosyada kalan wizard alanları üç başlık altında toplanır — `Menu`, `Language`, `Groups` — ve
`ListFormCode` → `WizardCode`, `MenuParentModuleId` → `ModuleId` adıyla yazılır; varsayılanı olan `ListFormCode` → `WizardCode`, `MenuParentModuleId` → `ModuleId`, `LanguageTexts` → `Language.Texts`
alanlar (`CreateMenu: true`, boş `DataSourceConnectionString`) hiç yazılmaz. Bu yalnızca dosya biçimidir; C# adıyla yazılır; varsayılanı olan alanlar (`CreateMenu: true`, boş `DataSourceConnectionString`, boş
`MenuParentPath` / `LanguageTexts`) hiç yazılmaz. Bu yalnızca dosya biçimidir; C#
sözleşmesi düzdür, dönüşüm `WizardSeedFileDto.ToSeedJson` / `FromSeedJson` içindedir. **Wizard sözleşmesi düzdür, dönüşüm `WizardSeedFileDto.ToSeedJson` / `FromSeedJson` içindedir. **Wizard
seed dosyası her zaman bu iki metotla okunup yazılır**; düz `JsonSerializer` çağrısı bloklu seed dosyası her zaman bu iki metotla okunup yazılır**; düz `JsonSerializer` çağrısı bloklu
bölümleri sessizce düşürür. bölümleri sessizce düşürür.
@ -264,8 +269,10 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
`add_dev_request_subtasks` ile yazılır: atanan kişi bağlanan kullanıcı, bitiş tarihi bugün — `add_dev_request_subtasks` ile yazılır: atanan kişi bağlanan kullanıcı, bitiş tarihi bugün —
sunucu doldurur, modele bırakılmaz. `Timesheets`'i tamamen sunucu yazar sunucu doldurur, modele bırakılmaz. `Timesheets`'i tamamen sunucu yazar
(`IMcpDevRequestTimesheetRecorder`): `get_dev_request`/`start_dev_request` talebi etkin talep yapar, (`IMcpDevRequestTimesheetRecorder`): `get_dev_request`/`start_dev_request` talebi etkin talep yapar,
sonraki her MCP yazma işlemi ona `App.Mcp.Timesheet.*` anahtarından Türkçe açıklama ve ölçülen sonraki her üretim/veri yazma işlemi (`create_table`, `deploy_wizard`, `delete_wizard`,
süreyle bir satır ekler. Yeni bir MCP yazma aracı eklenirse kaydedici çağrısı ve dil anahtarı da eklenir. `save_component`, `delete_component`, satır araçları, `save_dev_request_analysis`,
`append_dev_request_note`, `add_dev_request_subtasks`) ona `App.Mcp.Timesheet.*` anahtarından Türkçe
açıklama ve ölçülen süreyle bir satır ekler; yalnızca talebi açan `start_dev_request` satır yazmaz. Yeni bir üretim/veri yazma aracı eklenirse kaydedici çağrısı ve dil anahtarı da eklenir.
- **Talep analizi** → `Description` talebin yazıldığı hâliyle kalır; MCP ona yazmaz. Analiz ve - **Talep analizi** → `Description` talebin yazıldığı hâliyle kalır; MCP ona yazmaz. Analiz ve
üretim notları `Analysis` kolonundadır (Todo panosunda `AnalysisExpr`, Açıklama yanında sekme). üretim notları `Analysis` kolonundadır (Todo panosunda `AnalysisExpr`, Açıklama yanında sekme).
Durum sırası `Backlog → Analysis → Ready to Start → …`: "Analiz et" `save_dev_request_analysis` Durum sırası `Backlog → Analysis → Ready to Start → …`: "Analiz et" `save_dev_request_analysis`
@ -289,8 +296,8 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
karşılık gelen yetkiyle eklenir. `create_table` bu yüzden `.Write`'a ek olarak `App.SqlQueryManager` karşılık gelen yetkiyle eklenir. `create_table` bu yüzden `.Write`'a ek olarak `App.SqlQueryManager`
ister; tablo scriptini tasarımcının `generateCreateTableSql` çıktısıyla aynı biçimde üretir ister; tablo scriptini tasarımcının `generateCreateTableSql` çıktısıyla aynı biçimde üretir
(`McpTableCreator`) — tasarımcının şablon kolonları ya da script biçimi değişirse o da değişir. (`McpTableCreator`) — tasarımcının şablon kolonları ya da script biçimi değişirse o da değişir.
- **Bildirim kapsamı** → bildirim tipi, kuralı ve kuyruğu kiracıya aittir (`Adm_T_NotificationType`, - **Bildirim kapsamı** → bildirim tipi, kuralı ve kuyruğu kiracıya aittir (`Adm_T_NotificationTemplate`,
`Adm_T_NotificationRule`, `Adm_T_Notification`; üçü de `IMultiTenant`) ve ekranların tamamı `Adm_T_NotificationType`, `Adm_T_NotificationRule`, `Adm_T_Notification`; dördü de `IMultiTenant`) ve ekranların tamamı
Administration › Bildirimler altındadır. Ayrı bir manuel gönderim tablosu yoktur: **Bildirimler** Administration › Bildirimler altındadır. Ayrı bir manuel gönderim tablosu yoktur: **Bildirimler**
ekranının ekleme formu elle gönderimdir, uç alıcı × kanal açılımını kuyruğa yazar ekranının ekleme formu elle gönderimdir, uç alıcı × kanal açılımını kuyruğa yazar
(`list-form-dynamic-api/notification-insert`). Yeni kiracıya varsayılan tür/kural kümesi (`list-form-dynamic-api/notification-insert`). Yeni kiracıya varsayılan tür/kural kümesi

View file

@ -67428,6 +67428,34 @@
"Key": "App.Mcp.Timesheet.DeleteRow", "Key": "App.Mcp.Timesheet.DeleteRow",
"Value": "{0} ekranından satır silindi" "Value": "{0} ekranından satır silindi"
}, },
{
"Id": "02d139fc-753d-567a-b672-8aa0a0212ad0",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Mcp.Timesheet.AppendNote",
"Value": "Production note added to the analysis"
},
{
"Id": "9e9cc3eb-557b-5a02-8730-29347f4f77b4",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Mcp.Timesheet.AppendNote",
"Value": "Analize üretim notu eklendi"
},
{
"Id": "eb67cbd2-c6b3-57d6-ab44-ee7e79636553",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Mcp.Timesheet.AddSubTasks",
"Value": "{0} completed subtasks added"
},
{
"Id": "ec94c375-713b-51f8-8db8-5e58b9e4ce7b",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Mcp.Timesheet.AddSubTasks",
"Value": "{0} tamamlanmış alt görev eklendi"
},
{ {
"Id": "a5e491f7-a85c-572f-bf66-4245cb84fa36", "Id": "a5e491f7-a85c-572f-bf66-4245cb84fa36",
"CultureName": "en", "CultureName": "en",

View file

@ -3,6 +3,7 @@
* `<HtmlEditor {...htmlEditorDefaults}>` ile, dinamik formlar `mergeHtmlEditorOptions` ile * `<HtmlEditor {...htmlEditorDefaults}>` ile, dinamik formlar `mergeHtmlEditorOptions` ile
* aynı yetenek setini alır; ListForm'daki "HTML toolbar" kalıbı da buradan beslenir. * aynı yetenek setini alır; ListForm'daki "HTML toolbar" kalıbı da buradan beslenir.
* Değerler JSON'a yazılabilir kalmalıdır — kalıp editorOptions kolonuna olduğu gibi kaydedilir. * Değerler JSON'a yazılabilir kalmalıdır — kalıp editorOptions kolonuna olduğu gibi kaydedilir.
* Seed'li ekranlar aynı blokları C# `EditorOptions.Html` ile yazar; biri değişirse diğeri de değişir.
*/ */
import type { Properties as HtmlEditorProperties } from 'devextreme/ui/html_editor' import type { Properties as HtmlEditorProperties } from 'devextreme/ui/html_editor'