Event Log komponenti ve mcp hataları düzeltildi

This commit is contained in:
Sedat ÖZTÜRK 2026-10-02 15:46:52 +03:00
parent 021a8a346f
commit e05c44f295
20 changed files with 3973 additions and 24 deletions

View file

@ -709,6 +709,12 @@ Kısa ve karar odaklı yaz; talebi tekrar anlatma.
üç seviyedir; analiz talebin istemediği bir ara seviye eklemez. Talep menü yolunu yazıyorsa üç seviyedir; analiz talebin istemediği bir ara seviye eklemez. Talep menü yolunu yazıyorsa
(başlıkta ya da açıklamada) o yol girdidir ve seviye seviye aynen alınır. Wizard karşılığı: (başlıkta ya da açıklamada) o yol girdidir ve seviye seviye aynen alınır. Wizard karşılığı:
ekranın bir üstü `MenuParentCode`, daha üstündekiler `MenuParentPath` (iki seviyede boş, §4.4). ekranın bir üstü `MenuParentCode`, daha üstündekiler `MenuParentPath` (iki seviyede boş, §4.4).
Seviyenin kodu menü kaydının `Code`'udur, `DisplayName` dil anahtarı değildir: "Human Resources ›
Definitions" `App.Hr.Definitions`'tır, `App.Platform.Definitions` değil. Deploy yine de yanlış
yazılmış yolu var olan dala bağlar: kodu bulunamayan seviye, aynı üstün altında `DisplayName`
anahtarı koda eşit ya da EN/TR adı aynı olan bir dal varsa o dalın koduna çevrilir
(`ListFormWizardAppService.BindExistingMenuParentsAsync`); ikinci bir ara menü ve ara yetki
açılmaz. Eşleşme yoksa seviye yenidir ve kurulur.
**Yetki ağacı menü ağacıyla aynıdır**: deploy, izin grubu dışındaki her menü seviyesini aynı **Yetki ağacı menü ağacıyla aynıdır**: deploy, izin grubu dışındaki her menü seviyesini aynı
kodlu ara yetki yapar ve ekranın okuma yetkisini onun altına yazar. Analiz bunu menü tablosunun kodlu ara yetki yapar ve ekranın okuma yetkisini onun altına yazar. Analiz bunu menü tablosunun
altında tek satırda gösterir — `Yetki: {İzin grubu} › {Ara yetki} › {ListFormCode}` — ve her ara altında tek satırda gösterir — `Yetki: {İzin grubu} › {Ara yetki} › {ListFormCode}` — ve her ara
@ -1678,7 +1684,7 @@ ile ekler (§4.0). Sıra değerleri veritabanı ile dosyadaki satırların birle
| Dil anahtarları | `{MenuCode}` (menü), `{ListFormCode}.Title`, `{ListFormCode}.Desc`, `{PermissionGroupName}` ve her alan için `CaptionName` | | Dil anahtarları | `{MenuCode}` (menü), `{ListFormCode}.Title`, `{ListFormCode}.Desc`, `{PermissionGroupName}` ve her alan için `CaptionName` |
| Yetkiler | `{MenuCode}` kökü + `.Create/.Update/.Delete` (+ List yolunda `.Export/.Import/.Note`) | | Yetkiler | `{MenuCode}` kökü + `.Create/.Update/.Delete` (+ List yolunda `.Export/.Import/.Note`) |
| Yetkilerin dil anahtarları | Ortak sabitler: `App.Platform.Create/Update/Delete/Export/Import/Note` | | Yetkilerin dil anahtarları | Ortak sabitler: `App.Platform.Create/Update/Delete/Export/Import/Note` |
| Üst menü zinciri | `MenuParentPath` + `MenuParentCode` kökten yürünür; eksik seviye bir üstünün altına `Order = max(kardeş Order) + 1` ile yaratılır (kökte kök menülerin sonu) | | Üst menü zinciri | `MenuParentPath` + `MenuParentCode` kökten yürünür; kodu bulunamayan seviye önce aynı üstün altındaki dallarla adıyla eşleştirilir (dalın `DisplayName` anahtarı = verilen kod, ya da EN/TR adı aynı) ve eşleşen dalın koduna bağlanır; eşleşme yoksa bir üstünün altına `Order = max(kardeş Order) + 1` ile yaratılır (kökte kök menülerin sonu) |
| Menü sırası | `MenuOrder` 0/boş ise `max(kardeş Order) + 1` | | Menü sırası | `MenuOrder` 0/boş ise `max(kardeş Order) + 1` |
| `DataSource` | `DataSourceCode` yoksa migrate yaratır; bağlantı metninde `Server` geçiyorsa `Mssql`, aksi hâlde `Postgresql` | | `DataSource` | `DataSourceCode` yoksa migrate yaratır; bağlantı metninde `Server` geçiyorsa `Mssql`, aksi hâlde `Postgresql` |
| `LayoutJson` | Görünüm bayrakları + `DefaultLayout` | | `LayoutJson` | Görünüm bayrakları + `DefaultLayout` |

View file

