Wizard File Manager liste düzenlendi

This commit is contained in:
Sedat Öztürk 2026-05-03 15:24:46 +03:00
parent 8dda4498ef
commit 10bf95da66
6 changed files with 104 additions and 100 deletions

View file

@ -52,6 +52,8 @@ public class WizardFileInfoDto
public string FileName { get; set; }
public string WizardName { get; set; }
public string ListFormCode { get; set; }
public string DefaultLayout { get; set; }
public string MenuIcon { get; set; }
public string CreatedAt { get; set; }
public bool HasInsertedRecords { get; set; }
}

View file

@ -407,6 +407,8 @@ public class ListFormWizardAppService(
{
FileName = fileName,
WizardName = seed?.Wizard?.WizardName ?? fileName,
DefaultLayout = seed?.Wizard?.DefaultLayout ?? string.Empty,
MenuIcon = seed?.Wizard?.MenuIcon ?? string.Empty,
ListFormCode = seed?.Wizard?.ListFormCode ?? string.Empty,
CreatedAt = fileName.Length >= 12 ? fileName[..12] : fileName,
HasInsertedRecords = seed?.InsertedRecords != null &&

View file

@ -82,6 +82,8 @@ export interface WizardFileInfoDto {
fileName: string
wizardName: string
listFormCode: string
defaultLayout: string
menuIcon: string
createdAt: string
hasInsertedRecords: boolean
}

View file

@ -1,7 +1,7 @@
import { useState, useEffect, useCallback, useMemo } from 'react'
import { useNavigate } from 'react-router-dom'
import classNames from 'classnames'
import { Button, Input, Notification, toast } from '@/components/ui'
import { Badge, Button, Input, Notification, toast } from '@/components/ui'
import Container from '@/components/shared/Container'
import ConfirmDialog from '@/components/shared/ConfirmDialog'
import {
@ -12,6 +12,7 @@ import {
FaExclamationTriangle,
FaSearch,
FaEdit,
FaUser,
} from 'react-icons/fa'
import { FcAcceptDatabase } from 'react-icons/fc'
import { deleteWizardFile, getWizardFiles } from '@/services/wizard.service'
@ -21,17 +22,7 @@ import { useStoreState } from '@/store/store'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { WizardFileInfoDto } from '@/proxy/admin/wizard/models'
import { UiEvalService } from '@/services/UiEvalService'
// Timestamp formatı: "202605021730" → "2026-05-02 17:30"
const formatTimestamp = (raw: string): string => {
if (raw.length < 12) return raw
const y = raw.slice(0, 4)
const mo = raw.slice(4, 6)
const d = raw.slice(6, 8)
const h = raw.slice(8, 10)
const mi = raw.slice(10, 12)
return `${y}-${mo}-${d} ${h}:${mi}`
}
import navigationIcon from '@/proxy/menus/navigation-icon.config'
interface ConfirmState {
fileName: string
@ -50,6 +41,9 @@ const WizardFileManager = () => {
const [confirm, setConfirm] = useState<ConfirmState | null>(null)
const [search, setSearch] = useState('')
const [showDbMigrateDialog, setShowDbMigrateDialog] = useState(false)
const IconComponent = (icon: string) => {
return navigationIcon[icon] || FaDatabase // default icon
}
const filteredFiles = useMemo(() => {
const q = search.trim().toLowerCase()
@ -179,64 +173,66 @@ const WizardFileManager = () => {
)}
<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>
{filteredFiles.map((f) => {
const Icon = IconComponent(f.menuIcon)
return (
<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">
<Icon className="text-indigo-400 shrink-0 text-3xl" />
<div className="min-w-0">
<div className="font-medium text-sm text-gray-800 dark:text-gray-200 truncate">
{f.wizardName || f.fileName} <Badge content={f.defaultLayout} />
</div>
<div className="text-xs text-gray-400 flex gap-3 mt-0.5">
<span className="truncate">{f.fileName} - {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-indigo-500 hover:bg-indigo-50 dark:hover:bg-indigo-900/20"
type="button"
title={translate('::App.Platform.Edit') || 'Edit'}
onClick={() =>
navigate(ROUTES_ENUM.protected.saas.listFormManagement.wizard, {
state: { editFileName: f.fileName },
})
}
>
<FaExclamationTriangle />
</span>
)}
<Button
size="sm"
variant="plain"
className="text-indigo-500 hover:bg-indigo-50 dark:hover:bg-indigo-900/20"
type="button"
title={translate('::App.Platform.Edit') || 'Edit'}
onClick={() =>
navigate(ROUTES_ENUM.protected.saas.listFormManagement.wizard, {
state: { editFileName: f.fileName },
})
}
>
<FaEdit />
</Button>
<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>
<FaEdit />
</Button>
<Button
size="sm"
variant="plain"
className="text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20"
type="button"
title={translate('::App.Platform.Delete') || 'Delete'}
loading={deletingFile === f.fileName}
onClick={() =>
setConfirm({ fileName: f.fileName, wizardName: f.wizardName || f.fileName })
}
>
<FaTrash />
</Button>
</div>
</div>
</div>
))}
)
})}
</div>
</div>
{/* DB Migrate Confirmation Dialog */}
@ -261,34 +257,36 @@ const WizardFileManager = () => {
{/* Delete 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 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>
)}
</Container>
)
}

View file

@ -882,11 +882,11 @@ GO`,
))}
</select>
<Button
size="sm"
size="xs"
variant="default"
icon={<FcAcceptDatabase />}
onClick={() => setShowDbMigrateConfirmDialog(true)}
className="shadow-sm"
className="shadow-sm px-2 py-1"
title={translate('::App.DbMigrate.StartMessage') || 'Run DB Migration'}
>
{translate('::ListForms.ListForm.DbMigrate') || 'DB Migrate'}
@ -895,12 +895,12 @@ GO`,
<div className="flex flex-wrap items-center gap-2 sm:gap-3">
<Button
size="sm"
size="xs"
variant="default"
icon={<FaCopy />}
onClick={handleOpenCopyDialog}
disabled={!state.selectedDataSource}
className="shadow-sm"
className="shadow-sm px-2 py-1"
title={
translate('::App.Platform.CopyOrExecuteSql') ||
'Seçili nesneleri kopyala veya SQL script calistir'
@ -909,23 +909,23 @@ GO`,
{translate('::App.Platform.CopySelectedObjects') || 'Copy Selected Objects'}
</Button>
<Button
size="sm"
size="xs"
variant="default"
icon={<FaFileAlt />}
onClick={handleNewQuery}
className="shadow-sm"
className="shadow-sm px-2 py-1"
>
{translate('::App.Platform.NewQuery') || 'New Query'}
</Button>
<Button
size="sm"
size="xs"
variant="solid"
color="blue-600"
icon={<FaPlay />}
onClick={handleExecute}
loading={state.isExecuting}
disabled={!state.selectedDataSource}
className="shadow-sm"
className="shadow-sm px-2 py-1"
>
{translate('::App.Platform.Execute')}
<span className="ml-1 text-xs opacity-75">(F5)</span>

View file

@ -127,19 +127,19 @@ export const MenuManager = () => {
onClick={handleSave}
disabled={!isDesignMode || isSaving}
className={`
flex items-center gap-2 px-4 py-2 rounded-lg transition-colors
flex items-center gap-2 px-2 py-1 rounded-lg transition-colors
${isDesignMode ? 'bg-green-600 hover:bg-green-700 text-white' : 'bg-gray-300 text-gray-500 cursor-not-allowed'}
${isSaving ? 'opacity-50' : ''}
`}
>
{isSaving ? (
<>
<FaSpinner size={16} className="animate-spin" />
<FaSpinner size={10} className="animate-spin" />
Saving...
</>
) : (
<>
<FaRegSave size={16} />
<FaRegSave size={10} />
Save Changes
</>
)}