From b2dfb04879a93709b04f8f0fc3bd4f5af1f7c01b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Sun, 3 May 2026 12:52:22 +0300 Subject: [PATCH] =?UTF-8?q?Wizard=20Edit=20=C3=B6zelli=C4=9Fi=20eklendi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Wizard/IListFormWizardAppService.cs | 1 + .../ListForms/ListFormWizardAppService.cs | 18 + .../Seeds/LanguagesData.json | 6 + ...nts.json => 202605031235_Departments.json} | 8 +- ui/public/version.json | 54 ++- ui/src/proxy/admin/list-form/models.ts | 66 ---- ui/src/proxy/admin/wizard/models.ts | 109 ++++++ ui/src/services/wizard.service.ts | 9 +- ui/src/views/admin/listForm/wizard/Wizard.tsx | 369 ++++++++++++------ .../listForm/wizard/WizardFileManager.tsx | 65 ++- .../admin/listForm/wizard/WizardStep1.tsx | 32 +- .../admin/listForm/wizard/WizardStep2.tsx | 2 +- .../admin/listForm/wizard/WizardStep4.tsx | 2 +- ui/src/views/developerKit/SqlQueryManager.tsx | 4 +- ui/src/views/list/List.tsx | 27 +- ui/src/views/list/useFilters.tsx | 16 +- 16 files changed, 572 insertions(+), 216 deletions(-) rename api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/{202605022245_Departments.json => 202605031235_Departments.json} (97%) create mode 100644 ui/src/proxy/admin/wizard/models.ts diff --git a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/IListFormWizardAppService.cs b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/IListFormWizardAppService.cs index 5f682f0..c5b3f75 100644 --- a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/IListFormWizardAppService.cs +++ b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/IListFormWizardAppService.cs @@ -7,6 +7,7 @@ public interface IListFormWizardAppService { Task Create(ListFormWizardDto input); Task> GetFiles(); + Task GetFile(string fileName); Task DeleteFile(string fileName); } diff --git a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs index 79d2927..a113bb7 100644 --- a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs +++ b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs @@ -398,6 +398,24 @@ public class ListFormWizardAppService( return Task.FromResult(result); } + public async Task GetFile(string fileName) + { + // Güvenlik: sadece dosya adı, path traversal yasak + if (fileName.Contains('/') || fileName.Contains('\\') || fileName.Contains("..")) + throw new Volo.Abp.AbpException("Geçersiz dosya adı."); + + var outputPath = ResolveWizardSeedOutputPath(); + var filePath = Path.Combine(outputPath, fileName); + + if (!File.Exists(filePath)) + throw new Volo.Abp.AbpException($"Dosya bulunamadı: {fileName}"); + + var json = await File.ReadAllTextAsync(filePath); + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + var seed = JsonSerializer.Deserialize(json, options); + return seed ?? throw new Volo.Abp.AbpException("Dosya okunamadı."); + } + public async Task DeleteFile(string fileName) { // Güvenlik: sadece dosya adı, path traversal yasak diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json index 256ac81..4ffd921 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json @@ -16040,6 +16040,12 @@ "en": "Menu Information", "tr": "Menü Bilgileri" }, + { + "resourceName": "Platform", + "key": "ListForms.Wizard.AddNewRecord", + "en": "Add New Wizard", + "tr": "Yeni Sihirbaz Ekle" + }, { "resourceName": "Platform", "key": "ListForms.Wizard.Required", diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605022245_Departments.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605031235_Departments.json similarity index 97% rename from api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605022245_Departments.json rename to api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605031235_Departments.json index 38c111c..06ec57d 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605022245_Departments.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605031235_Departments.json @@ -48,7 +48,7 @@ "EditorScript": "", "ColSpan": 1, "IsRequired": true, - "DbSourceType": 9, + "DbSourceType": 12, "TurkishCaption": "Id", "EnglishCaption": "Id", "LookupDataSourceType": 1, @@ -64,7 +64,7 @@ "EditorScript": "", "ColSpan": 1, "IsRequired": false, - "DbSourceType": 9, + "DbSourceType": 12, "TurkishCaption": "Branch Id", "EnglishCaption": "Branch Id", "LookupDataSourceType": 2, @@ -80,7 +80,7 @@ "EditorScript": "", "ColSpan": 1, "IsRequired": true, - "DbSourceType": 16, + "DbSourceType": 12, "TurkishCaption": "Name", "EnglishCaption": "Name", "LookupDataSourceType": 1, @@ -96,7 +96,7 @@ "EditorScript": "", "ColSpan": 1, "IsRequired": false, - "DbSourceType": 9, + "DbSourceType": 12, "TurkishCaption": "Parent Id", "EnglishCaption": "Parent Id", "LookupDataSourceType": 2, diff --git a/ui/public/version.json b/ui/public/version.json index 8c11009..161aecb 100644 --- a/ui/public/version.json +++ b/ui/public/version.json @@ -1,4 +1,54 @@ { - "commit": "aac3f4a", - "releases": [] + "commit": "ea3e847", + "releases": [ + { + "version": "1.0.5", + "buildDate": "2026-04-28", + "commit": "b9cc68ff41d675fefadab79f5ea2c5e7f376708a", + "changeLog": [ + "- AllowAdding özelliği eklendi.", + "- Kulllanıcı bazında Workhour özelliği eklendi.", + "- ConcurrentUser sınırlaması getirildi.", + "- Uygulamadan kullanıcıyı kickleme özelliği getirildi.", + "- Uygulama açıkken DbMigrator çağrısı yapıldı." + ] + }, + { + "version": "1.0.4", + "buildDate": "2026-03-30", + "commit": "e9ce256c0706de408e08a462bee9e4a72653f2c7", + "changeLog": [ + "- Role Yetkilerini kopyalama", + "- Place Holder güncellemesi", + "- Kayıt kopyalama özelliği" + ] + }, + { + "version": "1.0.3", + "buildDate": "2026-03-28", + "commit": "130d35c37703935e34948419f2ee900cc1b6b28c", + "changeLog": [ + "Report Template View And Design" + ] + }, + { + "version": "1.0.2", + "buildDate": "2026-03-21", + "commit": "196b0dc24b7a815586166679b58ab4f9334bd40e", + "changeLog": [ + "Artificial Intelligence Chat Bot güncellemeleri" + ] + }, + { + "version": "1.0.1", + "buildDate": "2026-03-18", + "commit": "ac7784c030825158641e9042c50dede2067c0486", + "changeLog": [ + "Public Site Designer", + "Menu Groups", + "Sql Query Manager", + "Listform Wizard" + ] + } + ] } \ No newline at end of file diff --git a/ui/src/proxy/admin/list-form/models.ts b/ui/src/proxy/admin/list-form/models.ts index a477419..f3751a6 100644 --- a/ui/src/proxy/admin/list-form/models.ts +++ b/ui/src/proxy/admin/list-form/models.ts @@ -4,7 +4,6 @@ import { EditingFormDto, ExtraFilterEditDto, FieldsDefaultValueDto, - SelectCommandTypeEnum, SubFormDto, WidgetEditDto, } from '../../form/models' @@ -15,71 +14,6 @@ import { ChartValueAxisDto, } from '../charts/models' -export interface ListFormWizardColumnItemDto { - dataField: string - editorType: string - editorOptions: string - editorScript: string - colSpan: number - isRequired: boolean - dbSourceType: number -} - -export interface ListFormWizardColumnGroupDto { - caption: string - colCount: number - items: ListFormWizardColumnItemDto[] -} - -export interface ListFormWizardDto { - wizardName: string - listFormCode: string - menuCode: string - isTenant: boolean - isBranch: boolean - isOrganizationUnit: boolean - allowAdding: boolean - allowUpdating: boolean - allowDeleting: boolean - confirmDelete: boolean - allowDetail: boolean - - defaultLayout: ListViewLayoutType - grid: boolean - pivot: boolean - tree: boolean - chart: boolean - gantt: boolean - scheduler: boolean - - languageTextMenuEn: string - languageTextMenuTr: string - languageTextTitleEn: string - languageTextTitleTr: string - languageTextDescEn: string - languageTextDescTr: string - languageTextMenuParentEn: string - languageTextMenuParentTr: string - permissionGroupName: string - menuParentCode: string - menuIcon: string - dataSourceCode: string - dataSourceConnectionString: string - selectCommandType: SelectCommandTypeEnum - selectCommand: string - keyFieldName: string - keyFieldDbSourceType: number - groups?: ListFormWizardColumnGroupDto[] -} - -export interface WizardFileInfoDto { - fileName: string - wizardName: string - listFormCode: string - createdAt: string - hasInsertedRecords: boolean -} - export interface ListFormJsonRowDto { id?: string index: number diff --git a/ui/src/proxy/admin/wizard/models.ts b/ui/src/proxy/admin/wizard/models.ts new file mode 100644 index 0000000..0ac7520 --- /dev/null +++ b/ui/src/proxy/admin/wizard/models.ts @@ -0,0 +1,109 @@ +import { SelectCommandTypeEnum } from "@/proxy/form/models" +import { ListViewLayoutType } from "@/views/admin/listForm/edit/types" + +export interface ListFormWizardColumnItemDto { + dataField: string + editorType: string + editorOptions: string + editorScript: string + colSpan: number + isRequired: boolean + dbSourceType: number +} + +export interface ListFormWizardColumnGroupDto { + caption: string + colCount: number + items: ListFormWizardColumnItemDto[] +} + +export interface ListFormWizardDto { + wizardName: string + listFormCode: string + menuCode: string + isTenant: boolean + isBranch: boolean + isOrganizationUnit: boolean + allowAdding: boolean + allowUpdating: boolean + allowDeleting: boolean + confirmDelete: boolean + allowDetail: boolean + + defaultLayout: ListViewLayoutType + grid: boolean + pivot: boolean + tree: boolean + chart: boolean + gantt: boolean + scheduler: boolean + + languageTextMenuEn: string + languageTextMenuTr: string + languageTextTitleEn: string + languageTextTitleTr: string + languageTextDescEn: string + languageTextDescTr: string + languageTextMenuParentEn: string + languageTextMenuParentTr: string + permissionGroupName: string + menuParentCode: string + menuIcon: string + dataSourceCode: string + dataSourceConnectionString: string + selectCommandType: SelectCommandTypeEnum + selectCommand: string + keyFieldName: string + keyFieldDbSourceType: number + groups?: ListFormWizardColumnGroupDto[] +} + +export interface WizardFileInfoDto { + fileName: string + wizardName: string + listFormCode: string + createdAt: string + hasInsertedRecords: boolean +} + +export interface WizardInsertedRecordsDto { + languageKeys: string[] + permissionGroupNames: string[] + permissionNames: string[] + menuCodes: string[] + dataSourceCodes: string[] +} + +export interface WizardSeedFileItemDto { + dataField: string + editorType: string + editorOptions: string + editorScript: string + colSpan: number + isRequired: boolean + dbSourceType: number + turkishCaption?: string + englishCaption?: string + captionName?: string + lookupDataSourceType?: number + valueExpr?: string + displayExpr?: string + lookupQuery?: string +} + +export interface WizardSeedFileGroupDto { + caption: string + colCount: number + items: WizardSeedFileItemDto[] +} + +export interface WizardSeedFileWizardDto extends Omit { + groups?: WizardSeedFileGroupDto[] +} + +export interface WizardSeedFileDto { + wizard: WizardSeedFileWizardDto + isDeletedField: boolean + isCreatedField: boolean + insertedRecords: WizardInsertedRecordsDto +} \ No newline at end of file diff --git a/ui/src/services/wizard.service.ts b/ui/src/services/wizard.service.ts index 833b6cb..67ffe2f 100644 --- a/ui/src/services/wizard.service.ts +++ b/ui/src/services/wizard.service.ts @@ -1,4 +1,4 @@ -import { ListFormWizardDto, WizardFileInfoDto } from '../proxy/admin/list-form/models' +import { ListFormWizardDto, WizardFileInfoDto, WizardSeedFileDto } from '@/proxy/admin/wizard/models' import apiService from './api.service' export const postListFormWizard = (input: ListFormWizardDto) => @@ -14,6 +14,13 @@ export const getWizardFiles = () => url: `/api/app/list-form-wizard/files`, }) +export const getWizardFile = (fileName: string) => + apiService.fetchData({ + method: 'GET', + url: `/api/app/list-form-wizard/file`, + params: { fileName }, + }) + export const deleteWizardFile = (fileName: string) => apiService.fetchData({ method: 'DELETE', diff --git a/ui/src/views/admin/listForm/wizard/Wizard.tsx b/ui/src/views/admin/listForm/wizard/Wizard.tsx index b0f6806..cbffc44 100644 --- a/ui/src/views/admin/listForm/wizard/Wizard.tsx +++ b/ui/src/views/admin/listForm/wizard/Wizard.tsx @@ -1,12 +1,11 @@ import { FormContainer, Notification, Steps, toast } from '@/components/ui' import { ROUTES_ENUM } from '@/routes/route.constant' -import { ListFormWizardDto } from '@/proxy/admin/list-form/models' import { SelectBoxOption } from '@/types/shared' import { useLocalization } from '@/utils/hooks/useLocalization' import { Form, Formik, FormikProps } from 'formik' import { useEffect, useRef, useState } from 'react' import { Helmet } from 'react-helmet' -import { useNavigate } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import * as Yup from 'yup' import { getMenus } from '@/services/menu.service' import { getPermissions } from '@/services/identity.service' @@ -23,12 +22,14 @@ import WizardStep1, { findRootCode, } from './WizardStep1' import WizardStep2 from './WizardStep2' -import WizardStep3, { WizardGroup } from './WizardStep3' +import WizardStep3, { WizardGroup, WizardGroupItem } from './WizardStep3' import WizardStep4 from './WizardStep4' import { Container } from '@/components/shared' import { sqlDataTypeToDbType } from '../edit/options' import { useStoreActions } from '@/store/store' -import { postListFormWizard } from '@/services/wizard.service' +import { deleteWizardFile, getWizardFile, postListFormWizard } from '@/services/wizard.service' +import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models' +import { ListFormWizardDto } from '@/proxy/admin/wizard/models' // ─── Formik initial values & validation ────────────────────────────────────── const initialValues: ListFormWizardDto = { @@ -106,6 +107,13 @@ const listFormValidationSchema = step1ValidationSchema.concat(step2ValidationSch const Wizard = () => { const [currentStep, setCurrentStep] = useState(0) + // ── Edit mode ── + const location = useLocation() + const editFileName: string | null = (location.state as any)?.editFileName ?? null + const isEditMode = !!editFileName + const [isLoadingEditData, setIsLoadingEditData] = useState(false) + const editDataLoadedRef = useRef(false) + // ── Data Source ── const [isLoadingDataSource, setIsLoadingDataSource] = useState(false) const [dataSourceList, setDataSourceList] = useState([]) @@ -259,6 +267,118 @@ const Wizard = () => { getPermissionGroupList() }, []) + // ── Load edit data after reference lists are ready ── + useEffect(() => { + if (!isEditMode || !editFileName) return + if (editDataLoadedRef.current) return + if (isLoadingMenu || isLoadingDataSource || isLoadingPermissionGroup) return + if (menuTree.length === 0 && dataSourceList.length === 0) return + + editDataLoadedRef.current = true + + const loadEditData = async () => { + setIsLoadingEditData(true) + try { + const res = await getWizardFile(editFileName) + const seed = res.data + if (!seed?.wizard) return + + const w = seed.wizard + + // Populate formik values + formikRef.current?.setValues({ + wizardName: w.wizardName ?? '', + listFormCode: w.listFormCode ?? '', + menuCode: w.menuCode ?? '', + isTenant: w.isTenant ?? false, + isBranch: w.isBranch ?? false, + isOrganizationUnit: w.isOrganizationUnit ?? false, + allowAdding: w.allowAdding ?? true, + allowUpdating: w.allowUpdating ?? true, + allowDeleting: w.allowDeleting ?? true, + confirmDelete: w.confirmDelete ?? true, + allowDetail: w.allowDetail ?? false, + defaultLayout: w.defaultLayout ?? 'grid', + grid: w.grid ?? true, + pivot: w.pivot ?? true, + tree: w.tree ?? true, + chart: w.chart ?? true, + gantt: w.gantt ?? true, + scheduler: w.scheduler ?? true, + languageTextMenuEn: w.languageTextMenuEn ?? '', + languageTextMenuTr: w.languageTextMenuTr ?? '', + languageTextTitleEn: w.languageTextTitleEn ?? '', + languageTextTitleTr: w.languageTextTitleTr ?? '', + languageTextDescEn: w.languageTextDescEn ?? '', + languageTextDescTr: w.languageTextDescTr ?? '', + languageTextMenuParentEn: w.languageTextMenuParentEn ?? '', + languageTextMenuParentTr: w.languageTextMenuParentTr ?? '', + permissionGroupName: w.permissionGroupName ?? '', + menuParentCode: w.menuParentCode ?? '', + menuIcon: w.menuIcon ?? '', + dataSourceCode: w.dataSourceCode ?? '', + dataSourceConnectionString: w.dataSourceConnectionString ?? '', + selectCommandType: w.selectCommandType ?? SelectCommandTypeEnum.Table, + selectCommand: w.selectCommand ?? '', + keyFieldName: w.keyFieldName ?? '', + keyFieldDbSourceType: w.keyFieldDbSourceType ?? DbTypeEnum.Int32, + }) + + // Restore datasource to trigger db objects load + if (w.dataSourceCode) { + setCurrentDataSource(w.dataSourceCode) + } + + // Restore groups → WizardGroup[] + if (w.groups && w.groups.length > 0) { + const restoredGroups: WizardGroup[] = w.groups.map((g: any, gi: number) => ({ + id: `grp_edit_${gi}_${Date.now()}`, + caption: g.caption ?? '', + colCount: g.colCount ?? 2, + items: (g.items ?? []).map( + (it: any, ii: number) => + ({ + id: `${it.dataField}_edit_${ii}_${Date.now()}`, + dataField: it.dataField ?? '', + editorType: it.editorType ?? 'dxTextBox', + editorOptions: it.editorOptions ?? '', + editorScript: it.editorScript ?? '', + colSpan: it.colSpan ?? 1, + isRequired: it.isRequired ?? false, + turkishCaption: it.turkishCaption ?? it.dataField, + englishCaption: it.englishCaption ?? it.dataField, + captionName: it.captionName ?? `App.Listform.ListformField.${it.dataField}`, + lookupDataSourceType: + (it.lookupDataSourceType as UiLookupDataSourceTypeEnum) ?? + UiLookupDataSourceTypeEnum.StaticData, + valueExpr: it.valueExpr ?? 'Key', + displayExpr: it.displayExpr ?? 'Name', + lookupQuery: it.lookupQuery ?? '', + }) as WizardGroupItem, + ), + })) + setEditingGroups(restoredGroups) + + // Restore selectedColumns from all group items + const allFields = new Set(restoredGroups.flatMap((g) => g.items.map((i) => i.dataField))) + setSelectedColumns(allFields) + } + } catch { + toast.push( + + {translate('::App.Listforms.WizardFileLoadError') || 'Failed to load wizard file.'} + , + { placement: 'top-end' }, + ) + } finally { + setIsLoadingEditData(false) + } + } + + loadEditData() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [editFileName, isLoadingMenu, isLoadingDataSource, isLoadingPermissionGroup]) + const navigate = useNavigate() const formikRef = useRef>(null) @@ -365,6 +485,11 @@ const Wizard = () => { const values = formikRef.current.values + // Edit modunda: önce eski dosyayı sil (DB kayıtlarını temizler) + if (isEditMode && editFileName) { + await deleteWizardFile(editFileName) + } + // 🔴 Önce kayıt işlemi TAMAMLANSIN await postListFormWizard({ ...values, @@ -418,7 +543,7 @@ const Wizard = () => { @@ -435,130 +560,138 @@ const Wizard = () => { + {isLoadingEditData && ( +

+ {translate('::App.Platform.Loading') || 'Loading...'} +

+ )} + { - setSubmitting(true) + onSubmit={async (values, { setSubmitting }) => { + setSubmitting(true) - try { - // 🔴 1. Kaydet (bekle) - await postListFormWizard({ ...values }) + try { + // 🔴 1. Kaydet (bekle) + await postListFormWizard({ ...values }) - // 🔴 2. Config güncelle (bekle) - await getConfig(true) + // 🔴 2. Config güncelle (bekle) + await getConfig(true) - // 🔴 3. Navigate - navigate( - ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode), - { replace: true }, - ) + // 🔴 3. Navigate + navigate( + ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode), + { replace: true }, + ) - // 🔴 4. Toast (istersen navigate öncesi de olabilir) - toast.push( - - {translate('::ListForms.FormBilgileriKaydedildi')} - , - { placement: 'top-end' }, - ) - } catch (error: any) { - toast.push(, { - placement: 'top-end', - }) - } finally { - setSubmitting(false) - } - }} - > - {({ touched, errors, isSubmitting, values }) => ( -
- - {/* ─── Step 1: Basic Info ─────────────────────────────── */} - {currentStep === 0 && ( - formikRef.current?.setFieldValue('menuParentCode', '')} - onReloadMenu={getMenuList} - permissionGroupList={permissionGroupList} - isLoadingPermissionGroup={isLoadingPermissionGroup} - onNext={handleNext} - translate={translate} - /> - )} + // 🔴 4. Toast (istersen navigate öncesi de olabilir) + toast.push( + + {translate('::ListForms.FormBilgileriKaydedildi')} + , + { placement: 'top-end' }, + ) + } catch (error: any) { + toast.push(, { + placement: 'top-end', + }) + } finally { + setSubmitting(false) + } + }} + > + {({ touched, errors, isSubmitting, values }) => ( + + + {/* ─── Step 1: Basic Info ─────────────────────────────── */} + {currentStep === 0 && ( + + formikRef.current?.setFieldValue('menuParentCode', '') + } + onReloadMenu={getMenuList} + permissionGroupList={permissionGroupList} + isLoadingPermissionGroup={isLoadingPermissionGroup} + onNext={handleNext} + translate={translate} + /> + )} - {/* ─── Step 2: Data Settings ───────────────────────────── */} - {currentStep === 1 && ( - { - setSelectCommandColumns([]) - setSelectedColumns(new Set()) - }} - onToggleColumn={toggleColumn} - onToggleAllColumns={toggleAllColumns} - translate={translate} - onBack={handleBack} - onNext={handleNext2} - /> - )} + {/* ─── Step 2: Data Settings ───────────────────────────── */} + {currentStep === 1 && ( + { + setSelectCommandColumns([]) + setSelectedColumns(new Set()) + }} + onToggleColumn={toggleColumn} + onToggleAllColumns={toggleAllColumns} + translate={translate} + onBack={handleBack} + onNext={handleNext2} + /> + )} - {/* ─── Step 3: List Form Fields ───────────────────────────── */} - {currentStep === 2 && ( - setCurrentStep(1)} - onNext={() => setCurrentStep(3)} - /> - )} + {/* ─── Step 3: List Form Fields ───────────────────────────── */} + {currentStep === 2 && ( + setCurrentStep(1)} + onNext={() => setCurrentStep(3)} + /> + )} - {/* ─── Step 4: Deploy ───────────────────────────── */} - {currentStep === 3 && ( - setCurrentStep(2)} - onSubmit={handleDeploy} - /> - )} - - - )} -
+ {/* ─── Step 4: Deploy ───────────────────────────── */} + {currentStep === 3 && ( + setCurrentStep(2)} + onSubmit={handleDeploy} + /> + )} + + + )} +
) } diff --git a/ui/src/views/admin/listForm/wizard/WizardFileManager.tsx b/ui/src/views/admin/listForm/wizard/WizardFileManager.tsx index 67afbf6..ba5a9e7 100644 --- a/ui/src/views/admin/listForm/wizard/WizardFileManager.tsx +++ b/ui/src/views/admin/listForm/wizard/WizardFileManager.tsx @@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom' 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 ConfirmDialog from '@/components/shared/ConfirmDialog' import { FaTrash, FaSync, @@ -11,12 +11,16 @@ import { FaPlus, FaExclamationTriangle, FaSearch, + FaEdit, } from 'react-icons/fa' +import { FcAcceptDatabase } from 'react-icons/fc' import { deleteWizardFile, getWizardFiles } from '@/services/wizard.service' import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon' import { useLocalization } from '@/utils/hooks/useLocalization' 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 => { @@ -45,6 +49,7 @@ const WizardFileManager = () => { const [deletingFile, setDeletingFile] = useState(null) const [confirm, setConfirm] = useState(null) const [search, setSearch] = useState('') + const [showDbMigrateDialog, setShowDbMigrateDialog] = useState(false) const filteredFiles = useMemo(() => { const q = search.trim().toLowerCase() @@ -123,7 +128,7 @@ const WizardFileManager = () => {
{ />
+ @@ -192,6 +206,20 @@ const WizardFileManager = () => { )} + - diff --git a/ui/src/views/list/List.tsx b/ui/src/views/list/List.tsx index 07cda4d..8b1279a 100644 --- a/ui/src/views/list/List.tsx +++ b/ui/src/views/list/List.tsx @@ -31,6 +31,27 @@ const Chart = React.lazy(() => import('./Chart')) const GanttView = React.lazy(() => import('./GanttView')) const SchedulerView = React.lazy(() => import('./SchedulerView')) +function isLayoutValid(dto: GridDto, layout: ListViewLayoutType | undefined): boolean { + if (!layout || layout === 'grid') return true + if (layout === 'pivot') return !!dto.gridOptions?.layoutDto?.pivot + if (layout === 'chart') return !!dto.gridOptions?.layoutDto?.chart + if (layout === 'tree') + return !!(dto.gridOptions?.layoutDto?.tree && dto.gridOptions?.treeOptionDto?.parentIdExpr) + if (layout === 'gantt') + return !!( + dto.gridOptions?.layoutDto?.gantt && + dto.gridOptions?.ganttOptionDto?.parentIdExpr && + dto.gridOptions?.ganttOptionDto?.titleExpr + ) + if (layout === 'scheduler') + return !!( + dto.gridOptions?.layoutDto?.scheduler && + dto.gridOptions?.schedulerOptionDto?.textExpr && + dto.gridOptions?.schedulerOptionDto?.startDateExpr + ) + return false +} + const List: React.FC = () => { const { listFormCode = '' } = useParams() const [searchParams] = useSearchParams() @@ -69,10 +90,10 @@ const List: React.FC = () => { if (!gridDto) return const savedLayout = states.find((s) => s.listFormCode === listFormCode)?.layout - const defaultLayout = gridDto.gridOptions?.layoutDto?.defaultLayout - - setViewMode(savedLayout ?? defaultLayout) + const candidate = savedLayout ?? defaultLayout + + setViewMode(isLayoutValid(gridDto, candidate) ? candidate : 'grid') }, [gridDto, states, listFormCode]) /* ======================= diff --git a/ui/src/views/list/useFilters.tsx b/ui/src/views/list/useFilters.tsx index 797ab2a..80b7293 100644 --- a/ui/src/views/list/useFilters.tsx +++ b/ui/src/views/list/useFilters.tsx @@ -262,6 +262,14 @@ const useFilters = ({ }) } + if (grdOpt?.columnOptionDto?.columnAutoWidth) { + menus.push({ + text: translate('::ListForms.ListForm.FitColumns'), + id: 'fitColumns', + icon: 'columnchooser', + }) + } + //Kullanicinin gridstate kaydi yapmasina izin verilmis ise gridState menu elemanlarini ekle if (grdOpt?.stateStoringDto?.enabled) { menus.push({ @@ -277,14 +285,6 @@ const useFilters = ({ }) } - if (grdOpt?.columnOptionDto?.columnAutoWidth) { - menus.push({ - text: translate('::ListForms.ListForm.FitColumns'), - id: 'fitColumns', - icon: 'columnchooser', - }) - } - if (checkPermission(gridDto?.gridOptions.permissionDto.i)) { menus.push({ text: translate('::ListForms.ListForm.ImportManager'),