@ -951,7 +951,11 @@ zincirinden kurar, böylece çocuk her zaman ebeveyninin altında kalır. Değer
yazar: üst menü zincirindeki (`MenuParentPath` + `MenuParentCode`) her seviye, izin grubunun yazar: üst menü zincirindeki (`MenuParentPath` + `MenuParentCode`) her seviye, izin grubunun
kendisi hariç, aynı kodlu bir ara yetkidir (`İnsan Kaynakları › Tanımlamalar › Ekran` → kendisi hariç, aynı kodlu bir ara yetkidir (`İnsan Kaynakları › Tanımlamalar › Ekran` →
`App.Hr.Definitions › App.Hr.Doctor`). Var olan ara yetki kullanılır, eksik olan menü seviyesinin `App.Hr.Definitions › App.Hr.Doctor`). Var olan ara yetki kullanılır, eksik olan menü seviyesinin
görünen adıyla wizard'a ait üretilir; başka bir gruptaki aynı adlı yetki atlanır. Menüsüz wizard'ın görünen adıyla wizard'a ait üretilir; başka bir gruptaki aynı adlı yetki atlanır. Kodu bulunamayan
bir seviye önce aynı üstün altındaki dallarla adıyla eşleştirilir (dalın `DisplayName` anahtarı =
verilen kod ya da EN/TR adı aynı) ve eşleşen dalın koduna bağlanır; böylece MCP'nin yalnızca yol
verdiği deploy'da ikinci bir "Tanımlamalar" menüsü ve ara yetkisi oluşmaz
(`ListFormWizardAppService.BindExistingMenuParentsAsync`). Menüsüz wizard'ın
(`CreateMenu: false`, alt form) okuma yetkisi onu `SubForms` içinde taşıyan listenin yetkisine (`CreateMenu: false`, alt form) okuma yetkisi onu `SubForms` içinde taşıyan listenin yetkisine
bağlanır: `ParentName` = listenin yetki kodu (`App.Hr.HealthCard › App.Hr.HealthCardFile`), sırası bağlanır: `ParentName` = listenin yetki kodu (`App.Hr.HealthCard › App.Hr.HealthCardFile`), sırası
listenin alt yetkilerinin (Create/Update/…) ardındandır. Alt form listeden önce deploy edildiği için listenin alt yetkilerinin (Create/Update/…) ardındandır. Alt form listeden önce deploy edildiği için

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Common;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -105,7 +106,17 @@ public class McpQueryAppService(
var context = await queryExecutor.ResolveDataSourceAsync(); var context = await queryExecutor.ResolveDataSourceAsync();
var limitedSql = sqlGuard.ApplyRowLimit(sql, maxRows, context.DataSourceType); var limitedSql = sqlGuard.ApplyRowLimit(sql, maxRows, context.DataSourceType);
return ToResult(await queryExecutor.ExecuteAsync(context, limitedSql, parameters, maxRows)); // Sorguyu model yazar ve tablonun kolonlarini tahmin eder (her tabloda IsDeleted yok).
// Saglayici hatasi cevrilmezse istemciye yalnizca genel hata gider ve model sorguyu
// duzeltemez. Arac zaten SQL yetkisi istedigi icin hata metni yeni bilgi sizdirmaz.
try
{
return ToResult(await queryExecutor.ExecuteAsync(context, limitedSql, parameters, maxRows));
}
catch (DbException ex)
{
throw new UserFriendlyException(L[McpErrorCodes.SelectFailed, ex.Message]);
}
} }
public async Task<List<McpSavedQueryDto>> GetSavedQueriesAsync(string? search = null) public async Task<List<McpSavedQueryDto>> GetSavedQueriesAsync(string? search = null)

View file

@ -47,6 +47,7 @@ public static class McpErrorCodes
public const string VerifyPermissionMissing = Prefix + "VerifyPermissionMissing"; public const string VerifyPermissionMissing = Prefix + "VerifyPermissionMissing";
public const string VerifySelectPassed = Prefix + "VerifySelectPassed"; public const string VerifySelectPassed = Prefix + "VerifySelectPassed";
public const string VerifySelectFailed = Prefix + "VerifySelectFailed"; public const string VerifySelectFailed = Prefix + "VerifySelectFailed";
public const string SelectFailed = Prefix + "SelectFailed";
public const string VerifyComponentInactive = Prefix + "VerifyComponentInactive"; public const string VerifyComponentInactive = Prefix + "VerifyComponentInactive";
public const string VerifyComponentRouteMismatch = Prefix + "VerifyComponentRouteMismatch"; public const string VerifyComponentRouteMismatch = Prefix + "VerifyComponentRouteMismatch";
public const string VerifySeedClosureIncomplete = Prefix + "VerifySeedClosureIncomplete"; public const string VerifySeedClosureIncomplete = Prefix + "VerifySeedClosureIncomplete";

View file

