().FirstOrDefault();
@@ -425,6 +475,17 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens
return;
}
+ if (IsDynamicReport(reportName))
+ {
+ parameters.TryAdd("id", pathParameters[0]);
+ if (pathParameters.Length > 1)
+ {
+ parameters.TryAdd("listFormCode", pathParameters[1]);
+ }
+
+ return;
+ }
+
if (IsDynamicGridReport(reportName) || IsDynamicTreeReport(reportName) || IsDynamicFormReport(reportName))
{
if (pathParameters.Length == 1)
diff --git a/claude.md b/claude.md
index c4223ef0..06d5d029 100644
--- a/claude.md
+++ b/claude.md
@@ -193,7 +193,8 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
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
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 (`CommandColumns` →
+ `CommandColumnJson` bu yolla taşınır; wizard ekranında adımı yoktur, UI modeli düzenlemede korur).
Dosyada kalan wizard alanları üç başlık altında toplanır — `Menu`, `Language`, `Groups` — ve
`ListFormCode` → `WizardCode`, `MenuParentModuleId` → `ModuleId`, `LanguageTexts` → `Language.Texts`
adıyla yazılır; varsayılanı olan alanlar (`CreateMenu: true`, boş `DataSourceConnectionString`, boş
@@ -279,7 +280,8 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
sunucu doldurur, modele bırakılmaz. `Timesheets`'i tamamen sunucu yazar
(`IMcpDevRequestTimesheetRecorder`): `get_dev_request`/`start_dev_request` talebi etkin talep yapar,
sonraki her üretim/veri yazma işlemi (`create_table`, `deploy_wizard`, `delete_wizard`,
- `save_component`, `delete_component`, satır araçları, `save_dev_request_analysis`,
+ `save_component`, `delete_component`, `save_report_category`, `save_report_template`,
+ `delete_report_template`, 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.
Satır aracın UoW'si commit edildikten sonra ayrı UoW'de yazılır; aynı UoW'de yazmak Dapper
diff --git a/configs/seeds/host/data/App.DevRequests/c8017276-eef2-4ede-b060-ec86339fee18.json b/configs/seeds/host/data/App.DevRequests/c8017276-eef2-4ede-b060-ec86339fee18.json
new file mode 100644
index 00000000..ceebc420
--- /dev/null
+++ b/configs/seeds/host/data/App.DevRequests/c8017276-eef2-4ede-b060-ec86339fee18.json
@@ -0,0 +1,26 @@
+{
+ "ListFormCode": "App.DevRequests",
+ "KeyFieldName": "Id",
+ "GeneratedAt": "2026-10-01T10:29:00.7111349Z",
+ "Order": 0,
+ "Rows": [
+ {
+ "Id": "c8017276-eef2-4ede-b060-ec86339fee18",
+ "TenantId": null,
+ "UserName": "system@sozsoft.com",
+ "RequestDate": null,
+ "Status": "Backlog",
+ "Title": "Human Resources -> Eğitim",
+ "Description": "Human Resources menüsünün içerisinde Eğitim isimli bir alt menü oluşturulmalı. Aşağıdaki komponentler bu alt menünün altına yerleştirilmeli.
Eğitim Konuları : Eğtiim Tipi sütunu Oryantasyon Eğitimi, İş Başı Eğitimi, Teknik Oryantasyon Eğitimi, Grup Eğitimi, Firma Dışı Eğitimi, Eğitim İçerikli Sosyal Faaliyet, Akademi Eğitimleri, Rotasyon Eğitimleri seçenekleri olmalı.

Eğitimler : Yukarıda bahsedilen eğitim tiplerine ait fotoğraflarını gönderiyorum. Ancak beklentim sadece bir eğitim ekranına ihtiyacım var. Bu resimleri birleştirerek tek bir komponent tasarlamalısın. Eğitim ekranının üzerinde Eğitim tipi seçilmeli ve yukarıdaki listedeki Eğitim Konusu seçilmeli. Diğer sütunlar resimlerdeki ortak ve artan tüm bilgileri içerecek şekilde oluşturulmalıdır. Eğitimler listesinin detayında Katılımcılar, Maliyet ve Yetkinlikler girilebilmeli. Yekinlikler -> Skill Types içerisinde seçilebilmeli hatta bunun listesi olmayabilir Eğitim kaydında birden fazla seçilebilen yetkinler sütunu da olabilir. Her katılımcının katılıma durumu, değerlendirme puanı, sınav notu gibi bilgiler girilebilmelidir. Eğitimle alakalı birden fazla eğitim kaynağı olan dijital dosyaları da bu eğtiimin içerisine kaydedebilmeliyim.








Eğitime katılan tüm katılımcılar eğer katıldıysa Sertifika alabilmeli. Sertifika raporu aşağıdaki gibi hazırlanmalı. Uygulamada Rapor Kategorileri, Report Templates seçenekleri var. Bu Sertifika raporu için Standart Taahhütname gibi bir rapor hazırlanabilir. DynamicReport ile hazırlanabilmeli. Raporlar kategorisinde Standard Taahhütname gibi statik bir rapor ekle |

Yine eğitimin içerisinde Maliyet bilgileri girebileceğimiz bir group olmalı. aşağıda resimdeki detayları o kısma yazabilmeliyim. Bu bilgiler Eğitim listesinde görünebilmelidir.

",
+ "DueDate": "2026-10-01T10:34:00",
+ "Tags": "HR",
+ "Assignees": "system@sozsoft.com",
+ "Priority": "5",
+ "Completed": false,
+ "SortOrder": 0,
+ "Timesheets": null,
+ "SubTasks": null,
+ "Analysis": ""
+ }
+ ]
+}
diff --git a/configs/seeds/host/data/App.Languages.LanguageText.json b/configs/seeds/host/data/App.Languages.LanguageText.json
index 0bee6b25..9cfdbbbe 100644
--- a/configs/seeds/host/data/App.Languages.LanguageText.json
+++ b/configs/seeds/host/data/App.Languages.LanguageText.json
@@ -67951,14 +67951,14 @@
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Reports.ReportTemplates.Description",
- "Value": "Report Templates — printouts with their own layout. Table: Adm_T_ReportTemplate · tenant scope · list screen. Reporting is based on DevExpress XtraReports.\nUsage: needed for output with its own layout (invoice, quotation, work order, certificate). The template is drawn in the designer at /admin/reports/{report}/design and viewed at /admin/reports/{report}/view/{id}. It is bound to a screen with a CommandColumnJson button: Url = \"/admin/reports/{ReportName}/view/@Id\".\nFields:\n• Name → the template name; the report is opened with this value\n• CategoryId → the category it belongs to; the lookup comes from the Report Categories screen\n• Description → what the report is for and which data set it uses\n• HtmlContent → the layout definition of the template; produced by the designer, not edited by hand\n• Status → the state of the template; a draft template is not offered to the user\nNote: for a plain printout of the current list no definition is needed — the report action in the toolbar of every list opens the ready DynamicGrid report (DynamicTree in a tree list) with the current filters and columns.\nCaution: report templates are database records; they are not written into configs/seeds/. Take an export before a large change — the designer output cannot be diffed easily."
+ "Value": "Report Templates — printouts with their own layout. Table: Adm_T_ReportTemplate · tenant scope · list screen. Reporting is based on DevExpress XtraReports.\nUsage: needed for output with its own layout (invoice, quotation, work order, certificate). The template is drawn in the designer at /admin/reports/{report}/design and viewed at /admin/reports/{report}/view/{id}. It is bound to a screen with a CommandColumnJson button: Url = \"/admin/reports/{ReportName}/view/@Id\".\nFields:\n• Name → the template name; the report is opened with this value\n• CategoryId → the category it belongs to; the lookup comes from the Report Categories screen\n• Description → what the report is for and which data set it uses\n• HtmlContent → the layout definition of the template; produced by the designer, not edited by hand\n• Status → the state of the template; a draft template is not offered to the user\nNote: for a plain printout of the current list no definition is needed — the report action in the toolbar of every list opens the ready DynamicGrid report (DynamicTree in a tree list) with the current filters and columns.\nCaution: template records are mirrored to configs/seeds/ (data/App.Reports.ReportTemplates.json). A template in the Raporlar category is HTML printed by DynamicReport; when it is opened from a screen row (/admin/reports/DynamicReport/view/{Id}/{ListFormCode}?recordId=@Id) its {{FieldName}} placeholders are filled from that record. Over MCP: list_report_templates, get_report_template, save_report_category, save_report_template."
},
{
"Id": "eeebfb5c-35b9-5c8e-b23e-556d35948928",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Reports.ReportTemplates.Description",
- "Value": "Rapor Şablonları — kendi düzeni olan çıktılar. Tablo: Adm_T_ReportTemplate · tenant kapsamlı · liste ekranı. Raporlama DevExpress XtraReports tabanlıdır.\nKullanım: kendi düzeni istenen çıktı (fatura, teklif, iş emri, sertifika) için gerekir. Şablon /admin/reports/{rapor}/design adresindeki tasarımcıda çizilir, /admin/reports/{rapor}/view/{id} adresinde görüntülenir. Ekrana CommandColumnJson butonu ile bağlanır: Url = \"/admin/reports/{RaporAdi}/view/@Id\".\nAlanlar:\n• Name → şablon adı; rapor bu değerle açılır\n• CategoryId → bağlı olduğu kategori; lookup Rapor Kategorileri ekranından gelir\n• Description → raporun ne işe yaradığı ve hangi veri setini kullandığı\n• HtmlContent → şablonun düzen tanımı; tasarımcı tarafından üretilir, elle düzenlenmez\n• Status → şablonun durumu; taslak şablon kullanıcıya sunulmaz\nNot: o anki listenin düz çıktısı için tanım gerekmez — her listenin araç çubuğundaki rapor aksiyonu hazır DynamicGrid raporunu (ağaç listede DynamicTree) mevcut filtreler ve kolonlarla açar.\nDikkat: rapor şablonları veritabanı kaydıdır; configs/seeds/ altına yazılmaz. Büyük bir değişiklikten önce dışa aktarım al — tasarımcı çıktısı kolay karşılaştırılamaz."
+ "Value": "Rapor Şablonları — kendi düzeni olan çıktılar. Tablo: Adm_T_ReportTemplate · tenant kapsamlı · liste ekranı. Raporlama DevExpress XtraReports tabanlıdır.\nKullanım: kendi düzeni istenen çıktı (fatura, teklif, iş emri, sertifika) için gerekir. Şablon /admin/reports/{rapor}/design adresindeki tasarımcıda çizilir, /admin/reports/{rapor}/view/{id} adresinde görüntülenir. Ekrana CommandColumnJson butonu ile bağlanır: Url = \"/admin/reports/{RaporAdi}/view/@Id\".\nAlanlar:\n• Name → şablon adı; rapor bu değerle açılır\n• CategoryId → bağlı olduğu kategori; lookup Rapor Kategorileri ekranından gelir\n• Description → raporun ne işe yaradığı ve hangi veri setini kullandığı\n• HtmlContent → şablonun düzen tanımı; tasarımcı tarafından üretilir, elle düzenlenmez\n• Status → şablonun durumu; taslak şablon kullanıcıya sunulmaz\nNot: o anki listenin düz çıktısı için tanım gerekmez — her listenin araç çubuğundaki rapor aksiyonu hazır DynamicGrid raporunu (ağaç listede DynamicTree) mevcut filtreler ve kolonlarla açar.\nDikkat: şablon kayıtları configs/seeds/ altına (data/App.Reports.ReportTemplates.json) yansır. Raporlar kategorisindeki şablon DynamicReport ile basılan HTML'dir; bir ekran satırından açıldığında (/admin/reports/DynamicReport/view/{Id}/{ListFormCode}?recordId=@Id) {{AlanAdi}} yer tutucuları o kaydın alanlarıyla doldurulur. MCP üzerinden: list_report_templates, get_report_template, save_report_category, save_report_template."
},
{
"Id": "613a3f66-1426-5a8f-af24-4354b9dc6318",
@@ -69318,6 +69318,48 @@
"Key": "App.Mcp.Timesheet.DeleteComponent",
"Value": "{0} bileşeni silindi"
},
+ {
+ "Id": "e7c8404a-ba29-52f2-9f48-53d778dfe2f9",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Timesheet.SaveReportCategory",
+ "Value": "Report category {0} saved"
+ },
+ {
+ "Id": "744aed7c-4aa9-5868-a967-362543d4b9da",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Timesheet.SaveReportCategory",
+ "Value": "{0} rapor kategorisi kaydedildi"
+ },
+ {
+ "Id": "d17347c8-f526-560c-bd68-a9323721ffd9",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Timesheet.SaveReportTemplate",
+ "Value": "Report template {0} saved"
+ },
+ {
+ "Id": "3adca18e-583c-51d5-8e4d-4206f58ff3a3",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Timesheet.SaveReportTemplate",
+ "Value": "{0} rapor şablonu kaydedildi"
+ },
+ {
+ "Id": "c03489b9-1434-5598-bfec-f928e163b0d7",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Timesheet.DeleteReportTemplate",
+ "Value": "Report template {0} deleted"
+ },
+ {
+ "Id": "93e25831-412f-528b-8fec-6553b5d1137f",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Timesheet.DeleteReportTemplate",
+ "Value": "{0} rapor şablonu silindi"
+ },
{
"Id": "11a42b2b-3a91-54ec-92c7-3020e0b3aa14",
"CultureName": "en",
@@ -69416,6 +69458,104 @@
"Key": "App.Mcp.Error.VisualDesignerComponent",
"Value": "\"{0}\" bileşeninin kodu Visual Designer belgesinden üretiliyor, MCP üzerinden yazılamaz. Bileşeni Visual Designer'da düzenleyin."
},
+ {
+ "Id": "e9467c21-1acf-5b7e-bafe-22f5327e80b4",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportNameRequired",
+ "Value": "A name is required."
+ },
+ {
+ "Id": "d61f69b0-af46-5a66-bb64-c1558fecc904",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportNameRequired",
+ "Value": "Ad zorunludur."
+ },
+ {
+ "Id": "23b03a6a-9131-5367-a32c-3c4e6506f5aa",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportHtmlRequired",
+ "Value": "HtmlContent is required for a new report template."
+ },
+ {
+ "Id": "e406540b-d85e-5cf7-9076-6250f1c0532f",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportHtmlRequired",
+ "Value": "Yeni rapor şablonunda HtmlContent zorunludur."
+ },
+ {
+ "Id": "18d9c5cc-176e-5de9-a5a9-dd03bcc65934",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportCategoryRequired",
+ "Value": "A category is required for a new report template. Read the categories with list_report_templates."
+ },
+ {
+ "Id": "c31266e3-00be-5f7a-9c23-2cd7842c68fa",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportCategoryRequired",
+ "Value": "Yeni rapor şablonunda kategori zorunludur. Kategorileri list_report_templates ile okuyun."
+ },
+ {
+ "Id": "28fe03db-7c92-5875-a41f-c5c03299636e",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportCategoryNotFound",
+ "Value": "Report category \"{0}\" was not found. Read the categories with list_report_templates or create it with save_report_category."
+ },
+ {
+ "Id": "fa2a2230-8000-5326-ba1e-7a014cc45f39",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportCategoryNotFound",
+ "Value": "\"{0}\" rapor kategorisi bulunamadı. Kategorileri list_report_templates ile okuyun ya da save_report_category ile oluşturun."
+ },
+ {
+ "Id": "aaf964c0-ea3b-54a7-931c-95978e34e05e",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportTemplateNotFound",
+ "Value": "Report template \"{0}\" was not found."
+ },
+ {
+ "Id": "664b422e-00f3-5b86-a4f0-6a6b6205ccc8",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportTemplateNotFound",
+ "Value": "\"{0}\" rapor şablonu bulunamadı."
+ },
+ {
+ "Id": "375f2d7b-53c6-51f9-9682-aa5b17ffd334",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportListFormNotFound",
+ "Value": "List form \"{0}\" was not found. A screen that is waiting for DB Migrate cannot be used yet."
+ },
+ {
+ "Id": "134eb4f8-8902-5da5-a44d-b35a8bab0b5a",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportListFormNotFound",
+ "Value": "\"{0}\" ekranı bulunamadı. DB Migrate bekleyen bir ekran henüz kullanılamaz."
+ },
+ {
+ "Id": "fff89062-9058-5067-a13e-d2cb6f831dca",
+ "CultureName": "en",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportPlaceholdersUnknown",
+ "Value": "These placeholders are not fields of \"{0}\": {1}. Use the field names returned by describe_list."
+ },
+ {
+ "Id": "f6791258-c8e7-5351-b0e4-12e167be862f",
+ "CultureName": "tr",
+ "ResourceName": "Platform",
+ "Key": "App.Mcp.Error.ReportPlaceholdersUnknown",
+ "Value": "Şu yer tutucular \"{0}\" ekranının alanı değil: {1}. describe_list ile dönen alan adlarını kullanın."
+ },
{
"Id": "66fc88f1-60bd-5e69-9dbc-2da3a8db6f57",
"CultureName": "en",
diff --git a/ui/src/proxy/admin/wizard/models.ts b/ui/src/proxy/admin/wizard/models.ts
index a2263f11..bbf4c48d 100644
--- a/ui/src/proxy/admin/wizard/models.ts
+++ b/ui/src/proxy/admin/wizard/models.ts
@@ -1,5 +1,6 @@
import { ColumnFormatEditDto } from '@/proxy/admin/list-form-field/models'
import {
+ CommandColumnDto,
GanttOptionDto,
GridOptionsEditDto,
SchedulerOptionDto,
@@ -128,6 +129,8 @@ export interface ListFormWizardDto {
groups?: ListFormWizardColumnGroupDto[]
subForms?: SubFormDto[]
widgets?: WidgetEditDto[]
+ /** Wizard adımı yoktur; düzenlemede korunur ve MCP deploy_wizard ile yazılır. */
+ commandColumns?: CommandColumnDto[]
}
/** Izin grubu secim listesi ogesi; gorunen adlar grup adiyla ayni olan dil anahtarindan gelir. */
diff --git a/ui/src/views/admin/listForm/wizard/Wizard.tsx b/ui/src/views/admin/listForm/wizard/Wizard.tsx
index 447f8ab0..b8d49aba 100644
--- a/ui/src/views/admin/listForm/wizard/Wizard.tsx
+++ b/ui/src/views/admin/listForm/wizard/Wizard.tsx
@@ -181,6 +181,7 @@ const initialValues: ListFormWizardDto = {
keyFieldDbSourceType: DbTypeEnum.Int32,
subForms: [],
widgets: [],
+ commandColumns: [],
}
const step1ValidationSchema = Yup.object().shape({
@@ -753,6 +754,7 @@ const Wizard = () => {
keyFieldDbSourceType: w.keyFieldDbSourceType ?? DbTypeEnum.Int32,
subForms: w.subForms ?? [],
widgets: w.widgets ?? [],
+ commandColumns: w.commandColumns ?? [],
})
// Queue column load to run once dbObjects is available
@@ -1139,6 +1141,7 @@ const Wizard = () => {
groups: [],
subForms: [],
widgets: [],
+ commandColumns: [],
})
returnToManager()