From 7659dbdaa103764d48748db6d92eeab455eb7898 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?=
<76204082+iamsedatozturk@users.noreply.github.com>
Date: Wed, 19 Aug 2026 15:13:32 +0300
Subject: [PATCH] =?UTF-8?q?SqlDataSource=20->=20Form=20olarak=20de=C4=9Fi?=
=?UTF-8?q?=C5=9Ftirildi.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../DeveloperKit/CrudEndpointAppService.cs | 28 +-
.../Migrations/LanguagesData.json | 156 ++++-
.../DeveloperKit/IDynamicEntityManager.cs | 9 +-
.../PlatformDynamicEntityManager.cs | 180 +++++-
configs/seeds/host/crud/AbpUserRoles.json | 36 ++
configs/seeds/host/custom/RoleComponent.json | 15 +-
.../componentEditor/PlatformViewHost.tsx | 19 +-
.../visualDesigner/VisualCanvas.tsx | 64 +-
ui/src/components/visualDesigner/catalog.ts | 27 +-
.../visualDesigner/codeGenerator.ts | 330 +++++++++--
ui/src/components/visualDesigner/types.ts | 246 +++++++-
.../developerKit/VisualComponentDesigner.tsx | 548 +++++++++++++++++-
ui/src/views/list/Chart.tsx | 12 +-
ui/src/views/list/List.tsx | 10 +-
14 files changed, 1566 insertions(+), 114 deletions(-)
create mode 100644 configs/seeds/host/crud/AbpUserRoles.json
diff --git a/api/src/Sozsoft.Platform.Application/DeveloperKit/CrudEndpointAppService.cs b/api/src/Sozsoft.Platform.Application/DeveloperKit/CrudEndpointAppService.cs
index 65d9ec48..f405b114 100644
--- a/api/src/Sozsoft.Platform.Application/DeveloperKit/CrudEndpointAppService.cs
+++ b/api/src/Sozsoft.Platform.Application/DeveloperKit/CrudEndpointAppService.cs
@@ -1,5 +1,6 @@
using Sozsoft.Platform.Domain.DeveloperKit;
using Sozsoft.Platform.Entities;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
@@ -26,11 +27,36 @@ public class CrudEndpointAppService : ApplicationService
_dynamicManager = dynamicManager;
}
+ ///
+ /// Every query string entry that is not a paging parameter is a column filter:
+ /// ?RoleId=… compares for equality, ?Name.contains=… applies the
+ /// named operator. The column names are validated against the table schema in
+ /// the manager, so an unknown column fails loudly instead of returning the
+ /// unfiltered collection.
+ ///
[HttpGet("{entityName}")]
public async Task?> GetEntityListAsync(string entityName)
{
await EnsureEndpointAsync(entityName, "GET", "GetList");
- return await _dynamicManager.GetEntityListAsync(entityName);
+ return await _dynamicManager.GetEntityListAsync(entityName, ReadQueryFilters());
+ }
+
+ ///
+ /// Route values are not filters, so only the query string is read. A repeated
+ /// parameter keeps its comma joined form, which is what the in operator
+ /// expects.
+ ///
+ private Dictionary ReadQueryFilters()
+ {
+ var filters = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ var query = LazyServiceProvider.LazyGetService()?.HttpContext?.Request?.Query;
+ if (query == null)
+ return filters;
+
+ foreach (var entry in query)
+ filters[entry.Key] = string.Join(",", entry.Value.ToArray());
+
+ return filters;
}
[HttpGet("{entityName}/{id}")]
diff --git a/api/src/Sozsoft.Platform.DbMigrator/Migrations/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Migrations/LanguagesData.json
index 9ac32403..bf6fab4d 100644
--- a/api/src/Sozsoft.Platform.DbMigrator/Migrations/LanguagesData.json
+++ b/api/src/Sozsoft.Platform.DbMigrator/Migrations/LanguagesData.json
@@ -19530,6 +19530,108 @@
"en": "Download as JPG",
"tr": "JPG olarak indir"
},
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterMaster",
+ "en": "Master component",
+ "tr": "Ana komponent"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterMasterIncomplete",
+ "en": "Pick both the master component and its column; the filter does not run until then.",
+ "tr": "Ana komponenti ve sütununu birlikte seçin; ikisi tamamlanmadan filtre çalışmaz."
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.Filters",
+ "en": "Filters",
+ "tr": "Filtreler"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.AddFilter",
+ "en": "Add filter",
+ "tr": "Filtre ekle"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FiltersHint",
+ "en": "Filters are sent as query parameters to the endpoint and apply to every component bound to it. The value can be static, come from the page URL, or come from the record of another Form.",
+ "tr": "Filtreler endpointe query parametresi olarak gönderilir ve bu endpointe bağlı tüm komponentler için geçerlidir. Değer sabit olabilir, sayfa adresinden gelebilir veya başka bir Form kaydından okunabilir."
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.NoFilter",
+ "en": "No filter defined; the endpoint returns the whole collection.",
+ "tr": "Tanımlı filtre yok; endpoint tüm koleksiyonu döndürür."
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterColumn",
+ "en": "Column",
+ "tr": "Sütun"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterValue",
+ "en": "Value",
+ "tr": "Değer"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterUrlParam",
+ "en": "URL parameter name",
+ "tr": "Adres parametresi adı"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterMasterColumn",
+ "en": "Master column",
+ "tr": "Ana kayıt sütunu"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterPreviewValue",
+ "en": "Designer preview value",
+ "tr": "Tasarımcı önizleme değeri"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterRequired",
+ "en": "Required: cancel the request while the value is empty",
+ "tr": "Zorunlu: değer boşken istek gönderilmesin"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterSourceStatic",
+ "en": "Static",
+ "tr": "Sabit"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterSourceQuery",
+ "en": "URL query",
+ "tr": "Adres sorgusu"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterSourceRoute",
+ "en": "URL path",
+ "tr": "Adres yolu"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.FilterSourceRecord",
+ "en": "Form record",
+ "tr": "Form kaydı"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.DeveloperKitComponentDesigner.RequiredFilterPreviewMissing",
+ "en": "A required filter has no preview value, so the request was not sent.",
+ "tr": "Zorunlu bir filtrenin önizleme değeri yok, bu yüzden istek gönderilmedi."
+ },
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.AcceptsChildren",
@@ -19629,8 +19731,8 @@
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.BoundToSqlDataSource",
- "en": "This component is bound to a SqlDataSource record; fields come from the columns in the Select (GET) response.",
- "tr": "Bu komponent SqlDataSource kaydına bağlıdır; alanlar Select (GET) cevabındaki sütunlardan gelir."
+ "en": "This component is bound to a Form record; fields come from the columns in the Select (GET) response.",
+ "tr": "Bu komponent Form kaydına bağlıdır; alanlar Select (GET) cevabındaki sütunlardan gelir."
},
{
"resourceName": "Platform",
@@ -19653,8 +19755,8 @@
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.ClearNonSqlBinding",
- "en": "Non-SqlDataSource binding — clear",
- "tr": "SqlDataSource dışı bağlantı — temizle"
+ "en": "Non-Form binding — clear",
+ "tr": "Form dışı bağlantı — temizle"
},
{
"resourceName": "Platform",
@@ -19665,8 +19767,8 @@
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.CommandSlotsHint",
- "en": "Define endpoints in the Data workspace and bind them to command slots here. Select the components you drop inside and bind them to a column by choosing the SqlDataSource record source from the Data tab.",
- "tr": "Endpointleri Data çalışma alanında tanımlayın, burada komut yuvalarına bağlayın. İçine bıraktığınız komponentleri seçip Data sekmesinden SqlDataSource kaydı kaynağını seçerek sütuna bağlayabilirsiniz."
+ "en": "Define endpoints in the Data workspace and bind them to command slots here. Select the components you drop inside and bind them to a column by choosing the Form record source from the Data tab.",
+ "tr": "Endpointleri Data çalışma alanında tanımlayın, burada komut yuvalarına bağlayın. İçine bıraktığınız komponentleri seçip Data sekmesinden Form kaydı kaynağını seçerek sütuna bağlayabilirsiniz."
},
{
"resourceName": "Platform",
@@ -19719,14 +19821,14 @@
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.DefineAndRunSelect",
- "en": "Define and run the SqlDataSource Select endpoint.",
- "tr": "SqlDataSource Select endpointini tanımlayıp çalıştırın."
+ "en": "Define and run the Form Select endpoint.",
+ "tr": "Form Select endpointini tanımlayıp çalıştırın."
},
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.DefineSelectEndpointFirst",
- "en": "This component is inside a SqlDataSource. To bind it to columns, first select the SqlDataSource and define the Select (GET) endpoint from the Data tab.",
- "tr": "Bu komponent bir SqlDataSource içinde. Sütunlara bağlanabilmesi için önce SqlDataSource’u seçip Data sekmesinden Select (GET) endpointini tanımlayın."
+ "en": "This component is inside a Form. To bind it to columns, first select the Form and define the Select (GET) endpoint from the Data tab.",
+ "tr": "Bu komponent bir Form içinde. Sütunlara bağlanabilmesi için önce Form’u seçip Data sekmesinden Select (GET) endpointini tanımlayın."
},
{
"resourceName": "Platform",
@@ -19791,8 +19893,8 @@
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.EndpointNeedsKey",
- "en": "This endpoint expects a key parameter. Enter a preview key value on the SqlDataSource.",
- "tr": "Bu endpoint bir key parametresi bekliyor. SqlDataSource üzerinde önizleme key değeri girin."
+ "en": "This endpoint expects a key parameter. Enter a preview key value on the Form.",
+ "tr": "Bu endpoint bir key parametresi bekliyor. Form üzerinde önizleme key değeri girin."
},
{
"resourceName": "Platform",
@@ -19893,8 +19995,8 @@
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.GetPostHint",
- "en": "GET sources are read when the page opens; POST/PUT/DELETE sources only run when bound to a SqlDataSource command slot and are not triggered from the design screen.",
- "tr": "GET kaynakları sayfa açılışında okunur; POST/PUT/DELETE kaynakları yalnızca bir SqlDataSource komut yuvasına bağlandığında çalışır ve tasarım ekranından tetiklenmez."
+ "en": "GET sources are read when the page opens; POST/PUT/DELETE sources only run when bound to a Form command slot and are not triggered from the design screen.",
+ "tr": "GET kaynakları sayfa açılışında okunur; POST/PUT/DELETE kaynakları yalnızca bir Form komut yuvasına bağlandığında çalışır ve tasarım ekranından tetiklenmez."
},
{
"resourceName": "Platform",
@@ -19995,8 +20097,8 @@
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.MethodNotRunnableBindToSql",
- "en": "{method} endpoints are not run from the design screen; bind them to a SqlDataSource command.",
- "tr": "{method} endpointleri tasarım ekranından çalıştırılmaz; SqlDataSource komutuna bağlayın."
+ "en": "{method} endpoints are not run from the design screen; bind them to a Form command.",
+ "tr": "{method} endpointleri tasarım ekranından çalıştırılmaz; Form komutuna bağlayın."
},
{
"resourceName": "Platform",
@@ -20193,8 +20295,8 @@
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.RecordFieldHint",
- "en": "The SqlDataSource column the selection is read from and saved to.",
- "tr": "Seçimin okunacağı ve kaydedileceği SqlDataSource sütunu."
+ "en": "The Form column the selection is read from and saved to.",
+ "tr": "Seçimin okunacağı ve kaydedileceği Form sütunu."
},
{
"resourceName": "Platform",
@@ -20349,8 +20451,8 @@
{
"resourceName": "Platform",
"key": "App.DeveloperKitComponentDesigner.SqlDataSourceRecord",
- "en": "SqlDataSource record · {field}",
- "tr": "SqlDataSource kaydı · {field}"
+ "en": "Form record · {field}",
+ "tr": "Form kaydı · {field}"
},
{
"resourceName": "Platform",
@@ -24759,8 +24861,8 @@
{
"resourceName": "Platform",
"key": "App.CatalogGroup.SqlDataSource",
- "en": "SqlDataSource",
- "tr": "SqlDataSource"
+ "en": "Form",
+ "tr": "Form"
},
{
"resourceName": "Platform",
@@ -24906,6 +25008,12 @@
"en": "New record / editing, busy and error state.",
"tr": "Yeni kayıt / düzenleme, meşgul ve hata durumu."
},
+ {
+ "resourceName": "Platform",
+ "key": "App.CatalogSqlDataSource.SqlDataSourceTitleDescription",
+ "en": "Header text of the card wrapping the container; leave empty to hide the header. A value starting with :: is resolved as a localization key.",
+ "tr": "Kabı saran kartın başlık metni; boş bırakılırsa başlık gizlenir. :: ile başlayan değer dil anahtarı olarak çözümlenir."
+ },
{
"resourceName": "Platform",
"key": "App.CatalogSqlDataSource.SqlDataSourceTitle",
@@ -25707,8 +25815,8 @@
{
"resourceName": "Platform",
"key": "App.VisualDesigner.SqlRefRequired",
- "en": "This rule requires a SqlDataSource ref name.",
- "tr": "Bu kural bir SqlDataSource ref adı gerektiriyor."
+ "en": "This rule requires a Form ref name.",
+ "tr": "Bu kural bir Form ref adı gerektiriyor."
},
{
"resourceName": "Platform",
diff --git a/api/src/Sozsoft.Platform.Domain/DeveloperKit/IDynamicEntityManager.cs b/api/src/Sozsoft.Platform.Domain/DeveloperKit/IDynamicEntityManager.cs
index 7d0eaa2c..38c33cb8 100644
--- a/api/src/Sozsoft.Platform.Domain/DeveloperKit/IDynamicEntityManager.cs
+++ b/api/src/Sozsoft.Platform.Domain/DeveloperKit/IDynamicEntityManager.cs
@@ -7,7 +7,14 @@ namespace Sozsoft.Platform.Domain.DeveloperKit;
public interface IDynamicEntityManager
{
- Task?> GetEntityListAsync(string entityName);
+ ///
+ /// Column filters read from the request query string. The key is the column
+ /// name, optionally suffixed with an operator (Name.contains); every
+ /// column is validated against the table schema before it reaches the SQL.
+ ///
+ Task?> GetEntityListAsync(
+ string entityName,
+ IReadOnlyDictionary? filters = null);
Task