@ -42,7 +42,7 @@ public sealed class McpQueryTools(IMcpQueryAppService queryAppService)
}); });
[McpServerTool(Name = McpToolNames.RunSelect, ReadOnly = true)] [McpServerTool(Name = McpToolNames.RunSelect, ReadOnly = true)]
[Description("Yalnizca uygulamada SQL Query Manager yetkisi olan kullanicilar icin: tek bir parametreli SELECT ifadesi kosturur. Liste verisi icin query_list tercih edilir. Coklu ifade, DDL ve DML reddedilir; satir sayisi sunucu kaydindaki tavana kirpilir. Sorguya deger gomme, @ad parametresi kullan.")] [Description("Yalnizca uygulamada SQL Query Manager yetkisi olan kullanicilar icin: tek bir parametreli SELECT ifadesi kosturur. Liste verisi icin query_list tercih edilir. Coklu ifade, DDL ve DML reddedilir; satir sayisi sunucu kaydindaki tavana kirpilir. Sorguya deger gomme, @ad parametresi kullan. Kolonun var oldugunu varsayma: IsDeleted, TenantId, IsActive her tabloda yoktur; emin degilsen once INFORMATION_SCHEMA.COLUMNS (PostgreSQL: information_schema.columns) uzerinden tablonun kolonlarini oku, filtreyi yalnizca var olan kolona yaz.")]
public async Task<McpQueryResultDto> RunSelectAsync( public async Task<McpQueryResultDto> RunSelectAsync(
[Description("Tek bir SELECT (ya da WITH ... SELECT) ifadesi. Degerler @ad bicimindeki parametrelerle verilir.")] [Description("Tek bir SELECT (ya da WITH ... SELECT) ifadesi. Degerler @ad bicimindeki parametrelerle verilir.")]
string sql, string sql,

View file

@ -121,6 +121,7 @@ public class ListFormWizardAppService(
input.SeededAt = previous.Wizard.SeededAt; input.SeededAt = previous.Wizard.SeededAt;
var rows = await WizardSeedRowStore.LoadAsync(ResolveScopeRoot()); var rows = await WizardSeedRowStore.LoadAsync(ResolveScopeRoot());
await BindExistingMenuParentsAsync(input, rows, previous);
// Ad ve kod catismalari, dosyalar yazilmaya baslamadan once reddedilir; aksi halde yarim // Ad ve kod catismalari, dosyalar yazilmaya baslamadan once reddedilir; aksi halde yarim
// kalan bir deploy mevcut menu/permission satirlarini bozabilir. // kalan bir deploy mevcut menu/permission satirlarini bozabilir.
@ -139,6 +140,73 @@ public class ListFormWizardAppService(
await DeployWizardAsync(input, previous, editFileName, rows, devRequest); await DeployWizardAsync(input, previous, editFileName, rows, devRequest);
} }
/// <summary>
/// Ust menu zincirinde var olmayan bir seviye, ayni ustun altinda ayni ada sahip bir dal varsa o
/// dalin koduna baglanir. Model (ya da kullanici) dalin kodu yerine dil anahtarini
/// (<c>App.Platform.Definitions</c>) ya da yeni bir kod verdiginde deploy ikinci bir "Tanimlamalar"
/// menusu ve ara yetkisi acmaz; ekran var olan dalin altina, yetkisi de o dalin yetkisinin altina
/// yazilir. Ad, dalin dil anahtariyla ya da EN/TR metniyle karsilastirilir. Wizard'in onceki
/// surumde kendisinin kurdugu seviye var sayilir ve degistirilmez.
/// </summary>
private async Task BindExistingMenuParentsAsync(ListFormWizardDto input, WizardSeedRowStore rows, WizardSeedFileDto? previous)
{
static bool Same(string? a, string? b) => string.Equals(a?.Trim(), b?.Trim(), StringComparison.OrdinalIgnoreCase);
var chain = input.ResolveMenuParentChain();
if (chain.Count == 0)
return;
var ownedCodes = previous?.InsertedRecords?.MenuCodes ?? [];
var menus = (await repoMenu.GetListAsync())
.Select(m => (Code: (string?)m.Code, ParentCode: (string?)m.ParentCode, DisplayName: (string?)m.DisplayName))
.Concat(rows.Rows(WizardSeedRowStore.MenuFile).Select(r => (
Code: WizardSeedRowStore.Text(r, nameof(Menu.Code)),
ParentCode: WizardSeedRowStore.Text(r, nameof(Menu.ParentCode)),
DisplayName: WizardSeedRowStore.Text(r, nameof(Menu.DisplayName)))))
.Where(m => !string.IsNullOrWhiteSpace(m.Code))
.ToList();
var changed = false;
string? parentCode = null;
foreach (var level in chain)
{
var exists = menus.Any(m => Same(m.Code, level.Code)) ||
ownedCodes.Contains(level.Code, StringComparer.OrdinalIgnoreCase);
if (!exists)
{
foreach (var sibling in menus.Where(m => Same(m.ParentCode ?? string.Empty, parentCode ?? string.Empty)))
{
var displayKey = string.IsNullOrWhiteSpace(sibling.DisplayName) ? sibling.Code! : sibling.DisplayName;
var (en, tr) = await GetLangTextsAsync(rows, displayKey);
if (Same(displayKey, level.Code) ||
(!string.IsNullOrWhiteSpace(level.En) && Same(en, level.En)) ||
(!string.IsNullOrWhiteSpace(level.Tr) && Same(tr, level.Tr)))
{
level.Code = sibling.Code;
changed = true;
break;
}
}
}
parentCode = level.Code;
}
if (!changed)
return;
if (string.IsNullOrWhiteSpace(input.MenuParentCode))
{
input.MenuParentPath = chain;
return;
}
input.MenuParentCode = chain[^1].Code;
input.MenuParentPath = chain[..^1];
}
/// <summary> /// <summary>
/// Dosyaya yazilacak talep bagi. MCP etkin talebi verdiyse o talep yazilir; ayni wizard'i /// Dosyaya yazilacak talep bagi. MCP etkin talebi verdiyse o talep yazilir; ayni wizard'i
/// sonradan baska bir talep degistirirse bag o talebe gecer ve talep export'u degisikligi tasir. /// sonradan baska bir talep degistirirse bag o talebe gecer ve talep export'u degisikligi tasir.

View file

@ -8183,6 +8183,146 @@
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"Modules": "Hr" "Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.Shift",
"ParentName": "App.Hr.Definitions",
"DisplayName": "App.Hr.Shift",
"Order": 11,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.Shift.Create",
"ParentName": "App.Hr.Shift",
"DisplayName": "App.Platform.Create",
"Order": 1,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.Shift.Update",
"ParentName": "App.Hr.Shift",
"DisplayName": "App.Platform.Update",
"Order": 2,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.Shift.Delete",
"ParentName": "App.Hr.Shift",
"DisplayName": "App.Platform.Delete",
"Order": 3,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.Shift.Export",
"ParentName": "App.Hr.Shift",
"DisplayName": "App.Platform.Export",
"Order": 4,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.Shift.Import",
"ParentName": "App.Hr.Shift",
"DisplayName": "App.Platform.Import",
"Order": 5,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.Shift.Note",
"ParentName": "App.Hr.Shift",
"DisplayName": "App.Platform.Note",
"Order": 6,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.EventLog",
"ParentName": null,
"DisplayName": "App.Hr.EventLog",
"Order": 14,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.EventLog.Create",
"ParentName": "App.Hr.EventLog",
"DisplayName": "App.Platform.Create",
"Order": 1,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.EventLog.Update",
"ParentName": "App.Hr.EventLog",
"DisplayName": "App.Platform.Update",
"Order": 2,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.EventLog.Delete",
"ParentName": "App.Hr.EventLog",
"DisplayName": "App.Platform.Delete",
"Order": 3,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.EventLog.Export",
"ParentName": "App.Hr.EventLog",
"DisplayName": "App.Platform.Export",
"Order": 4,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.EventLog.Import",
"ParentName": "App.Hr.EventLog",
"DisplayName": "App.Platform.Import",
"Order": 5,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
},
{
"GroupName": "App.Hr",
"Name": "App.Hr.EventLog.Note",
"ParentName": "App.Hr.EventLog",
"DisplayName": "App.Platform.Note",
"Order": 6,
"IsEnabled": true,
"MultiTenancySide": 3,
"Modules": "Hr"
} }
] ]
} }

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

