Bazı hatalar giderildi
This commit is contained in:
parent
c62e2c8586
commit
6081131f95
9 changed files with 157 additions and 12 deletions
12
.github/instructions/lowcode.instructions.md
vendored
12
.github/instructions/lowcode.instructions.md
vendored
|
|
@ -707,6 +707,11 @@ Kısa ve karar odaklı yaz; talebi tekrar anlatma.
|
||||||
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
|
||||||
seviyenin yetkisi için Var / Yeni yazar (var olan `Abp.Identity.Permissions.json`'dan okunur).
|
seviyenin yetkisi için Var / Yeni yazar (var olan `Abp.Identity.Permissions.json`'dan okunur).
|
||||||
Yetkinin yerini menüden ayrı seçen bir wizard alanı yoktur; yetki dalı menü yoluyla birlikte değişir.
|
Yetkinin yerini menüden ayrı seçen bir wizard alanı yoktur; yetki dalı menü yoluyla birlikte değişir.
|
||||||
|
**Menüsüz alt formun yetkisi listenin yetkisinin altındadır**: alt formun okuma yetkisinin
|
||||||
|
`ParentName` değeri onu `SubForms` içinde taşıyan listenin yetki kodudur (grubun kökü değil);
|
||||||
|
analiz satırı `Yetki: {İzin grubu} › {Ara yetki} › {Liste} › {AltForm}` olur. Deploy bunu kendisi
|
||||||
|
kurar — alt form önce deploy edilir, liste deploy edildiğinde alt formun yetkisi listenin
|
||||||
|
altına, listenin alt yetkilerinin (Create/Update/…) ardına taşınır; ayrıca bir alan yazılmaz.
|
||||||
Aynı üst menü altındaki ekranlar **bağımlılık sırasıyla** yazılır: başka bir ekranın lookup
|
Aynı üst menü altındaki ekranlar **bağımlılık sırasıyla** yazılır: başka bir ekranın lookup
|
||||||
kaynağı olan (tanım) ekran, onu kullanan ekranın üstündedir. Menüdeki sıra deploy sırasından
|
kaynağı olan (tanım) ekran, onu kullanan ekranın üstündedir. Menüdeki sıra deploy sırasından
|
||||||
gelir; madde 9'daki üretim planı da aynı sırayla yazılır.
|
gelir; madde 9'daki üretim planı da aynı sırayla yazılır.
|
||||||
|
|
@ -1115,6 +1120,10 @@ kaynağı odur. Grup yapısı yalnızca düzenleme formunun yerleşimini belirle
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Grup başlığı yalnızca düzenleme formunda **birden fazla grup** varsa yazılır; tek gruplu formda
|
||||||
|
başlık popup başlığını tekrarlar ve boş bırakılır. MCP `deploy_wizard` bunu kendisi uygular:
|
||||||
|
düzenleme formuna giren tek grup varsa `Caption` boşaltılır (`McpDevelopAppService.DeployWizardAsync`).
|
||||||
|
|
||||||
Seed dosyasında `Groups` **kırpılmış** hâlde durur: grup başlığı/kolon sayısı ve alanların
|
Seed dosyasında `Groups` **kırpılmış** hâlde durur: grup başlığı/kolon sayısı ve alanların
|
||||||
editör bilgileri `ListForm.EditingFormDto` ve `Fields` içinde olduğu için tekrarlanmaz; dosyada
|
editör bilgileri `ListForm.EditingFormDto` ve `Fields` içinde olduğu için tekrarlanmaz; dosyada
|
||||||
her öğe yalnızca `FieldName`, `CaptionName` ve `En`/`Tr` taşır — çünkü
|
her öğe yalnızca `FieldName`, `CaptionName` ve `En`/`Tr` taşır — çünkü
|
||||||
|
|
@ -2159,7 +2168,8 @@ ardından `ListFormSeedDataApplier` menü/yetki/dil satırlarını kurar (§4.0)
|
||||||
1. Konfigürasyon doğrulama
|
1. Konfigürasyon doğrulama
|
||||||
2. Menü kaydı (`CreateMenu: false` ise atlanır)
|
2. Menü kaydı (`CreateMenu: false` ise atlanır)
|
||||||
3. Dil metinleri
|
3. Dil metinleri
|
||||||
4. İzin grubu + yetkiler (okuma yetkisi menü dalındaki ara yetkinin altına, §0.12 Menü yeri)
|
4. İzin grubu + yetkiler (okuma yetkisi menü dalındaki ara yetkinin altına; menüsüz alt formda
|
||||||
|
listenin yetkisinin altına, §0.12 Menü yeri)
|
||||||
5. List yolunda: veri kaynağı → ListForm → alan grupları · Custom yolunda: bileşen bağlama
|
5. List yolunda: veri kaynağı → ListForm → alan grupları · Custom yolunda: bileşen bağlama
|
||||||
6. Deploy + tamamlandı
|
6. Deploy + tamamlandı
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -951,8 +951,13 @@ 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'da
|
görünen adıyla wizard'a ait üretilir; başka bir gruptaki aynı adlı yetki atlanır. Menüsüz wizard'ın
|
||||||
(`CreateMenu: false`) okuma yetkisi grubun köküne yazılır.
|
(`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ı
|
||||||
|
listenin alt yetkilerinin (Create/Update/…) ardındandır. Alt form listeden önce deploy edildiği için
|
||||||
|
yetkisi önce grubun köküne yazılır; liste deploy edildiğinde alt formun satırı listenin altına
|
||||||
|
taşınır (satır alt formun wizard'ına ait kalır, başka bir listeye bağlanmış alt form taşınmaz).
|
||||||
|
Hiçbir listenin alt formu olmayan menüsüz wizard'ın yetkisi grubun kökünde kalır.
|
||||||
Wizard deploy'u yeni grubu ve yeni yetkileri (seed satırı olarak) veritabanı ile seed
|
Wizard deploy'u yeni grubu ve yeni yetkileri (seed satırı olarak) veritabanı ile seed
|
||||||
dosyasındaki kardeşlerin en büyük sırasının bir fazlasıyla, alt yetkileri `WizardSeedRowKeys.ChildPermissions` dizilimiyle
|
dosyasındaki kardeşlerin en büyük sırasının bir fazlasıyla, alt yetkileri `WizardSeedRowKeys.ChildPermissions` dizilimiyle
|
||||||
(List: Create/Update/Delete/Export/Import/Note, Custom: Create/Update/Delete) 1'den yazar
|
(List: Create/Update/Delete/Export/Import/Note, Custom: Create/Update/Delete) 1'den yazar
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,14 @@ public class McpDevelopAppService(
|
||||||
? 0
|
? 0
|
||||||
: (await wizardAppService.GetFile(wizard.EditFileName)).Wizard?.MenuOrder ?? 0;
|
: (await wizardAppService.GetFile(wizard.EditFileName)).Wizard?.MenuOrder ?? 0;
|
||||||
|
|
||||||
|
// Tek gruplu duzenleme formunda grup basligi popup basligini tekrarlar; baslik yalnizca
|
||||||
|
// birden fazla grubu birbirinden ayirmak icin yazilir.
|
||||||
|
var editGroups = wizard.Groups
|
||||||
|
.Where(group => group.Items.Any(item => item.IncludeInEditingForm && item.FieldName != wizard.KeyFieldName))
|
||||||
|
.ToList();
|
||||||
|
if (editGroups.Count == 1)
|
||||||
|
editGroups[0].Caption = string.Empty;
|
||||||
|
|
||||||
// Satirlar deploy'dan once dogrulanir; gecersiz girdi yarim bir deploy birakmaz.
|
// Satirlar deploy'dan once dogrulanir; gecersiz girdi yarim bir deploy birakmaz.
|
||||||
var seedRows = ParseSeedRows(input.SeedRows, wizard);
|
var seedRows = ParseSeedRows(input.SeedRows, wizard);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,17 @@ public class McpTableCreator(
|
||||||
/// Varsayilan deger olarak kabul edilenler: sayi, metin sabiti ve tasarimcinin kendi
|
/// Varsayilan deger olarak kabul edilenler: sayi, metin sabiti ve tasarimcinin kendi
|
||||||
/// sablonlarinda kullandigi fonksiyonlar. Baska bir ifade script'e hic girmez.
|
/// sablonlarinda kullandigi fonksiyonlar. Baska bir ifade script'e hic girmez.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <summary>
|
||||||
|
/// Istemcinin SQL bicimiyle yazdigi tip: <c>nvarchar(50)</c>, <c>nvarchar (MAX)</c>,
|
||||||
|
/// <c>decimal(18, 4)</c>. Boyut tipten ayrilir; tip adi yine beyaz listeden gecer.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Regex SizedTypeRegex = new(
|
||||||
|
@"^(?<name>[A-Za-z0-9]+)\s*\(\s*(?<size>[^)]*?)\s*\)$",
|
||||||
|
RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
||||||
|
|
||||||
|
/// <summary>Tasarimci decimal'i her zaman bu kesinlikle yazar (<c>ToColumnLine</c>).</summary>
|
||||||
|
private const string DecimalSize = "18,4";
|
||||||
|
|
||||||
private static readonly Regex SafeDefaultRegex = new(
|
private static readonly Regex SafeDefaultRegex = new(
|
||||||
@"^(?:-?\d{1,18}(?:\.\d{1,18})?|N?'(?:[^']|'')*'|NEWID\(\)|GETDATE\(\)|GETUTCDATE\(\)|SYSUTCDATETIME\(\))$",
|
@"^(?:-?\d{1,18}(?:\.\d{1,18})?|N?'(?:[^']|'')*'|NEWID\(\)|GETDATE\(\)|GETUTCDATE\(\)|SYSUTCDATETIME\(\))$",
|
||||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||||
|
|
@ -150,15 +161,12 @@ public class McpTableCreator(
|
||||||
var name = (column.Name ?? string.Empty).Trim();
|
var name = (column.Name ?? string.Empty).Trim();
|
||||||
EnsureSafeIdentifier(name);
|
EnsureSafeIdentifier(name);
|
||||||
|
|
||||||
var type = SupportedTypes.FirstOrDefault(candidate =>
|
var (type, sizedLength) = ResolveType(column.Type);
|
||||||
string.Equals(candidate, column.Type?.Trim(), StringComparison.OrdinalIgnoreCase))
|
|
||||||
?? throw new UserFriendlyException(
|
|
||||||
localizer[McpErrorCodes.UnsupportedColumnType, column.Type ?? string.Empty, string.Join(", ", SupportedTypes)]);
|
|
||||||
|
|
||||||
int? maxLength = null;
|
int? maxLength = null;
|
||||||
if (type == "nvarchar")
|
if (type == "nvarchar")
|
||||||
{
|
{
|
||||||
maxLength = column.MaxLength ?? DefaultTextLength;
|
maxLength = column.MaxLength ?? sizedLength ?? DefaultTextLength;
|
||||||
if (maxLength is < 1 or > MaxTextLength)
|
if (maxLength is < 1 or > MaxTextLength)
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException(localizer[McpErrorCodes.InvalidColumnLength, name, MaxTextLength]);
|
throw new UserFriendlyException(localizer[McpErrorCodes.InvalidColumnLength, name, MaxTextLength]);
|
||||||
|
|
@ -174,6 +182,49 @@ public class McpTableCreator(
|
||||||
return new McpTableColumn(name, type, maxLength, column.IsNullable, defaultValue);
|
return new McpTableColumn(name, type, maxLength, column.IsNullable, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tipi beyaz listedeki adina indirger. <c>nvarchar(N)</c> uzunlugu dondurur,
|
||||||
|
/// <c>nvarchar(MAX)</c> kendi tipidir; decimal yalnizca tasarimcinin kesinligiyle kabul edilir —
|
||||||
|
/// baska bir kesinligi 18,4'e cevirmek sessizce veri kaybi riski tasirdi.
|
||||||
|
/// </summary>
|
||||||
|
private (string Type, int? MaxLength) ResolveType(string? rawType)
|
||||||
|
{
|
||||||
|
var trimmed = rawType?.Trim() ?? string.Empty;
|
||||||
|
var name = trimmed;
|
||||||
|
string? size = null;
|
||||||
|
|
||||||
|
var sized = SizedTypeRegex.Match(trimmed);
|
||||||
|
if (sized.Success)
|
||||||
|
{
|
||||||
|
name = sized.Groups["name"].Value;
|
||||||
|
size = Regex.Replace(sized.Groups["size"].Value, @"\s+", string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
int? maxLength = null;
|
||||||
|
if (size is not null)
|
||||||
|
{
|
||||||
|
if (name.Equals("nvarchar", StringComparison.OrdinalIgnoreCase) && size.Equals("max", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
name = "nvarchar(MAX)";
|
||||||
|
}
|
||||||
|
else if (name.Equals("nvarchar", StringComparison.OrdinalIgnoreCase) && int.TryParse(size, out var length))
|
||||||
|
{
|
||||||
|
maxLength = length;
|
||||||
|
}
|
||||||
|
else if (!(name.Equals("decimal", StringComparison.OrdinalIgnoreCase) && size == DecimalSize))
|
||||||
|
{
|
||||||
|
name = trimmed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = SupportedTypes.FirstOrDefault(candidate =>
|
||||||
|
string.Equals(candidate, name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
?? throw new UserFriendlyException(
|
||||||
|
localizer[McpErrorCodes.UnsupportedColumnType, trimmed, string.Join(", ", SupportedTypes)]);
|
||||||
|
|
||||||
|
return (type, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
private static string BuildScript(string tableName, List<McpTableColumn> columns)
|
private static string BuildScript(string tableName, List<McpTableColumn> columns)
|
||||||
{
|
{
|
||||||
var fullTableName = $"[{SchemaName}].[{tableName}]";
|
var fullTableName = $"[{SchemaName}].[{tableName}]";
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService)
|
||||||
public async Task<McpCreateTableResultDto> CreateTableAsync(
|
public async Task<McpCreateTableResultDto> CreateTableAsync(
|
||||||
[Description("Tablo adi; harf/rakam/alt cizgi. Adlandirma icin get_dev_guide'daki tablo onek kuralina uy (ornegin Adm_T_...).")]
|
[Description("Tablo adi; harf/rakam/alt cizgi. Adlandirma icin get_dev_guide'daki tablo onek kuralina uy (ornegin Adm_T_...).")]
|
||||||
string tableName,
|
string tableName,
|
||||||
[Description("Is kolonlari. type: nvarchar, nvarchar(MAX), int, bigint, decimal (18,4), float, bit, datetime, datetime2, date, uniqueidentifier, money. maxLength yalnizca nvarchar icin (varsayilan 100). defaultValue: sayi, 'metin' ya da NEWID()/GETDATE()/GETUTCDATE()/SYSUTCDATETIME().")]
|
[Description("Is kolonlari. type: nvarchar, nvarchar(MAX), int, bigint, decimal (her zaman 18,4 yazilir; boyut verme), float, bit, datetime, datetime2, date, uniqueidentifier, money. maxLength yalnizca nvarchar icin (varsayilan 100). defaultValue: sayi, 'metin' ya da NEWID()/GETDATE()/GETUTCDATE()/SYSUTCDATETIME().")]
|
||||||
List<McpTableColumnDto> columns,
|
List<McpTableColumnDto> columns,
|
||||||
[Description("Tam audit kolonlari eklensin mi. Kullanici acikca istemedikce true birak.")]
|
[Description("Tam audit kolonlari eklensin mi. Kullanici acikca istemedikce true birak.")]
|
||||||
bool fullAudited = true,
|
bool fullAudited = true,
|
||||||
|
|
|
||||||
|
|
@ -409,7 +409,8 @@ public class ListFormWizardAppService(
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Okuma yetkisi ve alt yetkileri. Alt yetkilerin sirasi kardesler arasindadir ve listedeki
|
/// Okuma yetkisi ve alt yetkileri. Alt yetkilerin sirasi kardesler arasindadir ve listedeki
|
||||||
/// dizilimi izler (Create = 1, ...); okuma yetkisi grubun kok yetkilerinin sonuna eklenir.
|
/// dizilimi izler (Create = 1, ...), menusuz alt formlarin okuma yetkileri bunlarin ardindan
|
||||||
|
/// gelir; okuma yetkisi menu dalinin, menusuz alt formda ise listenin yetkisinin altina eklenir.
|
||||||
/// Yetkiler menuyle ayni modul filtresine tabidir; modul bos kalirsa rol ekraninda modul
|
/// Yetkiler menuyle ayni modul filtresine tabidir; modul bos kalirsa rol ekraninda modul
|
||||||
/// secimiyle filtrelenen listede gorunmez.
|
/// secimiyle filtrelenen listede gorunmez.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -496,6 +497,24 @@ public class ListFormWizardAppService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Menusuz alt formun menude dali yoktur; yetkisi onu alt form olarak tasiyan listenin
|
||||||
|
// yetkisinin altindadir. Liste henuz deploy edilmediyse kokte kalir, liste deploy
|
||||||
|
// edildiginde asagida tasinir.
|
||||||
|
var wizards = (await ReadSeedFilesAsync()).Select(f => f.Seed?.Wizard).OfType<ListFormWizardDto>().ToList();
|
||||||
|
bool InGroup(string name) =>
|
||||||
|
rows.Find(WizardSeedRowStore.PermissionFile, "Name", name) is { } row
|
||||||
|
? Same(WizardSeedRowStore.Text(row, "GroupName"), groupName)
|
||||||
|
: dbPermissions.Any(p => Same(p.Name, name));
|
||||||
|
|
||||||
|
if (!input.CreateMenu)
|
||||||
|
{
|
||||||
|
var listFormCode = input.ResolveListFormCode();
|
||||||
|
parentName = wizards
|
||||||
|
.Where(w => !Same(w.ResolveMenuCode(), code) && (w.SubForms ?? []).Any(s => Same(s.Code, listFormCode)))
|
||||||
|
.Select(w => w.ResolveMenuCode())
|
||||||
|
.FirstOrDefault(InGroup);
|
||||||
|
}
|
||||||
|
|
||||||
if (IsOwnable(code))
|
if (IsOwnable(code))
|
||||||
Write(code, parentName, code, NextOrder(code, parentName));
|
Write(code, parentName, code, NextOrder(code, parentName));
|
||||||
|
|
||||||
|
|
@ -508,6 +527,31 @@ public class ListFormWizardAppService(
|
||||||
if (IsOwnable(name))
|
if (IsOwnable(name))
|
||||||
Write(name, code, langKey, childOrder);
|
Write(name, code, langKey, childOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Alt formlar listeden once deploy edilir (bagimlilik sirasi), yetkileri o an kokte yazilir.
|
||||||
|
// Satir alt formun wizard'ina ait kalir; liste yalnizca yerini degistirir. Baska bir listenin
|
||||||
|
// altina alinmis alt form orada birakilir.
|
||||||
|
foreach (var subForm in input.SubForms ?? [])
|
||||||
|
{
|
||||||
|
var child = wizards.FirstOrDefault(w => !w.CreateMenu && Same(w.ResolveListFormCode(), subForm.Code));
|
||||||
|
var childName = child?.ResolveMenuCode();
|
||||||
|
var row = rows.Find(WizardSeedRowStore.PermissionFile, "Name", childName);
|
||||||
|
|
||||||
|
if (child == null || row == null || Same(childName, code) || !InGroup(childName!))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var currentParent = WizardSeedRowStore.Text(row, "ParentName");
|
||||||
|
if (!string.IsNullOrWhiteSpace(currentParent) && !Same(currentParent, code))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
childOrder++;
|
||||||
|
rows.Upsert(WizardSeedRowStore.PermissionFile, new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
["Name"] = childName!,
|
||||||
|
["ParentName"] = code,
|
||||||
|
[PlatformConsts.Permissions.Order] = childOrder,
|
||||||
|
}, "Name");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,8 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
|
||||||
değer base64 saklanır, sınırlı boy ve `dxImageViewer` kullanılmaz (deploy ikisini de reddeder).
|
değer base64 saklanır, sınırlı boy ve `dxImageViewer` kullanılmaz (deploy ikisini de reddeder).
|
||||||
2. **Yeni ekran** → Wizard yolu. `Definitions` altına otomatik yerleştirme yok; modüle ait yeni
|
2. **Yeni ekran** → Wizard yolu. `Definitions` altına otomatik yerleştirme yok; modüle ait yeni
|
||||||
bir kök menü oluştur, `Order = max(Order) + 1`. Yetki ağacı menü ağacını izler: ekranın okuma
|
bir kök menü oluştur, `Order = max(Order) + 1`. Yetki ağacı menü ağacını izler: ekranın okuma
|
||||||
yetkisi menüdeki dalın ara yetkisinin altına yazılır (`lowcode.instructions.md` §0.12 Menü yeri).
|
yetkisi menüdeki dalın ara yetkisinin altına yazılır; menüsüz alt formun yetkisi ise listenin
|
||||||
|
yetkisine bağlanır (`ParentName` = listenin yetki kodu) (`lowcode.instructions.md` §0.12 Menü yeri).
|
||||||
3. **Yeni ekran/menü** → yetki sözleşmesi olmadan önerilmez. Menü ve route aynı ekran
|
3. **Yeni ekran/menü** → yetki sözleşmesi olmadan önerilmez. Menü ve route aynı ekran
|
||||||
sözleşmesini göstermeli.
|
sözleşmesini göstermeli.
|
||||||
4. **Kullanıcıya görünen her metin** → dil anahtarı üzerinden, EN + TR birlikte. Koda gömülü
|
4. **Kullanıcıya görünen her metin** → dil anahtarı üzerinden, EN + TR birlikte. Koda gömülü
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1964,7 +1964,7 @@ const TodoBoardContent = ({
|
||||||
{canDelete && (
|
{canDelete && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="hidden rounded p-1 text-gray-400 hover:bg-red-50 hover:text-red-500 group-hover/card:block dark:hover:bg-red-950"
|
className="invisible rounded p-1 text-gray-400 hover:bg-red-50 hover:text-red-500 focus-visible:visible group-hover/card:visible dark:hover:bg-red-950"
|
||||||
title={translate('::App.ListFormTodoBoard.DeleteTodo')}
|
title={translate('::App.ListFormTodoBoard.DeleteTodo')}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue