diff --git a/api/src/Sozsoft.Platform.DbMigrator/Migrations/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Migrations/LanguagesData.json
index 5f3698fe..3d01bad9 100644
--- a/api/src/Sozsoft.Platform.DbMigrator/Migrations/LanguagesData.json
+++ b/api/src/Sozsoft.Platform.DbMigrator/Migrations/LanguagesData.json
@@ -10854,6 +10854,48 @@
"tr": "Görüntüle",
"en": "View"
},
+ {
+ "resourceName": "Platform",
+ "key": "App.Platform.CardView",
+ "tr": "Kart Görünümü",
+ "en": "Card View"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.Platform.ListView",
+ "tr": "Liste Görünümü",
+ "en": "List View"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.Platform.Name",
+ "tr": "Ad",
+ "en": "Name"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.Platform.Description",
+ "tr": "Açıklama",
+ "en": "Description"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.Platform.Actions",
+ "tr": "İşlemler",
+ "en": "Actions"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.Platform.Dependencies",
+ "tr": "Bağımlılıklar",
+ "en": "Dependencies"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.Platform.RoutePath",
+ "tr": "Rota",
+ "en": "Route Path"
+ },
{
"resourceName": "Platform",
"key": "App.Platform.Manage2",
diff --git a/ui/src/views/admin/listForm/wizard/WizardFileManager.tsx b/ui/src/views/admin/listForm/wizard/WizardFileManager.tsx
index df077ff5..211234c2 100644
--- a/ui/src/views/admin/listForm/wizard/WizardFileManager.tsx
+++ b/ui/src/views/admin/listForm/wizard/WizardFileManager.tsx
@@ -18,6 +18,8 @@ import {
FaExternalLinkAlt,
FaFileExport,
FaFileImport,
+ FaTh,
+ FaList,
} from 'react-icons/fa'
import DbMigrateButton from '@/components/shared/DbMigrateButton'
import {
@@ -28,7 +30,8 @@ import {
} from '@/services/wizard.service'
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
import { useLocalization } from '@/utils/hooks/useLocalization'
-import { useStoreState } from '@/store/store'
+import { useStoreActions, useStoreState } from '@/store/store'
+import type { ListViewLayoutType } from '../edit/types'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { WizardComponentKindEnum, WizardFileInfoDto } from '@/proxy/admin/wizard/models'
import { useNavigationIcons } from '@/proxy/menus/navigation-icon.config'
@@ -36,6 +39,9 @@ import { usePermission } from '@/utils/hooks/usePermission'
import { WIZARD_PERMISSION } from '@/constants/permission.constant'
import WizardImportDialog from './WizardImportDialog'
+/** Layout tercihi diger listelerle ayni yerde (admin.lists.states) saklanir. */
+const VIEW_STATE_CODE = 'developerkit-wizardmanager'
+
interface ConfirmState {
fileName: string
wizardName: string
@@ -57,6 +63,13 @@ const WizardFileManager = () => {
const [importFile, setImportFile] = useState(null)
const importInputRef = useRef(null)
+ const { states } = useStoreState((state) => state.admin.lists)
+ const { setStates } = useStoreActions((a) => a.admin.lists)
+ const viewMode: ListViewLayoutType =
+ states.find((s) => s.listFormCode === VIEW_STATE_CODE)?.layout === 'grid' ? 'grid' : 'card'
+ const setViewMode = (layout: ListViewLayoutType) =>
+ setStates({ listFormCode: VIEW_STATE_CODE, layout })
+
// Butonlar yalnizca gizlenir; asil kontrol ListFormWizardAppService'te yapilir.
const { checkPermission } = usePermission()
const canCreate = checkPermission(WIZARD_PERMISSION.CREATE)
@@ -152,6 +165,72 @@ const WizardFileManager = () => {
}
}
+ const renderActions = (f: WizardFileInfoDto, className: string) => (
+
+ {!f.hasInsertedRecords && (
+
+
+
+ )}
+ {canUpdate && (
+
+ )}
+ {/* Menünün açtığı adres yeni sekmede açılır; adres yoksa buton anlamsızdır. */}
+ {f.menuUrl && (
+
+ )}
+ {canExport && (
+
+ )}
+ {canDelete && (
+
+ )}
+
+ )
+
return (
{/* ── Header ─────────────────────────────────────────────── */}
@@ -227,6 +306,24 @@ const WizardFileManager = () => {
)}
+
+ }
+ variant={viewMode === 'card' ? 'solid' : 'default'}
+ title={translate('::App.Platform.CardView')}
+ onClick={() => setViewMode('card')}
+ />
+ }
+ variant={viewMode === 'grid' ? 'solid' : 'default'}
+ title={translate('::App.Platform.ListView')}
+ onClick={() => setViewMode('grid')}
+ />
+
@@ -246,138 +343,149 @@ const WizardFileManager = () => {
)}
-
- {filteredFiles.map((f) => {
- const Icon = navigationIcon[f.menuIcon] ?? FaDatabase
- const isCustom = f.componentKind === WizardComponentKindEnum.Custom
- return (
-
-
-
-
- {/* 1. satır: wizard adı */}
-
- {f.wizardName || f.fileName}
-
-
- {/* 2. satır: dosya adı ve üretilen kod */}
-
- {f.fileName}
- •
-
- {isCustom ? f.customComponentName : f.listFormCode}
-
-
-
- {/* 3. satır: yol ayrımı (Custom / List), layout ve menü adresi */}
-
-
+ {filteredFiles.map((f) => {
+ const Icon = navigationIcon[f.menuIcon] ?? FaDatabase
+ const isCustom = f.componentKind === WizardComponentKindEnum.Custom
+ return (
+
+
+
+
+ {/* 1. satır: wizard adı */}
+
- {isCustom ? : }
- {translate(
- isCustom
- ? '::App.WizardStepComponent.CustomComponent'
- : '::App.WizardStepComponent.ListComponent',
- )}
-
+ {f.wizardName || f.fileName}
+
- {/* Custom yolunda layout kavramı yoktur. */}
- {!isCustom && f.defaultLayout && (
-
- {f.defaultLayout}
-
- )}
-
- {f.menuUrl && (
-
-
- {f.menuUrl}
-
- )}
+ {/* 2. satır: dosya adı ve üretilen kod */}
+
+ {f.fileName}
+
+
+ {isCustom ? f.customComponentName : f.listFormCode}
+
-
-
- {!f.hasInsertedRecords && (
+ {/* 3. satır: yol ayrımı (Custom / List), layout ve menü adresi */}
+
-
+ {isCustom ? : }
+ {translate(
+ isCustom
+ ? '::App.WizardStepComponent.CustomComponent'
+ : '::App.WizardStepComponent.ListComponent',
+ )}
- )}
- {/* Menünün açtığı adres yeni sekmede açılır; adres yoksa buton anlamsızdır. */}
- {f.menuUrl && (
-
- )}
- {canExport && (
-
- )}
- {canUpdate && (
-
- )}
- {canDelete && (
-
+
+ {/* Custom yolunda layout kavramı yoktur. */}
+ {!isCustom && f.defaultLayout && (
+
+ {f.defaultLayout}
+
+ )}
+
+ {f.menuUrl && (
+
+
+ {f.menuUrl}
+
+ )}
+
+
+ {renderActions(
+ f,
+ 'flex items-center justify-end gap-1 pt-1 border-t border-gray-200 dark:border-gray-700',
)}
-
- )
- })}
-
+ )
+ })}
+
+ ) : (
+
+ {filteredFiles.map((f) => {
+ const Icon = navigationIcon[f.menuIcon] ?? FaDatabase
+ const isCustom = f.componentKind === WizardComponentKindEnum.Custom
+ return (
+
+
+
+
+ {/* 1. satır: wizard adı */}
+
+ {f.wizardName || f.fileName}
+
+
+ {/* 2. satır: dosya adı ve üretilen kod */}
+
+ {f.fileName}
+ •
+
+ {isCustom ? f.customComponentName : f.listFormCode}
+
+
+
+ {/* 3. satır: yol ayrımı (Custom / List), layout ve menü adresi */}
+
+
+ {isCustom ? : }
+ {translate(
+ isCustom
+ ? '::App.WizardStepComponent.CustomComponent'
+ : '::App.WizardStepComponent.ListComponent',
+ )}
+
+
+ {/* Custom yolunda layout kavramı yoktur. */}
+ {!isCustom && f.defaultLayout && (
+
+ {f.defaultLayout}
+
+ )}
+
+ {f.menuUrl && (
+
+
+ {f.menuUrl}
+
+ )}
+
+
+
+
+ {renderActions(f, 'flex items-center gap-1 shrink-0 sm:ml-3')}
+
+ )
+ })}
+
+ )}
{importFile && (
diff --git a/ui/src/views/developerKit/ComponentManager.tsx b/ui/src/views/developerKit/ComponentManager.tsx
index 12130f6f..683aecc8 100644
--- a/ui/src/views/developerKit/ComponentManager.tsx
+++ b/ui/src/views/developerKit/ComponentManager.tsx
@@ -12,6 +12,8 @@ import {
FaExternalLinkAlt,
FaCog,
FaSyncAlt,
+ FaTh,
+ FaList,
} from 'react-icons/fa'
import Widget from '@/components/common/Widget'
import { ROUTES_ENUM } from '@/routes/route.constant'
@@ -26,6 +28,12 @@ import { usePermission } from '@/utils/hooks/usePermission'
import { COMPONENT_PERMISSION } from '@/constants/permission.constant'
import Input from '@/components/ui/Input'
import Select from '@/components/ui/Select'
+import type { CustomComponent } from '@/proxy/developerKit/models'
+import { useStoreActions, useStoreState } from '@/store/store'
+import type { ListViewLayoutType } from '../admin/listForm/edit/types'
+
+/** Layout tercihi diger listelerle ayni yerde (admin.lists.states) saklanir. */
+const VIEW_STATE_CODE = 'developerkit-components'
const ComponentManager: React.FC = () => {
const {
@@ -40,6 +48,12 @@ const ComponentManager: React.FC = () => {
const [filterActive, setFilterActive] = useState<'all' | 'active' | 'inactive'>('all')
const [isRefreshing, setIsRefreshing] = useState(false)
const [editorComponentId, setEditorComponentId] = useState
(undefined)
+ const { states } = useStoreState((state) => state.admin.lists)
+ const { setStates } = useStoreActions((a) => a.admin.lists)
+ const viewMode: ListViewLayoutType =
+ states.find((s) => s.listFormCode === VIEW_STATE_CODE)?.layout === 'grid' ? 'grid' : 'card'
+ const setViewMode = (layout: ListViewLayoutType) =>
+ setStates({ listFormCode: VIEW_STATE_CODE, layout })
// Calculate statistics
const totalComponents = components?.length || 0
@@ -104,6 +118,85 @@ const ComponentManager: React.FC = () => {
}
}
+ const renderStatusToggle = (component: CustomComponent) => (
+
+ )
+
+ const renderActions = (component: CustomComponent) => (
+
+ {canUpdate && (
+
+ )}
+
+
+ {canDelete && (
+
+ )}
+
+ )
+
return (
@@ -181,6 +274,22 @@ const ComponentManager: React.FC = () => {
)}
+
+ }
+ variant={viewMode === 'card' ? 'solid' : 'default'}
+ title={translate('::App.Platform.CardView')}
+ onClick={() => setViewMode('card')}
+ />
+ }
+ variant={viewMode === 'grid' ? 'solid' : 'default'}
+ title={translate('::App.Platform.ListView')}
+ onClick={() => setViewMode('grid')}
+ />
+
{/* Components List */}
@@ -191,148 +300,158 @@ const ComponentManager: React.FC = () => {
) : filteredComponents?.length > 0 ? (
-
- {filteredComponents.map((component) => (
-
-
-
- {/* Sol taraf */}
-
-
-
- {component.name}
-
-
-
+ viewMode === 'card' ? (
+
+ {filteredComponents.map((component) => (
+
+
+
+ {/* Sol taraf */}
+
+
+
+ {component.name}
+
+
+
-
- {parseComponentDependencies(component.dependencies).join(', ') ||
- translate('::App.DeveloperKitComponent.NoDependencies')}
-
-
-
- {component.routePath}
-
-
- {component.description && (
-
- {component.description}
+
+ {parseComponentDependencies(component.dependencies).join(', ') ||
+ translate('::App.DeveloperKitComponent.NoDependencies')}
- )}
- {componentErrors[component.name] && (
- {componentErrors[component.name]}
+ {component.routePath}
- )}
-
- {/* Sağ taraf */}
- {component.lastModificationTime && (
-
-
-
- {new Date(component.lastModificationTime).toLocaleDateString() ?? ''}
-
-
- )}
-
-
- {/* Actions */}
-
-
-
+
+ {componentErrors[component.name] && (
+
+ {componentErrors[component.name]}
+
+ )}
+
+
+ {/* Sag taraf */}
+ {component.lastModificationTime && (
+
+
+
+ {new Date(component.lastModificationTime).toLocaleDateString() ?? ''}
+
+
+ )}
-
- {canUpdate && (
-
- )}
-
-
- {canDelete && (
-
- )}
+
+ {/* Actions */}
+
+ {renderStatusToggle(component)}
+ {renderActions(component)}
-
- ))}
-
+ ))}
+
+ ) : (
+
+
+
+
+ |
+ {translate('::App.Platform.Name')}
+ |
+
+ {translate('::App.Platform.Dependencies')}
+ |
+
+ {translate('::App.Platform.RoutePath')}
+ |
+
+ {translate('::App.Platform.Description')}
+ |
+
+ {translate('::App.Platform.Modified')}
+ |
+
+ {translate('::App.Platform.Status')}
+ |
+
+ {translate('::App.Platform.Actions')}
+ |
+
+
+
+ {filteredComponents.map((component) => (
+
+
+
+
+
+ {component.name}
+
+
+ {componentErrors[component.name] && (
+
+ {componentErrors[component.name]}
+
+ )}
+ |
+
+ {parseComponentDependencies(component.dependencies).join(', ') ||
+ translate('::App.DeveloperKitComponent.NoDependencies')}
+ |
+
+ {component.routePath}
+ |
+
+ {component.description}
+ |
+
+ {component.lastModificationTime
+ ? new Date(component.lastModificationTime).toLocaleDateString()
+ : ''}
+ |
+ {renderStatusToggle(component)} |
+
+ {renderActions(component)}
+ |
+
+ ))}
+
+
+
+ )
) : (
diff --git a/ui/src/views/forum/admin/CategoryManagement.tsx b/ui/src/views/forum/admin/CategoryManagement.tsx
index 128edc90..cb86eaef 100644
--- a/ui/src/views/forum/admin/CategoryManagement.tsx
+++ b/ui/src/views/forum/admin/CategoryManagement.tsx
@@ -16,7 +16,7 @@ import { useLocalization } from '@/utils/hooks/useLocalization'
import { Formik, Form, Field, FieldProps } from 'formik'
import * as Yup from 'yup'
import { FormContainer, FormItem } from '@/components/ui/Form'
-import { Input, Checkbox, Button, Select } from '@/components/ui'
+import { Input, Checkbox, Button, Select, Dialog } from '@/components/ui'
import { ConfirmDialog } from '@/components/shared'
import { CategoryIconOption, resolveCategoryIconOptions } from './categoryIcons'
@@ -69,6 +69,11 @@ export function CategoryManagement({
setShowCreateForm(true)
}
+ const handleCloseForm = () => {
+ setShowCreateForm(false)
+ setEditingCategory(null)
+ }
+
const handleToggleActive = async (category: ForumCategory) => {
try {
await onUpdateCategoryActiveState(category.id)
@@ -87,16 +92,24 @@ export function CategoryManagement({
return (
- {/* Create/Edit Form */}
- {showCreateForm && (
-
-
+ {/* Create/Edit Modal */}
+