View file

@ -0,0 +1,29 @@
{
"ListFormCode": "App.Hr.Shift",
"KeyFieldName": "Id",
"GeneratedAt": "2026-10-02T12:05:29.2891234Z",
"Order": 0,
"Rows": [
{
"Name": "Sabah",
"StartTime": "08:00",
"EndTime": "16:00",
"IsActive": true,
"Id": "df1b7d79-07a5-4afd-5c2c-3a240eae2c48"
},
{
"Name": "Akşam",
"StartTime": "16:00",
"EndTime": "00:00",
"IsActive": true,
"Id": "72968eb6-c7b5-1ab2-942b-3a240eae2c49"
},
{
"Name": "Gece",
"StartTime": "00:00",
"EndTime": "08:00",
"IsActive": true,
"Id": "6d625cbb-aec9-4edf-86d2-3a240eae2c49"
}
]
}

View file

@ -69080,6 +69080,20 @@
"Key": "App.Mcp.Error.VerifySelectFailed", "Key": "App.Mcp.Error.VerifySelectFailed",
"Value": "Ekran sorgusu başarısız: {0}" "Value": "Ekran sorgusu başarısız: {0}"
}, },
{
"Id": "ffd914ea-7f36-58e1-a72a-506b7eb07cb9",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Mcp.Error.SelectFailed",
"Value": "The query failed: {0} Do not assume a column exists (IsDeleted, TenantId, IsActive are not on every table); check the table's columns with search_schema or a SELECT on INFORMATION_SCHEMA.COLUMNS, then fix the query."
},
{
"Id": "beb659d6-fabd-5964-be42-ffe996044afc",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Mcp.Error.SelectFailed",
"Value": "Sorgu çalışmadı: {0} Bir kolonun var olduğunu varsayma (IsDeleted, TenantId, IsActive her tabloda yoktur); tablonun kolonlarını search_schema ya da INFORMATION_SCHEMA.COLUMNS üzerinde bir SELECT ile kontrol edip sorguyu düzelt."
},
{ {
"Id": "aac27480-88f4-5230-9820-f9c7472ef178", "Id": "aac27480-88f4-5230-9820-f9c7472ef178",
"CultureName": "en", "CultureName": "en",
@ -74917,6 +74931,202 @@
"ResourceName": "Platform", "ResourceName": "Platform",
"Key": "App.ListFormField.DragToReorder", "Key": "App.ListFormField.DragToReorder",
"Value": "Sürükleyerek sırala" "Value": "Sürükleyerek sırala"
},
{
"Id": "35a42330-e286-5fb5-9d9e-b61749533a17",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.Shift",
"Value": "Shifts"
},
{
"Id": "2c426526-1141-569f-ad8f-7b2b2c0efd35",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.Shift",
"Value": "Vardiyalar"
},
{
"Id": "bb0b9c7a-cde2-5ed0-8c27-6950ea7f3b53",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.Shift.Title",
"Value": "Shifts"
},
{
"Id": "ff8eb858-9c0a-5b9e-8181-bdc6a6a16ab5",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.Shift.Title",
"Value": "Vardiyalar"
},
{
"Id": "3d3d8758-b436-5159-9708-007993e8eeab",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.Shift.Desc",
"Value": "Shift definitions"
},
{
"Id": "cf02c928-6d89-517a-8d38-69526f714816",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.Shift.Desc",
"Value": "Vardiya tanımları"
},
{
"Id": "aeb48e3b-03d4-5adb-a19d-e437a8d2a7b4",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.ShiftName",
"Value": "Shift Name"
},
{
"Id": "78ad15d9-5df6-5f12-88e5-44bfadf139a0",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.ShiftName",
"Value": "Vardiya Adı"
},
{
"Id": "9c1aa263-53d3-5870-8cbd-ae9cc6fed884",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.EventLog",
"Value": "Event Log"
},
{
"Id": "7b2a90ad-f9d7-5edb-a532-8976c3b7bfdd",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.EventLog",
"Value": "Olay Günlüğü"
},
{
"Id": "2cdc7085-010a-57b4-a1b0-92b822160bae",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.EventLog.Title",
"Value": "Event Log"
},
{
"Id": "5aa973c2-efcd-5d74-aa8c-d81f32455e9d",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.EventLog.Title",
"Value": "Olay Günlüğü"
},
{
"Id": "4aa7bad2-8c10-5f8a-ae6c-e31d5af3234d",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.EventLog.Desc",
"Value": "Important events recorded by shift supervisors, security and observation rooms"
},
{
"Id": "b3e31a80-2040-594e-8019-172da369656f",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.EventLog.Desc",
"Value": "Vardiya amiri, güvenlik ve gözlem odasının kaydettiği önemli olaylar"
},
{
"Id": "b41120f5-2c85-50a4-a6f4-9745641e0330",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.EventLog.Widget.Important",
"Value": "Important"
},
{
"Id": "cf863bdb-3b42-53db-a8b6-b7adf7298001",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.EventLog.Widget.Important",
"Value": "Önemli"
},
{
"Id": "aa2b144c-246a-5da6-a51f-99a12aed48f7",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.LogSource",
"Value": "Source"
},
{
"Id": "f35114e6-4f92-5177-ba2a-d1a0ebc26a49",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.LogSource",
"Value": "Kaynak"
},
{
"Id": "5b2206b0-e108-5e3a-a2e3-376a13b06425",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.EventUserId",
"Value": "Person Involved"
},
{
"Id": "fc6db7c5-13de-54bc-8e41-030e3f610dd9",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.EventUserId",
"Value": "Vardiya Amiri / Olayı Yaşayan"
},
{
"Id": "124e1013-22c9-591a-8993-174fb9036cb5",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.EventDate",
"Value": "Event Date"
},
{
"Id": "ec854e6d-a44e-54b0-ba08-5e1b0339cb83",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.EventDate",
"Value": "Olay Tarihi"
},
{
"Id": "9f0010c1-702c-5bd9-81dc-56b3ca171341",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.EventTime",
"Value": "Event Time"
},
{
"Id": "75fe3dff-f1fe-56de-ba17-681f507e655a",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.EventTime",
"Value": "Olay Saati"
},
{
"Id": "51bc2879-a43d-5fef-a425-92000db88fce",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.ShiftId",
"Value": "Shift"
},
{
"Id": "06cd6a46-45b4-5d04-9a7d-96072355f654",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.ShiftId",
"Value": "Vardiya"
},
{
"Id": "c4bebb07-722e-5292-a6d1-43ca79ac6b24",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.CreatorId",
"Value": "Created By"
},
{
"Id": "cf65fff8-a56e-5b77-bad3-a144c881b8fe",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Listform.ListformField.CreatorId",
"Value": "Kayıt"
} }
] ]
} }

