Seeder ve WizardFileManager düzeltmesi
This commit is contained in:
parent
d44555ad6a
commit
444261ba39
3 changed files with 147 additions and 108 deletions
|
|
@ -15998,6 +15998,36 @@
|
|||
"en": "Listform Wizard",
|
||||
"tr": "Listform Sihirbazı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Listforms.WizardFileLoadError",
|
||||
"en": "Failed to load wizard files.",
|
||||
"tr": "Wizard dosyaları yüklenemedi."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Listforms.WizardNoFiles",
|
||||
"en": "No wizard file saved yet.",
|
||||
"tr": "Henüz kaydedilmiş wizard dosyası yok."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Listforms.WizardFileDeleteConfirm",
|
||||
"en": "Are you sure you want to delete this wizard file? All related database records (permission, menu, language, listform) will also be deleted. This action cannot be undone.",
|
||||
"tr": "Bu wizard dosyasını silmek istediğinizden emin misiniz? ve buna ait tüm veritabanı kayıtları (izin, menü, dil, listform) silinecek. Bu işlem geri alınamaz."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Listforms.WizardFileDeleteError",
|
||||
"en": "Failed to delete wizard file.",
|
||||
"tr": "Wizard dosyası silinemedi."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Listforms.WizardFileDeleteSuccess",
|
||||
"en": "Wizard file deleted successfully.",
|
||||
"tr": "Wizard dosyası başarıyla silindi."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Listforms.WizardManager",
|
||||
|
|
|
|||
|
|
@ -70,18 +70,18 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
var wizardDataPath = Path.Combine(Directory.GetCurrentDirectory(), "Seeds", "WizardData");
|
||||
if (!Directory.Exists(wizardDataPath))
|
||||
{
|
||||
_logger.LogInformation("Seeds/WizardData dizini bulunamadı, atlanıyor.");
|
||||
_logger.LogInformation("Seeds/WizardData directory not found, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
var jsonFiles = Directory.GetFiles(wizardDataPath, "*.json").OrderBy(f => Path.GetFileName(f)).ToArray();
|
||||
if (jsonFiles.Length == 0)
|
||||
{
|
||||
_logger.LogInformation("Seeds/WizardData dizininde JSON dosyası bulunamadı, atlanıyor.");
|
||||
_logger.LogInformation("No JSON files found in Seeds/WizardData directory, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("WizardDataSeeder başladı. {Count} dosya işlenecek.", jsonFiles.Length);
|
||||
_logger.LogInformation("WizardDataSeeder started. {Count} files to be processed.", jsonFiles.Length);
|
||||
|
||||
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||
|
||||
|
|
@ -94,14 +94,14 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
|
||||
if (seedFile?.Wizard == null)
|
||||
{
|
||||
_logger.LogWarning("Geçersiz dosya atlandı: {FilePath}", filePath);
|
||||
_logger.LogWarning("Invalid file skipped: {FilePath}", filePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
var wizardName = seedFile.Wizard.WizardName?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(wizardName))
|
||||
{
|
||||
_logger.LogWarning("WizardName boş olduğu için atlandı: {FilePath}", filePath);
|
||||
_logger.LogWarning("WizardName is empty, skipped: {FilePath}", filePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -110,13 +110,13 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
// Zaten seeded mi kontrol et (ListForm var mı?)
|
||||
if (await _repoListForm.AnyAsync(a => a.ListFormCode == seedFile.Wizard.ListFormCode))
|
||||
{
|
||||
_logger.LogInformation("[{File}] '{WizardName}' zaten mevcut, atlandı.", fileName, wizardName);
|
||||
_logger.LogInformation("[{File}] '{WizardName}' already exists, skipped.", fileName, wizardName);
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.LogInformation("[{File}] '{WizardName}' uygulanıyor...", fileName, wizardName);
|
||||
_logger.LogInformation("[{File}] '{WizardName}' is being applied...", fileName, wizardName);
|
||||
await ApplyWizardSeedAsync(seedFile);
|
||||
_logger.LogInformation("[{File}] '{WizardName}' başarıyla uygulandı.", fileName, wizardName);
|
||||
_logger.LogInformation("[{File}] '{WizardName}' has been successfully applied.", fileName, wizardName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -190,23 +190,23 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
permNote = await _repoPerm.InsertAsync(new PermissionDefinitionRecord(
|
||||
Guid.NewGuid(), groupName, WizardConsts.PermNote(wizardName), permRead.Name, WizardConsts.LangKeyNote, true, MultiTenancySides.Both), autoSave: true);
|
||||
|
||||
// Permission Grants - Admin role için, sadece eksik olanları ekle
|
||||
var existingGrants = await _permissionGrantRepository.GetListAsync("R", PlatformConsts.AbpIdentity.User.AdminRoleName);
|
||||
var existingGrantNames = new HashSet<string>(existingGrants.Select(g => g.Name));
|
||||
// // Permission Grants - Admin role için, sadece eksik olanları ekle
|
||||
// var existingGrants = await _permissionGrantRepository.GetListAsync("R", PlatformConsts.AbpIdentity.User.AdminRoleName);
|
||||
// var existingGrantNames = new HashSet<string>(existingGrants.Select(g => g.Name));
|
||||
|
||||
var grantsToInsert = new[]
|
||||
{
|
||||
permRead.Name, permCreate.Name, permUpdate.Name,
|
||||
permDelete.Name, permExport.Name, permImport.Name, permNote.Name
|
||||
}
|
||||
.Where(name => !existingGrantNames.Contains(name))
|
||||
.Select(name => new PermissionGrant(Guid.NewGuid(), name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName))
|
||||
.ToList();
|
||||
// var grantsToInsert = new[]
|
||||
// {
|
||||
// permRead.Name, permCreate.Name, permUpdate.Name,
|
||||
// permDelete.Name, permExport.Name, permImport.Name, permNote.Name
|
||||
// }
|
||||
// .Where(name => !existingGrantNames.Contains(name))
|
||||
// .Select(name => new PermissionGrant(Guid.NewGuid(), name, "R", PlatformConsts.AbpIdentity.User.AdminRoleName))
|
||||
// .ToList();
|
||||
|
||||
if (grantsToInsert.Count > 0)
|
||||
{
|
||||
await _permissionGrantRepository.InsertManyAsync(grantsToInsert, autoSave: true);
|
||||
}
|
||||
// if (grantsToInsert.Count > 0)
|
||||
// {
|
||||
// await _permissionGrantRepository.InsertManyAsync(grantsToInsert, autoSave: true);
|
||||
// }
|
||||
|
||||
// Menu Parent
|
||||
var menuQueryable = await _repoMenu.GetQueryableAsync();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,14 @@ import classNames from 'classnames'
|
|||
import { Button, Input, Notification, toast } from '@/components/ui'
|
||||
import Container from '@/components/shared/Container'
|
||||
import { WizardFileInfoDto } from '@/proxy/admin/list-form/models'
|
||||
import { FaTrash, FaSync, FaDatabase, FaPlus, FaExclamationTriangle, FaSearch } from 'react-icons/fa'
|
||||
import {
|
||||
FaTrash,
|
||||
FaSync,
|
||||
FaDatabase,
|
||||
FaPlus,
|
||||
FaExclamationTriangle,
|
||||
FaSearch,
|
||||
} from 'react-icons/fa'
|
||||
import { deleteWizardFile, getWizardFiles } from '@/services/wizard.service'
|
||||
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
|
@ -56,7 +63,9 @@ const WizardFileManager = () => {
|
|||
setFiles(res.data ?? [])
|
||||
} catch {
|
||||
toast.push(
|
||||
<Notification type="danger">Wizard dosyaları yüklenemedi.</Notification>,
|
||||
<Notification type="danger">
|
||||
{translate('::App.Listforms.WizardFileLoadError') || 'Failed to load wizard files.'}
|
||||
</Notification>,
|
||||
{ placement: 'top-end' },
|
||||
)
|
||||
} finally {
|
||||
|
|
@ -76,7 +85,9 @@ const WizardFileManager = () => {
|
|||
await deleteWizardFile(confirm.fileName)
|
||||
toast.push(
|
||||
<Notification type="success" duration={3000}>
|
||||
<strong>{confirm.wizardName}</strong> silindi.
|
||||
<strong>{confirm.wizardName}</strong>{' '}
|
||||
{translate('::App.Listforms.WizardFileDeleteSuccess') ||
|
||||
'wizard file deleted successfully.'}
|
||||
</Notification>,
|
||||
{ placement: 'top-end' },
|
||||
)
|
||||
|
|
@ -84,7 +95,8 @@ const WizardFileManager = () => {
|
|||
} catch (err: any) {
|
||||
toast.push(
|
||||
<Notification type="danger">
|
||||
Silme başarısız: {err?.message ?? 'Bilinmeyen hata'}
|
||||
{translate('::App.Listforms.WizardFileDeleteError') || 'Failed to delete wizard file.'}:{' '}
|
||||
{err?.message ?? 'Unknown error'}
|
||||
</Notification>,
|
||||
{ placement: 'top-end' },
|
||||
)
|
||||
|
|
@ -134,102 +146,99 @@ const WizardFileManager = () => {
|
|||
className="flex items-center"
|
||||
>
|
||||
<FaPlus className="mr-1" />
|
||||
{translate('::ListForms.ListForm.AddNewRecord') || 'Add New Record'}
|
||||
{translate('::ListForms.ListForm.AddNewRecord') || 'Add New Record'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
{filteredFiles.length === 0 && !loading && (
|
||||
<p className="text-xs text-gray-400 text-center py-4">
|
||||
{translate('::App.Listforms.WizardNoFiles') || 'No wizard files found.'}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{filteredFiles.length === 0 && !loading && (
|
||||
<p className="text-xs text-gray-400 text-center py-4">
|
||||
Henüz kaydedilmiş wizard dosyası yok.
|
||||
</p>
|
||||
)}
|
||||
{loading && (
|
||||
<p className="text-xs text-gray-400 text-center py-4 animate-pulse">
|
||||
{translate('::App.Platform.Loading') || 'Loading...'}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{loading && (
|
||||
<p className="text-xs text-gray-400 text-center py-4 animate-pulse">Yükleniyor...</p>
|
||||
)}
|
||||
|
||||
<div className="space-y-2">
|
||||
{filteredFiles.map((f) => (
|
||||
<div
|
||||
key={f.fileName}
|
||||
className="flex items-center justify-between p-3 rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800"
|
||||
>
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<FaDatabase className="text-indigo-400 shrink-0 text-lg" />
|
||||
<div className="min-w-0">
|
||||
<div className="font-medium text-sm text-gray-800 dark:text-gray-200 truncate">
|
||||
{f.wizardName || f.fileName}
|
||||
</div>
|
||||
<div className="text-xs text-gray-400 flex gap-3 mt-0.5">
|
||||
<span>{formatTimestamp(f.createdAt)}</span>
|
||||
<span className="truncate">{f.listFormCode}</span>
|
||||
<div className="space-y-2">
|
||||
{filteredFiles.map((f) => (
|
||||
<div
|
||||
key={f.fileName}
|
||||
className="flex items-center justify-between p-3 rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800"
|
||||
>
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<FaDatabase className="text-indigo-400 shrink-0 text-lg" />
|
||||
<div className="min-w-0">
|
||||
<div className="font-medium text-sm text-gray-800 dark:text-gray-200 truncate">
|
||||
{f.wizardName || f.fileName}
|
||||
</div>
|
||||
<div className="text-xs text-gray-400 flex gap-3 mt-0.5">
|
||||
<span>{formatTimestamp(f.createdAt)}</span>
|
||||
<span className="truncate">{f.listFormCode}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 shrink-0 ml-3">
|
||||
{!f.hasInsertedRecords && (
|
||||
<span
|
||||
title="Bu dosyada izlenen kayıt bilgisi yok. Eski format olabilir."
|
||||
className="text-yellow-500 text-xs flex items-center gap-1"
|
||||
<div className="flex items-center gap-2 shrink-0 ml-3">
|
||||
{!f.hasInsertedRecords && (
|
||||
<span
|
||||
title="Bu dosyada izlenen kayıt bilgisi yok. Eski format olabilir."
|
||||
className="text-yellow-500 text-xs flex items-center gap-1"
|
||||
>
|
||||
<FaExclamationTriangle />
|
||||
</span>
|
||||
)}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="plain"
|
||||
className="text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20"
|
||||
type="button"
|
||||
loading={deletingFile === f.fileName}
|
||||
onClick={() =>
|
||||
setConfirm({ fileName: f.fileName, wizardName: f.wizardName || f.fileName })
|
||||
}
|
||||
>
|
||||
<FaExclamationTriangle />
|
||||
</span>
|
||||
)}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="plain"
|
||||
className="text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20"
|
||||
type="button"
|
||||
loading={deletingFile === f.fileName}
|
||||
onClick={() => setConfirm({ fileName: f.fileName, wizardName: f.wizardName || f.fileName })}
|
||||
>
|
||||
<FaTrash />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Confirm Dialog */}
|
||||
{confirm && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-white dark:bg-gray-900 rounded-xl shadow-xl p-6 max-w-sm w-full mx-4">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<FaExclamationTriangle className="text-red-500 text-xl shrink-0" />
|
||||
<div>
|
||||
<p className="font-semibold text-gray-800 dark:text-gray-200">Wizard Sil</p>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
<strong>{confirm.wizardName}</strong> wizard'ı ve buna ait tüm veritabanı
|
||||
kayıtları (izin, menü, dil, listform) silinecek. Bu işlem geri alınamaz.
|
||||
</p>
|
||||
<FaTrash />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="plain"
|
||||
type="button"
|
||||
onClick={() => setConfirm(null)}
|
||||
>
|
||||
İptal
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="solid"
|
||||
color="red"
|
||||
type="button"
|
||||
onClick={handleDeleteConfirm}
|
||||
>
|
||||
Evet, Sil
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Confirm Dialog */}
|
||||
{confirm && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40">
|
||||
<div className="bg-white dark:bg-gray-900 rounded-xl shadow-xl p-6 max-w-sm w-full mx-4">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<FaExclamationTriangle className="text-red-500 text-xl shrink-0" />
|
||||
<div>
|
||||
<p className="font-semibold text-gray-800 dark:text-gray-200">{translate('::App.Platform.DeleteAction')}</p>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
{translate('::App.Listforms.WizardFileDeleteConfirm')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<Button size="sm" variant="plain" type="button" onClick={() => setConfirm(null)}>
|
||||
İptal
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="solid"
|
||||
color="red"
|
||||
type="button"
|
||||
onClick={handleDeleteConfirm}
|
||||
>
|
||||
{translate('::App.Platform.Delete') || 'Yes, Delete'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue