CustomEndpoints klasör yapısına taşındı
This commit is contained in:
parent
135a85e682
commit
b9b26eff7c
17 changed files with 180 additions and 55 deletions
13
.github/instructions/lowcode.instructions.md
vendored
13
.github/instructions/lowcode.instructions.md
vendored
|
|
@ -546,6 +546,10 @@ eklenen dosya) bu satırlar ekranla birlikte seed edilir; migrate çalıştığ
|
|||
|
||||
Kurallar:
|
||||
- Dosyayı elle yazma; `seedRows` alan adlarını ekranın alanlarına göre doğrular, bilinmeyen alanı reddeder.
|
||||
Migrate satırı yalnızca ekranın alanı olan kolonlara yazar; aynı tablonun alt form sekmesindeki
|
||||
kolon (ör. `Form` tipi detay sekmesi) ana ekranın satırından yazılmaz. Ret mesajı, kolonun aynı
|
||||
tabloyu okuyan hangi wizard ekranında alan olduğunu wizard dosyalarından bulup yazar: kolonu ana
|
||||
ekrana alan olarak ekle (`IncludeInEditingForm: false`) ya da satırdan çıkar.
|
||||
- Görsel yalnızca ekranın şablonu değildir: içinde görünen **her satır** okunur ve demo veri
|
||||
olarak eklenir (standing default 6'daki "piksel sözleşmesi değildir" kuralı düzen içindir, veri için değil).
|
||||
- Görselden okunamayan değer uydurulmaz: zorunlu alan boşsa kullanıcıya sor.
|
||||
|
|
@ -1988,7 +1992,7 @@ işlemde siler. Onay diyaloğu sırayı ve tabloları gösterir:
|
|||
kaynağı kaydı silinmeden önce çözülür. Tablo seçmek yine `App.SqlQueryManager` ister.
|
||||
- **Talebin Custom Endpoint'leri de gider:** tablo talebe aitse (`create_table`/tasarımcı scripti var,
|
||||
talep dışında ekran kullanmıyor) onu sorgulayan Custom Endpoint'ler tabloyu tutmaz; veritabanından
|
||||
ve `data/App.DeveloperKit.CustomEndpoints.json`'dan (migrate edilmemiş satır dahil) silinir —
|
||||
ve `data/App.DeveloperKit.CustomEndpoints/` klasöründeki satır dosyasından (migrate edilmemiş satır dahil) silinir —
|
||||
tablo seçilmese de (`WizardDeleteTableDto.CustomEndpoints`, `WizardTableCleaner.DeleteCustomEndpointsAsync`).
|
||||
Diyalog bunları tablonun altında listeler. Tek wizard silmede endpoint yine tabloyu "kullanımda" tutar.
|
||||
- Rapor tek wizard silmeyle aynı sözleşmedir (`WizardDeleteResultDto`, bütün wizard'ların kayıtları
|
||||
|
|
@ -3956,9 +3960,10 @@ Endpoint **tanımlarını** düzenleme yetkileri ListForm ekranının
|
|||
`App.DeveloperKit.CustomEndpoints{,.Create,.Update,.Delete}` yetkileridir — çağırma
|
||||
yetkilerinden (`.Get/.Post/.Put/.Remove` + `PermissionsJson`) ayrıdır.
|
||||
|
||||
**Seed:** `configs/seeds/data/App.DeveloperKit.CustomEndpoints.json` (§9.15). Ekranın
|
||||
**Seed:** `configs/seeds/data/App.DeveloperKit.CustomEndpoints/{Id}.json` (§9.15) — ekran klasör
|
||||
modundadır, her endpoint kendi satır dosyasındadır. Ekranın
|
||||
`SeedSyncInsert/Update/Delete` bayrakları **açıktır**: ekrandan eklenen/değiştirilen/silinen kayıt
|
||||
dosyaya yansır, migrate'te eksikse geri eklenir. Prompt ile üretimde satırı bu dosyaya yaz
|
||||
dosyasına yansır, migrate'te eksikse geri eklenir. Prompt ile üretimde satırı `{Id}.json` dosyası olarak yaz
|
||||
(`Id` sabit GUID; `ParametersJson`/`PermissionsJson` kaçışlanmış string).
|
||||
|
||||
**Ne zaman CRUD, ne zaman Custom Endpoint?** Tek tabloya standart CRUD gerekiyorsa CRUD Endpoint
|
||||
|
|
@ -4626,7 +4631,7 @@ kullanılacağı** `lowcode-reference.instructions.md` §12'dedir.
|
|||
>
|
||||
> | Durum | Ekranlar (örnek) | Prompt ile kayıt eklerken |
|
||||
> | --- | --- | --- |
|
||||
> | Seed bayrakları açık — ekrandan yapılan kayıt dosyaya yansır | RecurringJobs, NotificationTemplates/Types/Rules, SettingDefinitions, AiBot, CustomEndpoints, DynamicServices, CustomComponents, McpServers, IntranetWidgets, ReportTemplates/Categories, `App.Menus.*`, `Abp.Identity.Permission*` | Satırı `data/{ListFormCode}.json`'a yaz (rapor şablonu için `save_report_template`) |
|
||||
> | Seed bayrakları açık — ekrandan yapılan kayıt dosyaya yansır | RecurringJobs, NotificationTemplates/Types/Rules, SettingDefinitions, AiBot, CustomEndpoints, DynamicServices, CustomComponents, McpServers, IntranetWidgets, ReportTemplates/Categories, `App.Menus.*`, `Abp.Identity.Permission*` | Satırı ekranın `SeedFilePath` tanımına yaz: `.json` ile bitiyorsa o dosya, uzantısızsa klasördeki `{anahtar}.json` (§9.15) (rapor şablonu için `save_report_template`) |
|
||||
> | `SeedFilePath` dolu, bayraklar kapalı — dosya migrate'te uygulanır, ekrandan yapılan değişiklik dosyaya **yansımaz** | Sequence, GlobalSearch, Currency, ContactTitle, Country/City/District, Uom, Hr Department/JobPosition/SkillType, WorkHour, Intranet, Blog, Forum, Orders tanımları | Satırı dosyaya yaz; ekrandan eklenen kayıt teslim sayılmaz |
|
||||
> | `SeedFilePath` boş — yalnızca veritabanı | DataSource, Languages, Branches, Roles/Users/Tenants, AuditLogs, IpRestrictions, Notification (geçmiş), BackgroundWorkers.Jobs | `sql/execute/{Ad}.sql` altında **varsa güncelleyen/yoksa ekleyen** bir prosedür (§8.4) |
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1550,7 +1550,7 @@ liste süzgeci ve çağrı kapısı aynı kuralı kullanır.
|
|||
| `describe_list` | Bir listenin sütunları: alan adı, görünen başlık, SQL tipi, lookup ilişkisi, `isSensitive`. |
|
||||
| `search_schema` | Liste ve sütun adları/başlıkları üzerinde aksan ve büyük/küçük harf duyarsız arama. |
|
||||
| `query_list` | Listenin verisini ekranın kendi sorgusuyla (`GetSelectAsync`) okur: filtre, sıralama, gruplama, özet (DevExtreme biçimi). Sıralama/gruplama/özet JSON'u, arayüzün `Utils.ts`'te yaptığı gibi select ucunun metin biçimine (`Alan desc|Alan2 asc`) `McpLoadOptions` ile çevrilir; select ucu JSON'u tanımaz. Normal kullanıcının veri okuma yolu. |
|
||||
| `run_select` | Parametreli tek SELECT; çoklu ifade, DDL ve DML reddedilir, satır tavanı sorguya yazılır. Yalnızca SQL Query Manager yetkisiyle. Sağlayıcı hatası mesajıyla döner (`SelectFailed`); araç açıklaması kolonu varsaymamayı, gerekirse önce `INFORMATION_SCHEMA.COLUMNS`'ı okumayı söyler. |
|
||||
| `run_select` | Parametreli tek SELECT; çoklu ifade, DDL ve DML reddedilir, satır tavanı sorguya yazılır. Yalnızca SQL Query Manager yetkisiyle. Sağlayıcı hatası mesajıyla döner (`SelectFailed`; bilinmeyen kolonda tabloların gerçek kolonlarıyla `SelectFailedColumns`; veritabanında olmayan ama seed scripti olan tabloda — `create_table` yazdı, DB Migrate kurmadı — scriptteki kolonlarla `SelectTableNotInstalled`); araç açıklaması kolonu varsaymamayı, gerekirse önce `INFORMATION_SCHEMA.COLUMNS`'ı okumayı söyler. |
|
||||
| `list_queries` | View/procedure/function nesneleri (SQL Query Manager yetkisiyle) + çağrılabilir Custom Endpoint'ler (`App.DeveloperKit.CustomEndpoints.Get` ile). |
|
||||
| `run_query` | Kayıtlı bir nesneyi ya da Custom Endpoint'i parametreleriyle çağırır; yetkiler `list_queries` ile aynı. |
|
||||
| `insert_row` / `update_row` / `delete_row` | ListForm ekranının insert/update/delete sözleşmesinden geçer. |
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ public class McpDevelopAppService(
|
|||
editGroups[0].Caption = string.Empty;
|
||||
|
||||
// Satirlar deploy'dan once dogrulanir; gecersiz girdi yarim bir deploy birakmaz.
|
||||
var seedRows = ParseSeedRows(input.SeedRows, wizard);
|
||||
var seedRows = await ParseSeedRowsAsync(input.SeedRows, wizard);
|
||||
|
||||
// Wizard dosyasi onu ureten talebi tasir; Wizard Manager talebi gosterir ve talebin
|
||||
// butun wizard'larini birlikte export eder. Bag modelin girdisinden degil etkin talepten gelir.
|
||||
|
|
@ -282,7 +282,7 @@ public class McpDevelopAppService(
|
|||
/// Demo satirlarini okur ve ekranin alanlarina gore dogrular. Satirlar yalnizca SeedData acik
|
||||
/// liste ekraninda kabul edilir: migrate onlari ekranin veri dosyasindan ekler.
|
||||
/// </summary>
|
||||
private List<Dictionary<string, JsonElement>> ParseSeedRows(string? json, ListFormWizardDto wizard)
|
||||
private async Task<List<Dictionary<string, JsonElement>>> ParseSeedRowsAsync(string? json, ListFormWizardDto wizard)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
return [];
|
||||
|
|
@ -310,10 +310,53 @@ public class McpDevelopAppService(
|
|||
|
||||
var unknown = rows.SelectMany(row => row.Keys).Where(key => !fields.Contains(key))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
|
||||
if (unknown.Count > 0)
|
||||
throw new UserFriendlyException(L[McpErrorCodes.SeedRowsUnknownFields, string.Join(", ", unknown), string.Join(", ", fields)]);
|
||||
|
||||
if (unknown.Count == 0)
|
||||
return rows;
|
||||
|
||||
var screenFields = string.Join(", ", fields);
|
||||
var owners = await FindSameTableScreensAsync(wizard, unknown);
|
||||
if (owners.Count == 0)
|
||||
throw new UserFriendlyException(L[McpErrorCodes.SeedRowsUnknownFields, string.Join(", ", unknown), screenFields]);
|
||||
|
||||
// Ayni tablonun baska ekraninda (cogunlukla alt form sekmesi) alan olan kolon migrate'te
|
||||
// bu ekranin veri dosyasindan yazilmaz; model kolonun nerede durdugunu gorurse alani ekrana
|
||||
// ekleyip ya da satirdan cikarip tekrar dener.
|
||||
var placement = string.Join("; ", owners.Select(owner => $"{owner.Key}: {string.Join(", ", owner.Value)}"));
|
||||
throw new UserFriendlyException(L[McpErrorCodes.SeedRowsFieldsOnOtherScreens, string.Join(", ", unknown), placement, screenFields]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bilinmeyen kolonlari ayni tabloyu okuyan diger wizard ekranlarinin alanlarinda arar; sonuc
|
||||
/// ekran kodundan o ekranda bulunan kolonlara eslemedir. Ekran listesi wizard dosyalarindan
|
||||
/// okunur, migrate bekleyen ekranlar da dahildir.
|
||||
/// </summary>
|
||||
private async Task<Dictionary<string, List<string>>> FindSameTableScreensAsync(ListFormWizardDto wizard, List<string> columns)
|
||||
{
|
||||
var owners = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
|
||||
var table = wizard.SelectCommand?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(table))
|
||||
return owners;
|
||||
|
||||
var wizardName = wizard.WizardName?.Trim();
|
||||
foreach (var file in await wizardAppService.GetFiles())
|
||||
{
|
||||
if (file.ComponentKind == WizardComponentKindEnum.Custom ||
|
||||
string.Equals(file.WizardName, wizardName, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(file.FileName, wizard.EditFileName, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
var seed = await wizardAppService.GetFile(file.FileName);
|
||||
if (!string.Equals(seed.Wizard?.SelectCommand?.Trim(), table, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
var found = columns
|
||||
.Where(column => (seed.Fields ?? []).Any(field => string.Equals(field.FieldName, column, StringComparison.OrdinalIgnoreCase)))
|
||||
.ToList();
|
||||
if (found.Count > 0)
|
||||
owners[seed.ListForm?.ListFormCode ?? file.ListFormCode ?? file.WizardName] = found;
|
||||
}
|
||||
|
||||
return owners;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ using System.Text.Json;
|
|||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Sozsoft.Mcp.Dtos;
|
||||
using Sozsoft.Mcp.Services;
|
||||
using Sozsoft.Platform;
|
||||
using Sozsoft.Platform.Data.Seeds;
|
||||
using Sozsoft.Platform.Entities;
|
||||
using Sozsoft.Platform.Enums;
|
||||
using Sozsoft.Platform.ListForms.Select;
|
||||
|
|
@ -37,7 +39,8 @@ public partial class McpQueryAppService(
|
|||
IMcpQueryExecutor queryExecutor,
|
||||
IRepository<CustomEndpoint, Guid> customEndpointRepository,
|
||||
IListFormSelectAppService listFormSelectAppService,
|
||||
IMcpListFormAccessFilter accessFilter)
|
||||
IMcpListFormAccessFilter accessFilter,
|
||||
IConfiguration configuration)
|
||||
: McpAppService(serverConfigProvider), IMcpQueryAppService
|
||||
{
|
||||
private const string SqlPermission = PlatformConsts.AppCodes.SqlQueryManagers.Default;
|
||||
|
|
@ -116,6 +119,10 @@ public partial class McpQueryAppService(
|
|||
}
|
||||
catch (DbException ex)
|
||||
{
|
||||
var pending = IsUnknownObjectError(ex) ? DescribePendingTables(sql) : null;
|
||||
if (pending is not null)
|
||||
throw new UserFriendlyException(L[McpErrorCodes.SelectTableNotInstalled, ex.Message, pending]);
|
||||
|
||||
var columns = IsUnknownColumnError(ex) ? await DescribeTableColumnsAsync(context, sql) : null;
|
||||
throw new UserFriendlyException(columns is null
|
||||
? L[McpErrorCodes.SelectFailed, ex.Message]
|
||||
|
|
@ -129,6 +136,30 @@ public partial class McpQueryAppService(
|
|||
private static bool IsUnknownColumnError(DbException ex) =>
|
||||
ex.SqlState == "42703" || ex.Message.Contains("Invalid column name", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>SQL Server 208 ("Invalid object name"), PostgreSQL 42P01 (undefined_table).</summary>
|
||||
private static bool IsUnknownObjectError(DbException ex) =>
|
||||
ex.SqlState == "42P01" || ex.Message.Contains("Invalid object name", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Sorgunun andigi ve veritabaninda olmayan tablolardan seed scripti olanlar (<c>Tablo(A, B); …</c>).
|
||||
/// <c>create_table</c> tabloyu yalnizca scripte yazar, kurulum DB Migrate'tedir; model ayni talepte
|
||||
/// tabloyu sorgularsa kolon tahmini yuzunden degil kurulum beklendigi icin bos doner. Kolonlar
|
||||
/// scriptten okunur, boylece model sema araci cagirmadan ilerler. Scripti olan tablo yoksa null.
|
||||
/// </summary>
|
||||
private string? DescribePendingTables(string sql)
|
||||
{
|
||||
var described = TableReferenceRegex().Matches(sql)
|
||||
.Select(match => match.Groups["table"].Value)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Take(MaxDescribedTables)
|
||||
.Select(table => (Table: table, Columns: PostgreSqlTableScript.ReadSeedColumns(configuration, table)))
|
||||
.Where(item => item.Columns.Count > 0)
|
||||
.Select(item => $"{item.Table}({string.Join(", ", item.Columns.Keys)})")
|
||||
.ToList();
|
||||
|
||||
return described.Count == 0 ? null : string.Join("; ", described);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorgunun FROM/JOIN ile andigi tablolarin gercek kolonlari (<c>Tablo(A, B, C); …</c>). Model
|
||||
/// kolonu tahmin ettiyse dogru listeyi ayni cevapta gorur ve ayrica sema araci cagirmadan duzeltir.
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ public static class McpErrorCodes
|
|||
public const string SeedRowsInvalid = Prefix + "SeedRowsInvalid";
|
||||
public const string SeedRowsNotAllowed = Prefix + "SeedRowsNotAllowed";
|
||||
public const string SeedRowsUnknownFields = Prefix + "SeedRowsUnknownFields";
|
||||
public const string SeedRowsFieldsOnOtherScreens = Prefix + "SeedRowsFieldsOnOtherScreens";
|
||||
public const string ComponentNameRequired = Prefix + "ComponentNameRequired";
|
||||
public const string ComponentCodeRequired = Prefix + "ComponentCodeRequired";
|
||||
public const string ComponentNotFound = Prefix + "ComponentNotFound";
|
||||
|
|
@ -49,6 +50,7 @@ public static class McpErrorCodes
|
|||
public const string VerifySelectFailed = Prefix + "VerifySelectFailed";
|
||||
public const string SelectFailed = Prefix + "SelectFailed";
|
||||
public const string SelectFailedColumns = Prefix + "SelectFailedColumns";
|
||||
public const string SelectTableNotInstalled = Prefix + "SelectTableNotInstalled";
|
||||
public const string VerifyComponentInactive = Prefix + "VerifyComponentInactive";
|
||||
public const string VerifyComponentRouteMismatch = Prefix + "VerifyComponentRouteMismatch";
|
||||
public const string VerifySeedClosureIncomplete = Prefix + "VerifySeedClosureIncomplete";
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ public class WizardTableCleaner(
|
|||
|
||||
/// <summary>
|
||||
/// Talep silmesinde talebin tablolarini sorgulayan Custom Endpoint'leri veritabanindan ve
|
||||
/// <c>data/App.DeveloperKit.CustomEndpoints.json</c> dosyasindan siler.
|
||||
/// <c>data/App.DeveloperKit.CustomEndpoints/</c> klasorundeki satir dosyalarindan siler.
|
||||
/// </summary>
|
||||
public async Task DeleteCustomEndpointsAsync(IReadOnlyCollection<string> names, List<WizardDeleteLogItemDto> report)
|
||||
{
|
||||
|
|
@ -211,21 +211,28 @@ public class WizardTableCleaner(
|
|||
/// <summary>Henuz migrate edilmemis, yalnizca seed dosyasinda duran ve tabloyu sorgulayan endpoint'ler.</summary>
|
||||
private async Task<List<string>> FindSeedEndpointsAsync(WizardDeleteTableDto table)
|
||||
{
|
||||
var path = ScopeFile(SeedPathResolver.GetDataFilePath(CustomEndpointsListFormCode));
|
||||
if (!File.Exists(path))
|
||||
// Ekran klasor modundadir: her endpoint data/App.DeveloperKit.CustomEndpoints/{Id}.json dosyasindadir.
|
||||
var folder = ScopeFile(SeedPathResolver.GetDataFolderPath(CustomEndpointsListFormCode));
|
||||
if (!Directory.Exists(folder))
|
||||
return [];
|
||||
|
||||
var file = JsonSerializer.Deserialize<ListFormSeedDataFileDto>(await File.ReadAllTextAsync(path), ListFormSeedDataFileDto.JsonOptions);
|
||||
var pattern = TablePattern(table.TableName);
|
||||
var names = new List<string>();
|
||||
|
||||
string? Text(Dictionary<string, object> row, string field) =>
|
||||
row.FirstOrDefault(kv => string.Equals(kv.Key, field, StringComparison.OrdinalIgnoreCase)).Value?.ToString();
|
||||
|
||||
return [.. (file?.Rows ?? [])
|
||||
foreach (var path in Directory.EnumerateFiles(folder, "*.json"))
|
||||
{
|
||||
var file = JsonSerializer.Deserialize<ListFormSeedDataFileDto>(await File.ReadAllTextAsync(path), ListFormSeedDataFileDto.JsonOptions);
|
||||
names.AddRange((file?.Rows ?? [])
|
||||
.Where(row => string.Equals(Text(row, nameof(CustomEndpoint.DataSourceCode)), table.DataSourceCode, StringComparison.OrdinalIgnoreCase) &&
|
||||
Text(row, nameof(CustomEndpoint.Sql)) is { } sql && pattern.IsMatch(sql))
|
||||
.Select(row => Text(row, nameof(CustomEndpoint.Name)))
|
||||
.OfType<string>()];
|
||||
.OfType<string>());
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
private async Task ReadTableStateAsync(WizardDeleteTableDto table)
|
||||
|
|
|
|||
|
|
@ -5563,7 +5563,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
|||
new("POST", "green", "FaPlusCircle", "\"Method\" = 'POST'"),
|
||||
new("PUT", "orange", "FaEdit", "\"Method\" = 'PUT'"),
|
||||
new("DELETE", "red", "FaTrash", "\"Method\" = 'DELETE'")),
|
||||
SeedFilePath = SeedPathResolver.GetDataFilePath(listFormName),
|
||||
SeedFilePath = SeedPathResolver.GetDataFolderPath(listFormName),
|
||||
SeedSyncInsert = true,
|
||||
SeedSyncUpdate = true,
|
||||
SeedSyncDelete = true,
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
|
|||
değer **tek dosyadır** (`data/{ListFormCode}.json`, bütün satırlar orada), uzantısız değer
|
||||
**klasördür** (`data/{ListFormCode}/{anahtar}.json`, her satır kendi dosyasında) ve klasör yoksa
|
||||
ilk kayıtta oluşturulur. Klasör modu satırı büyük ya da sık yazılan ekranlar içindir
|
||||
(varsayılan tek dosya; şu an klasör kullanan tek ekran Custom Components). Applier `data/`
|
||||
(varsayılan tek dosya; şu an klasör kullanan ekranlar Custom Components ve Custom Endpoints). Applier `data/`
|
||||
altını özyinelemeli tarar ve **bir klasörün tamamını tek unit of work'te** uygular — ekran
|
||||
tanımı, alan listesi ve veri kaynağı satır dosyası başına değil ekran başına bir kez çözülür;
|
||||
dosyadaki `ListFormCode` boşsa ekran kodu klasör adından gelir. Tek dosyaya bağlı eski bir kayıt,
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"ListFormCode": "App.DeveloperKit.CustomEndpoints",
|
||||
"KeyFieldName": "Id",
|
||||
"GeneratedAt": "2026-09-04T00:00:00Z",
|
||||
"Order": 0,
|
||||
"Rows": [
|
||||
{
|
||||
"Id": "22cdbe14-f7dc-5771-8553-927ad017db9e",
|
||||
"Name": "Langugage",
|
||||
"Description": "https://localhost:44344/api/app/custom-endpoint/dil/en",
|
||||
"Url": "/dil/",
|
||||
"Method": "GET",
|
||||
"DataSourceCode": "Default",
|
||||
"Sql": "SELECT * FROM Sas_H_Language WHERE IsEnabled = @IsEnabled AND CultureName = @CultureName",
|
||||
"ParametersJson": "[{\"Type\":\"Path\",\"Name\":\"CultureName\",\"DefaultValue\":\"ar\",\"Path\":\"/dil/:CultureName/\",\"IsRequired\":false},{\"Type\":\"Static\",\"Name\":\"IsEnabled\",\"DefaultValue\":\"true\",\"Path\":null,\"IsRequired\":false}]",
|
||||
"PermissionsJson": "[{\"ResourceType\":\"User\",\"ResourceId\":\"system@sozsoft.com\"}]"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -2,18 +2,8 @@
|
|||
"ListFormCode": "App.DeveloperKit.CustomEndpoints",
|
||||
"KeyFieldName": "Id",
|
||||
"GeneratedAt": "2026-09-04T00:00:00Z",
|
||||
"Order": 0,
|
||||
"Rows": [
|
||||
{
|
||||
"Id": "22cdbe14-f7dc-5771-8553-927ad017db9e",
|
||||
"Name": "Langugage",
|
||||
"Description": "https://localhost:44344/api/app/custom-endpoint/dil/en",
|
||||
"Url": "/dil/",
|
||||
"Method": "GET",
|
||||
"DataSourceCode": "Default",
|
||||
"Sql": "SELECT * FROM Sas_H_Language WHERE IsEnabled = @IsEnabled AND CultureName = @CultureName",
|
||||
"ParametersJson": "[{\"Type\":\"Path\",\"Name\":\"CultureName\",\"DefaultValue\":\"ar\",\"Path\":\"/dil/:CultureName/\",\"IsRequired\":false},{\"Type\":\"Static\",\"Name\":\"IsEnabled\",\"DefaultValue\":\"true\",\"Path\":null,\"IsRequired\":false}]",
|
||||
"PermissionsJson": "[{\"ResourceType\":\"User\",\"ResourceId\":\"system@sozsoft.com\"}]"
|
||||
},
|
||||
{
|
||||
"Id": "3c8b861f-abfa-5db3-8d93-8c1a08605ac5",
|
||||
"Name": "HrAttendancePdks",
|
||||
|
|
@ -69150,6 +69150,20 @@
|
|||
"Key": "App.Mcp.Error.SeedRowsUnknownFields",
|
||||
"Value": "seedRows ekranda olmayan alanlar içeriyor: {0}. Ekranın alanları: {1}."
|
||||
},
|
||||
{
|
||||
"Id": "e24ee936-c5cf-5839-840b-5ade854f8310",
|
||||
"CultureName": "en",
|
||||
"ResourceName": "Platform",
|
||||
"Key": "App.Mcp.Error.SeedRowsFieldsOnOtherScreens",
|
||||
"Value": "seedRows contains fields that are not on the screen: {0}. These columns are fields of other screens on the same table ({1}); migrate writes a demo row only into columns that are fields of this screen. Add them to this screen's Groups (IncludeInEditingForm: false if they belong to another tab) or remove them from the rows, then deploy again. Screen fields: {2}."
|
||||
},
|
||||
{
|
||||
"Id": "41b2c0c2-a87d-5b3c-9f42-49395ff075c5",
|
||||
"CultureName": "tr",
|
||||
"ResourceName": "Platform",
|
||||
"Key": "App.Mcp.Error.SeedRowsFieldsOnOtherScreens",
|
||||
"Value": "seedRows ekranda olmayan alanlar içeriyor: {0}. Bu kolonlar aynı tablonun başka ekranlarında alan ({1}); migrate demo satırı yalnızca bu ekranın alanı olan kolonlara yazar. Kolonları bu ekranın Groups'una ekle (başka bir sekmeye aitse IncludeInEditingForm: false) ya da satırlardan çıkar, sonra tekrar deploy et. Ekranın alanları: {2}."
|
||||
},
|
||||
{
|
||||
"Id": "fe038e1e-68b6-5cfe-ad9e-42c8e58f01bb",
|
||||
"CultureName": "en",
|
||||
|
|
@ -69318,6 +69332,20 @@
|
|||
"Key": "App.Mcp.Error.SelectFailedColumns",
|
||||
"Value": "Sorgu çalışmadı: {0} Sorgudaki tabloların gerçek kolonları: {1}. Sorguyu yalnızca bu kolonlarla yeniden yaz; kolon adı tahmin etme."
|
||||
},
|
||||
{
|
||||
"Id": "b408c374-3a88-54be-868f-6417e96bdd1e",
|
||||
"CultureName": "en",
|
||||
"ResourceName": "Platform",
|
||||
"Key": "App.Mcp.Error.SelectTableNotInstalled",
|
||||
"Value": "The query failed: {0} These tables are defined in seed scripts but not installed in the database yet: {1}. create_table only writes the script; the table is created when the user runs DB Migrate. Do not query or retry them in this request: there are no rows to read. Use the columns listed here and continue (deploy_wizard reads them from the script); tell the user that DB Migrate is required."
|
||||
},
|
||||
{
|
||||
"Id": "259012b8-fcf6-5995-a411-90d6aa6fabcc",
|
||||
"CultureName": "tr",
|
||||
"ResourceName": "Platform",
|
||||
"Key": "App.Mcp.Error.SelectTableNotInstalled",
|
||||
"Value": "Sorgu çalışmadı: {0} Bu tablolar seed scriptinde tanımlı ama veritabanına henüz kurulmadı: {1}. create_table yalnızca scripti yazar; tabloyu kullanıcının çalıştırdığı DB Migrate kurar. Bu talepte tabloları sorgulama ya da tekrar deneme: okunacak satır yok. Buradaki kolonlarla devam et (deploy_wizard kolonları scriptten okur); kullanıcıya DB Migrate gerektiğini bildir."
|
||||
},
|
||||
{
|
||||
"Id": "aac27480-88f4-5230-9820-f9c7472ef178",
|
||||
"CultureName": "en",
|
||||
|
|
|
|||
|
|
@ -1496,7 +1496,7 @@ grubu, `App.HrSettings` altında). Hiçbir yetki role otomatik atanmaz.
|
|||
| Çalışma Takvimi | → izin, → puantaj | Tatil `Holiday`, arife `HalfDay` (yarım vardiya); takvim kaydı denk gelen izinlerin gün sayısını ve puantajı hemen yeniler (`Hr_S_WorkCalendarAfterSave`) |
|
||||
| Vardiyalar / kullanıcı vardiyası | → puantaj | Saat, mola, tolerans; değişiklik gece işinde ya da dönem kaydında yansır |
|
||||
| İzin ayarları | → puantaj | Hafta tatili günleri |
|
||||
| PDKS | → hareket | Custom Endpoint `POST /api/app/custom-endpoint/hr/attendance/` (`data/App.DeveloperKit.CustomEndpoints.json`, `PermissionsJson`: rol `PDKS`) |
|
||||
| PDKS | → hareket | Custom Endpoint `POST /api/app/custom-endpoint/hr/attendance/` (`data/App.DeveloperKit.CustomEndpoints/3c8b861f-abfa-5db3-8d93-8c1a08605ac5.json`, `PermissionsJson`: rol `PDKS`) |
|
||||
| Excel | → hareket | Günlük Hareketler import'u aynı kayıt yolundan (`InsertAfterCommand`) geçer; `Source` boş gelir ve `Import` yazılır |
|
||||
| Intranet | ← puantaj | `my-timesheet` widget'ı |
|
||||
| Kullanıcı detayı | ← puantaj | Puantaj sekmesi |
|
||||
|
|
@ -1577,7 +1577,7 @@ Custom Endpoints'ten aynı SQL ve parametrelerle eklenir.
|
|||
| `configs/seeds/wizard/Shift.json` | Tolerans alanları |
|
||||
| `configs/seeds/data/App.DeveloperKit.CustomComponents/1bca19aa-e144-5e4c-b23b-9eddd4dafd19.json` | `MyTimesheetWidget` |
|
||||
| `configs/seeds/data/App.DeveloperKit.IntranetWidgets.json` | `my-timesheet` |
|
||||
| `configs/seeds/data/App.DeveloperKit.CustomEndpoints.json` | PDKS ucu |
|
||||
| `configs/seeds/data/App.DeveloperKit.CustomEndpoints/3c8b861f-abfa-5db3-8d93-8c1a08605ac5.json` | PDKS ucu |
|
||||
| `configs/seeds/data/App.BackgroundWorkers.RecurringJobs.json` | `Timesheet Nightly` |
|
||||
| `configs/seeds/data/App.SettingDefinitions.json` | `App.HrSettings.Attendance.*` |
|
||||
| `configs/seeds/data/{App.Menus.Menu,Abp.Identity.Permissions,App.Languages.LanguageText}.json` | Menü, yetki, dil |
|
||||
|
|
|
|||
Loading…
Reference in a new issue