View file

@ -1583,7 +1583,7 @@
"Id": "ae8c7c61-8b57-4335-bacb-d54bcce3d661", "Id": "ae8c7c61-8b57-4335-bacb-d54bcce3d661",
"Code": "App.Hr.Visitor", "Code": "App.Hr.Visitor",
"DisplayName": "App.Hr.Visitor", "DisplayName": "App.Hr.Visitor",
"Order": 4, "Order": 7,
"Url": "/admin/list/App.Hr.Visitor", "Url": "/admin/list/App.Hr.Visitor",
"Icon": "FcBusinessman", "Icon": "FcBusinessman",
"ParentCode": "App.Hr", "ParentCode": "App.Hr",
@ -1598,7 +1598,7 @@
"Id": "8803f8c5-e85b-491d-9330-a9dd5a95f1a1", "Id": "8803f8c5-e85b-491d-9330-a9dd5a95f1a1",
"Code": "App.Hr.HealthCard", "Code": "App.Hr.HealthCard",
"DisplayName": "App.Hr.HealthCard", "DisplayName": "App.Hr.HealthCard",
"Order": 2, "Order": 4,
"Url": "/admin/list/App.Hr.HealthCard", "Url": "/admin/list/App.Hr.HealthCard",
"Icon": "FcInspection", "Icon": "FcInspection",
"ParentCode": "App.Hr", "ParentCode": "App.Hr",
@ -1610,135 +1610,213 @@
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr", "Id": "aa47dc14-483f-41ad-83f5-f304050db135",
"Code": "App.Hr.Trainings", "Code": "App.Hr.Trainings",
"DisplayName": "App.Hr.Trainings", "DisplayName": "App.Hr.Trainings",
"Order": 5, "Order": 5,
"Url": null, "Url": null,
"Icon": "FcGraduationCap", "Icon": "FcGraduationCap",
"ParentCode": "App.Hr",
"RequiredPermissionName": null, "RequiredPermissionName": null,
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Trainings", "Id": "0912d86d-80ee-48b2-8926-560112cf24d1",
"Code": "App.Hr.TrainingType", "Code": "App.Hr.TrainingType",
"DisplayName": "App.Hr.TrainingType", "DisplayName": "App.Hr.TrainingType",
"Order": 1, "Order": 1,
"Url": "/admin/list/App.Hr.TrainingType", "Url": "/admin/list/App.Hr.TrainingType",
"Icon": "FcList", "Icon": "FcList",
"ParentCode": "App.Hr.Trainings",
"RequiredPermissionName": "App.Hr.TrainingType", "RequiredPermissionName": "App.Hr.TrainingType",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Trainings", "Id": "484a01d3-b27d-4453-8411-a31f88d05a23",
"Code": "App.Hr.TrainingSubject", "Code": "App.Hr.TrainingSubject",
"DisplayName": "App.Hr.TrainingSubject", "DisplayName": "App.Hr.TrainingSubject",
"Order": 2, "Order": 2,
"Url": "/admin/list/App.Hr.TrainingSubject", "Url": "/admin/list/App.Hr.TrainingSubject",
"Icon": "FcViewDetails", "Icon": "FcViewDetails",
"ParentCode": "App.Hr.Trainings",
"RequiredPermissionName": "App.Hr.TrainingSubject", "RequiredPermissionName": "App.Hr.TrainingSubject",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Trainings", "Id": "b35fc8d6-a535-41ff-9b28-ef4ae900187f",
"Code": "App.Hr.Training", "Code": "App.Hr.Training",
"DisplayName": "App.Hr.Training", "DisplayName": "App.Hr.Training",
"Order": 3, "Order": 3,
"Url": "/admin/list/App.Hr.Training", "Url": "/admin/list/App.Hr.Training",
"Icon": "FcGraduationCap", "Icon": "FcGraduationCap",
"ParentCode": "App.Hr.Trainings",
"RequiredPermissionName": "App.Hr.Training", "RequiredPermissionName": "App.Hr.Training",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr", "Id": "18146db0-b2aa-49d8-b39c-0165a1d85e53",
"Code": "App.Hr.Vehicles", "Code": "App.Hr.Vehicles",
"DisplayName": "App.Hr.Vehicles", "DisplayName": "App.Hr.Vehicles",
"Order": 6, "Order": 6,
"Url": null, "Url": null,
"Icon": "FcAutomotive", "Icon": "FcAutomotive",
"ParentCode": "App.Hr",
"RequiredPermissionName": null, "RequiredPermissionName": null,
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Vehicles", "Id": "1d5c26e2-c8eb-49b4-99d3-e77b76220d2c",
"Code": "App.Hr.VehicleDocument", "Code": "App.Hr.VehicleDocument",
"DisplayName": "App.Hr.VehicleDocument", "DisplayName": "App.Hr.VehicleDocument",
"Order": 1, "Order": 1,
"Url": "/admin/list/App.Hr.VehicleDocument", "Url": "/admin/list/App.Hr.VehicleDocument",
"Icon": "FcDocument", "Icon": "FcDocument",
"ParentCode": "App.Hr.Vehicles",
"RequiredPermissionName": "App.Hr.VehicleDocument", "RequiredPermissionName": "App.Hr.VehicleDocument",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Vehicles", "Id": "e07191b4-f6b0-42f2-a19a-fd22a41abf39",
"Code": "App.Hr.Vehicle", "Code": "App.Hr.Vehicle",
"DisplayName": "App.Hr.Vehicle", "DisplayName": "App.Hr.Vehicle",
"Order": 2, "Order": 2,
"Url": "/admin/list/App.Hr.Vehicle", "Url": "/admin/list/App.Hr.Vehicle",
"Icon": "FcAutomotive", "Icon": "FcAutomotive",
"ParentCode": "App.Hr.Vehicles",
"RequiredPermissionName": "App.Hr.Vehicle", "RequiredPermissionName": "App.Hr.Vehicle",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Vehicles", "Id": "6830fe01-a678-45c9-96e2-a6daefc77ff6",
"Code": "App.Hr.VehicleDestination", "Code": "App.Hr.VehicleDestination",
"DisplayName": "App.Hr.VehicleDestination", "DisplayName": "App.Hr.VehicleDestination",
"Order": 3, "Order": 3,
"Url": "/admin/list/App.Hr.VehicleDestination", "Url": "/admin/list/App.Hr.VehicleDestination",
"Icon": "FcGlobe", "Icon": "FcGlobe",
"ParentCode": "App.Hr.Vehicles",
"RequiredPermissionName": "App.Hr.VehicleDestination", "RequiredPermissionName": "App.Hr.VehicleDestination",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Vehicles", "Id": "e61fd31e-265b-410e-9e71-4862aea4bdff",
"Code": "App.Hr.Driver", "Code": "App.Hr.Driver",
"DisplayName": "App.Hr.Driver", "DisplayName": "App.Hr.Driver",
"Order": 4, "Order": 4,
"Url": "/admin/list/App.Hr.Driver", "Url": "/admin/list/App.Hr.Driver",
"Icon": "FcBusinessman", "Icon": "FcBusinessman",
"ParentCode": "App.Hr.Vehicles",
"RequiredPermissionName": "App.Hr.Driver", "RequiredPermissionName": "App.Hr.Driver",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Vehicles", "Id": "d2672ea5-55a2-43fc-8832-901cfd3bcf4d",
"Code": "App.Hr.VehicleExpenseDefinition", "Code": "App.Hr.VehicleExpenseDefinition",
"DisplayName": "App.Hr.VehicleExpenseDefinition", "DisplayName": "App.Hr.VehicleExpenseDefinition",
"Order": 5, "Order": 5,
"Url": "/admin/list/App.Hr.VehicleExpenseDefinition", "Url": "/admin/list/App.Hr.VehicleExpenseDefinition",
"Icon": "FcList", "Icon": "FcList",
"ParentCode": "App.Hr.Vehicles",
"RequiredPermissionName": "App.Hr.VehicleExpenseDefinition", "RequiredPermissionName": "App.Hr.VehicleExpenseDefinition",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Vehicles", "Id": "be5ca380-4054-4cc5-80f6-67bee385a145",
"Code": "App.Hr.VehicleExpense", "Code": "App.Hr.VehicleExpense",
"DisplayName": "App.Hr.VehicleExpense", "DisplayName": "App.Hr.VehicleExpense",
"Order": 6, "Order": 6,
"Url": "/admin/list/App.Hr.VehicleExpense", "Url": "/admin/list/App.Hr.VehicleExpense",
"Icon": "FcMoneyTransfer", "Icon": "FcMoneyTransfer",
"ParentCode": "App.Hr.Vehicles",
"RequiredPermissionName": "App.Hr.VehicleExpense", "RequiredPermissionName": "App.Hr.VehicleExpense",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
}, },
{ {
"ParentCode": "App.Hr.Vehicles", "Id": "65918815-4fd4-49b7-aed1-477e0acc4e16",
"Code": "App.Hr.VehicleMovement", "Code": "App.Hr.VehicleMovement",
"DisplayName": "App.Hr.VehicleMovement", "DisplayName": "App.Hr.VehicleMovement",
"Order": 7, "Order": 7,
"Url": "/admin/list/App.Hr.VehicleMovement", "Url": "/admin/list/App.Hr.VehicleMovement",
"Icon": "FcInspection", "Icon": "FcInspection",
"ParentCode": "App.Hr.Vehicles",
"RequiredPermissionName": "App.Hr.VehicleMovement", "RequiredPermissionName": "App.Hr.VehicleMovement",
"CssClass": null,
"Target": null,
"IsDisabled": false, "IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr"
},
{
"Id": "0f1b3f0c-f9d8-4f09-9506-59fb19272176",
"Code": "App.Hr.Shift",
"DisplayName": "App.Hr.Shift",
"Order": 2,
"Url": "/admin/list/App.Hr.Shift",
"Icon": "FcClock",
"ParentCode": "App.Hr",
"RequiredPermissionName": "App.Hr.Shift",
"CssClass": null,
"Target": null,
"IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr"
},
{
"Id": "5786d92e-0501-4775-bf1b-697a41a90f40",
"Code": "App.Hr.EventLog",
"DisplayName": "App.Hr.EventLog",
"Order": 8,
"Url": "/admin/list/App.Hr.EventLog",
"Icon": "FcViewDetails",
"ParentCode": "App.Hr",
"RequiredPermissionName": "App.Hr.EventLog",
"CssClass": null,
"Target": null,
"IsDisabled": false,
"ElementId": null,
"ModuleId": "Hr" "ModuleId": "Hr"
} }
] ]

