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 FileName { get; set; }
public string WizardName { get; set; } public string WizardName { get; set; }
public string ListFormCode { get; set; } public string ListFormCode { get; set; }
public string DefaultLayout { get; set; }
public string MenuIcon { get; set; }
public string CreatedAt { get; set; } public string CreatedAt { get; set; }
public bool HasInsertedRecords { get; set; } public bool HasInsertedRecords { get; set; }
} }

View file

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

View file

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

View file

@ -1,7 +1,7 @@
import { useState, useEffect, useCallback, useMemo } from 'react' import { useState, useEffect, useCallback, useMemo } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import classNames from 'classnames' 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 Container from '@/components/shared/Container'
import ConfirmDialog from '@/components/shared/ConfirmDialog' import ConfirmDialog from '@/components/shared/ConfirmDialog'
import { import {
@ -12,6 +12,7 @@ import {
FaExclamationTriangle, FaExclamationTriangle,
FaSearch, FaSearch,
FaEdit, FaEdit,
FaUser,
} from 'react-icons/fa' } from 'react-icons/fa'
import { FcAcceptDatabase } from 'react-icons/fc' import { FcAcceptDatabase } from 'react-icons/fc'
import { deleteWizardFile, getWizardFiles } from '@/services/wizard.service' import { deleteWizardFile, getWizardFiles } from '@/services/wizard.service'
@ -21,17 +22,7 @@ import { useStoreState } from '@/store/store'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
import { WizardFileInfoDto } from '@/proxy/admin/wizard/models' import { WizardFileInfoDto } from '@/proxy/admin/wizard/models'
import { UiEvalService } from '@/services/UiEvalService' import { UiEvalService } from '@/services/UiEvalService'
import navigationIcon from '@/proxy/menus/navigation-icon.config'
// 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}`
}
interface ConfirmState { interface ConfirmState {
fileName: string fileName: string
@ -50,6 +41,9 @@ const WizardFileManager = () => {
const [confirm, setConfirm] = useState<ConfirmState | null>(null) const [confirm, setConfirm] = useState<ConfirmState | null>(null)
const [search, setSearch] = useState('') const [search, setSearch] = useState('')
const [showDbMigrateDialog, setShowDbMigrateDialog] = useState(false) const [showDbMigrateDialog, setShowDbMigrateDialog] = useState(false)
const IconComponent = (icon: string) => {
return navigationIcon[icon] || FaDatabase // default icon
}
const filteredFiles = useMemo(() => { const filteredFiles = useMemo(() => {
const q = search.trim().toLowerCase() const q = search.trim().toLowerCase()
@ -179,64 +173,66 @@ const WizardFileManager = () => {
)} )}
<div className="space-y-2"> <div className="space-y-2">
{filteredFiles.map((f) => ( {filteredFiles.map((f) => {
<div const Icon = IconComponent(f.menuIcon)
key={f.fileName} return (
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
> key={f.fileName}
<div className="flex items-center gap-3 min-w-0"> 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"
<FaDatabase className="text-indigo-400 shrink-0 text-lg" /> >
<div className="min-w-0"> <div className="flex items-center gap-3 min-w-0">
<div className="font-medium text-sm text-gray-800 dark:text-gray-200 truncate"> <Icon className="text-indigo-400 shrink-0 text-3xl" />
{f.wizardName || f.fileName} <div className="min-w-0">
</div> <div className="font-medium text-sm text-gray-800 dark:text-gray-200 truncate">
<div className="text-xs text-gray-400 flex gap-3 mt-0.5"> {f.wizardName || f.fileName} <Badge content={f.defaultLayout} />
<span>{formatTimestamp(f.createdAt)}</span> </div>
<span className="truncate">{f.listFormCode}</span> <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>
</div>
<div className="flex items-center gap-2 shrink-0 ml-3"> <div className="flex items-center gap-2 shrink-0 ml-3">
{!f.hasInsertedRecords && ( {!f.hasInsertedRecords && (
<span <span
title="Bu dosyada izlenen kayıt bilgisi yok. Eski format olabilir." title="Bu dosyada izlenen kayıt bilgisi yok. Eski format olabilir."
className="text-yellow-500 text-xs flex items-center gap-1" 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 /> <FaEdit />
</span> </Button>
)} <Button
<Button size="sm"
size="sm" variant="plain"
variant="plain" className="text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20"
className="text-indigo-500 hover:bg-indigo-50 dark:hover:bg-indigo-900/20" type="button"
type="button" title={translate('::App.Platform.Delete') || 'Delete'}
title={translate('::App.Platform.Edit') || 'Edit'} loading={deletingFile === f.fileName}
onClick={() => onClick={() =>
navigate(ROUTES_ENUM.protected.saas.listFormManagement.wizard, { setConfirm({ fileName: f.fileName, wizardName: f.wizardName || f.fileName })
state: { editFileName: f.fileName }, }
}) >
} <FaTrash />
> </Button>
<FaEdit /> </div>
</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>
</div> </div>
</div> )
))} })}
</div> </div>
</div> </div>
{/* DB Migrate Confirmation Dialog */} {/* DB Migrate Confirmation Dialog */}
@ -261,34 +257,36 @@ const WizardFileManager = () => {
{/* Delete Confirm Dialog */} {/* Delete Confirm Dialog */}
{confirm && ( {confirm && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40"> <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="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"> <div className="flex items-center gap-3 mb-4">
<FaExclamationTriangle className="text-red-500 text-xl shrink-0" /> <FaExclamationTriangle className="text-red-500 text-xl shrink-0" />
<div> <div>
<p className="font-semibold text-gray-800 dark:text-gray-200">{translate('::App.Platform.DeleteAction')}</p> <p className="font-semibold text-gray-800 dark:text-gray-200">
<p className="text-sm text-gray-500 mt-1"> {translate('::App.Platform.DeleteAction')}
{translate('::App.Listforms.WizardFileDeleteConfirm')} </p>
</p> <p className="text-sm text-gray-500 mt-1">
</div> {translate('::App.Listforms.WizardFileDeleteConfirm')}
</div> </p>
<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 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>
)}
</Container> </Container>
) )
} }

View file

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

View file

@ -127,19 +127,19 @@ export const MenuManager = () => {
onClick={handleSave} onClick={handleSave}
disabled={!isDesignMode || isSaving} disabled={!isDesignMode || isSaving}
className={` 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'} ${isDesignMode ? 'bg-green-600 hover:bg-green-700 text-white' : 'bg-gray-300 text-gray-500 cursor-not-allowed'}
${isSaving ? 'opacity-50' : ''} ${isSaving ? 'opacity-50' : ''}
`} `}
> >
{isSaving ? ( {isSaving ? (
<> <>
<FaSpinner size={16} className="animate-spin" /> <FaSpinner size={10} className="animate-spin" />
Saving... Saving...
</> </>
) : ( ) : (
<> <>
<FaRegSave size={16} /> <FaRegSave size={10} />
Save Changes Save Changes
</> </>
)} )}