View file

@ -0,0 +1,28 @@
IF OBJECT_ID(N'[dbo].[Hr_T_EventLog]', 'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Hr_T_EventLog]
(
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
[TenantId] uniqueidentifier NULL,
[BranchId] uniqueidentifier NULL,
[LogSource] nvarchar(32) NOT NULL,
[UserId] uniqueidentifier NOT NULL,
[EventDate] date NOT NULL,
[EventTime] nvarchar(5) NOT NULL,
[Importance] int NOT NULL DEFAULT 1,
[ShiftId] uniqueidentifier NULL,
[Description] nvarchar(MAX) NULL,
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
[CreatorId] uniqueidentifier NULL,
[LastModificationTime] datetime2 NULL,
[LastModifierId] uniqueidentifier NULL,
[IsDeleted] bit NOT NULL DEFAULT 0,
[DeletionTime] datetime2 NULL,
[DeleterId] uniqueidentifier NULL,
CONSTRAINT [PK_Hr_T_EventLog] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO

View file

@ -0,0 +1,24 @@
IF OBJECT_ID(N'[dbo].[Hr_T_Shift]', 'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Hr_T_Shift]
(
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
[TenantId] uniqueidentifier NULL,
[Name] nvarchar(64) NOT NULL,
[StartTime] nvarchar(5) NULL,
[EndTime] nvarchar(5) NULL,
[IsActive] bit NOT NULL DEFAULT 1,
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
[CreatorId] uniqueidentifier NULL,
[LastModificationTime] datetime2 NULL,
[LastModifierId] uniqueidentifier NULL,
[IsDeleted] bit NOT NULL DEFAULT 0,
[DeletionTime] datetime2 NULL,
[DeleterId] uniqueidentifier NULL,
CONSTRAINT [PK_Hr_T_Shift] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -211,6 +211,15 @@ const flattenWizardTree = (
: [row, ...flattenWizardTree(node.children, collapsed, depth + 1, `${key}/`, childGuides)] : [row, ...flattenWizardTree(node.children, collapsed, depth + 1, `${key}/`, childGuides)]
}) })
/** Alt ekranı olan her düğümün aç/kapa anahtarı; anahtar biçimi `flattenWizardTree` ile aynıdır. */
const collectWizardTreeKeys = (nodes: WizardTreeNode[], prefix = ''): string[] =>
nodes.flatMap((node) => {
const key = `${prefix}${node.file.fileName}`
return node.children.length > 0
? [key, ...collectWizardTreeKeys(node.children, `${key}/`)]
: []
})
/** Bir ağaç seviyesinin genişliği: aç/kapa düğmesi (14px) + satırdaki boşluk (8px). */ /** Bir ağaç seviyesinin genişliği: aç/kapa düğmesi (14px) + satırdaki boşluk (8px). */
const TREE_INDENT = 22 const TREE_INDENT = 22
/** Dikey çizginin seviye içindeki yeri; aç/kapa düğmesinin ortasına denk gelir. */ /** Dikey çizginin seviye içindeki yeri; aç/kapa düğmesinin ortasına denk gelir. */
@ -304,6 +313,11 @@ const WizardFileManager = () => {
return [...groups.values()].sort((a, b) => Number(!a.file) - Number(!b.file)) return [...groups.values()].sort((a, b) => Number(!a.file) - Number(!b.file))
}, [tree]) }, [tree])
// Talep grupları yalnızca liste görünümünde vardır; kart görünümünde fazladan anahtar etkisizdir.
const collapseAll = () =>
setCollapsed(new Set([...devRequestGroups.map((g) => g.key), ...collectWizardTreeKeys(tree)]))
const expandAll = () => setCollapsed(new Set())
const loadFiles = useCallback(async () => { const loadFiles = useCallback(async () => {
setLoading(true) setLoading(true)
try { try {
@ -881,6 +895,25 @@ const WizardFileManager = () => {
> >
<FaSync /> <FaSync />
</Button> </Button>
{/* Arama sırasında gruplar zaten açık gösterilir; butonlar o an etkisizdir. */}
<Button
size="sm"
variant="default"
type="button"
icon={<FaPlusSquare />}
title={translate('::App.Platform.ExpandAll')}
disabled={!!search.trim()}
onClick={expandAll}
/>
<Button
size="sm"
variant="default"
type="button"
icon={<FaMinusSquare />}
title={translate('::App.Platform.CollapseAll')}
disabled={!!search.trim()}
onClick={collapseAll}
/>
{pendingCount > 0 && ( {pendingCount > 0 && (
<span <span
className="inline-flex items-center gap-1 rounded-full bg-amber-100 px-2 py-1 text-xs font-medium text-amber-700 dark:bg-amber-900/30 dark:text-amber-300" className="inline-flex items-center gap-1 rounded-full bg-amber-100 px-2 py-1 text-xs font-medium text-amber-700 dark:bg-amber-900/30 dark:text-amber-300"