Wizard Edit özelliği eklendi
This commit is contained in:
parent
ea3e847490
commit
b2dfb04879
16 changed files with 572 additions and 216 deletions
|
|
@ -7,6 +7,7 @@ public interface IListFormWizardAppService
|
||||||
{
|
{
|
||||||
Task Create(ListFormWizardDto input);
|
Task Create(ListFormWizardDto input);
|
||||||
Task<List<WizardFileInfoDto>> GetFiles();
|
Task<List<WizardFileInfoDto>> GetFiles();
|
||||||
|
Task<WizardSeedFileDto> GetFile(string fileName);
|
||||||
Task DeleteFile(string fileName);
|
Task DeleteFile(string fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -398,6 +398,24 @@ public class ListFormWizardAppService(
|
||||||
return Task.FromResult(result);
|
return Task.FromResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<WizardSeedFileDto> 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<WizardSeedFileDto>(json, options);
|
||||||
|
return seed ?? throw new Volo.Abp.AbpException("Dosya okunamadı.");
|
||||||
|
}
|
||||||
|
|
||||||
public async Task DeleteFile(string fileName)
|
public async Task DeleteFile(string fileName)
|
||||||
{
|
{
|
||||||
// Güvenlik: sadece dosya adı, path traversal yasak
|
// Güvenlik: sadece dosya adı, path traversal yasak
|
||||||
|
|
|
||||||
|
|
@ -16040,6 +16040,12 @@
|
||||||
"en": "Menu Information",
|
"en": "Menu Information",
|
||||||
"tr": "Menü Bilgileri"
|
"tr": "Menü Bilgileri"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "ListForms.Wizard.AddNewRecord",
|
||||||
|
"en": "Add New Wizard",
|
||||||
|
"tr": "Yeni Sihirbaz Ekle"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "ListForms.Wizard.Required",
|
"key": "ListForms.Wizard.Required",
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
"EditorScript": "",
|
"EditorScript": "",
|
||||||
"ColSpan": 1,
|
"ColSpan": 1,
|
||||||
"IsRequired": true,
|
"IsRequired": true,
|
||||||
"DbSourceType": 9,
|
"DbSourceType": 12,
|
||||||
"TurkishCaption": "Id",
|
"TurkishCaption": "Id",
|
||||||
"EnglishCaption": "Id",
|
"EnglishCaption": "Id",
|
||||||
"LookupDataSourceType": 1,
|
"LookupDataSourceType": 1,
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
"EditorScript": "",
|
"EditorScript": "",
|
||||||
"ColSpan": 1,
|
"ColSpan": 1,
|
||||||
"IsRequired": false,
|
"IsRequired": false,
|
||||||
"DbSourceType": 9,
|
"DbSourceType": 12,
|
||||||
"TurkishCaption": "Branch Id",
|
"TurkishCaption": "Branch Id",
|
||||||
"EnglishCaption": "Branch Id",
|
"EnglishCaption": "Branch Id",
|
||||||
"LookupDataSourceType": 2,
|
"LookupDataSourceType": 2,
|
||||||
|
|
@ -80,7 +80,7 @@
|
||||||
"EditorScript": "",
|
"EditorScript": "",
|
||||||
"ColSpan": 1,
|
"ColSpan": 1,
|
||||||
"IsRequired": true,
|
"IsRequired": true,
|
||||||
"DbSourceType": 16,
|
"DbSourceType": 12,
|
||||||
"TurkishCaption": "Name",
|
"TurkishCaption": "Name",
|
||||||
"EnglishCaption": "Name",
|
"EnglishCaption": "Name",
|
||||||
"LookupDataSourceType": 1,
|
"LookupDataSourceType": 1,
|
||||||
|
|
@ -96,7 +96,7 @@
|
||||||
"EditorScript": "",
|
"EditorScript": "",
|
||||||
"ColSpan": 1,
|
"ColSpan": 1,
|
||||||
"IsRequired": false,
|
"IsRequired": false,
|
||||||
"DbSourceType": 9,
|
"DbSourceType": 12,
|
||||||
"TurkishCaption": "Parent Id",
|
"TurkishCaption": "Parent Id",
|
||||||
"EnglishCaption": "Parent Id",
|
"EnglishCaption": "Parent Id",
|
||||||
"LookupDataSourceType": 2,
|
"LookupDataSourceType": 2,
|
||||||
|
|
@ -1,4 +1,54 @@
|
||||||
{
|
{
|
||||||
"commit": "aac3f4a",
|
"commit": "ea3e847",
|
||||||
"releases": []
|
"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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,6 @@ import {
|
||||||
EditingFormDto,
|
EditingFormDto,
|
||||||
ExtraFilterEditDto,
|
ExtraFilterEditDto,
|
||||||
FieldsDefaultValueDto,
|
FieldsDefaultValueDto,
|
||||||
SelectCommandTypeEnum,
|
|
||||||
SubFormDto,
|
SubFormDto,
|
||||||
WidgetEditDto,
|
WidgetEditDto,
|
||||||
} from '../../form/models'
|
} from '../../form/models'
|
||||||
|
|
@ -15,71 +14,6 @@ import {
|
||||||
ChartValueAxisDto,
|
ChartValueAxisDto,
|
||||||
} from '../charts/models'
|
} 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 {
|
export interface ListFormJsonRowDto {
|
||||||
id?: string
|
id?: string
|
||||||
index: number
|
index: number
|
||||||
|
|
|
||||||
109
ui/src/proxy/admin/wizard/models.ts
Normal file
109
ui/src/proxy/admin/wizard/models.ts
Normal file
|
|
@ -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<ListFormWizardDto, 'groups'> {
|
||||||
|
groups?: WizardSeedFileGroupDto[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WizardSeedFileDto {
|
||||||
|
wizard: WizardSeedFileWizardDto
|
||||||
|
isDeletedField: boolean
|
||||||
|
isCreatedField: boolean
|
||||||
|
insertedRecords: WizardInsertedRecordsDto
|
||||||
|
}
|
||||||
|
|
@ -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'
|
import apiService from './api.service'
|
||||||
|
|
||||||
export const postListFormWizard = (input: ListFormWizardDto) =>
|
export const postListFormWizard = (input: ListFormWizardDto) =>
|
||||||
|
|
@ -14,6 +14,13 @@ export const getWizardFiles = () =>
|
||||||
url: `/api/app/list-form-wizard/files`,
|
url: `/api/app/list-form-wizard/files`,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const getWizardFile = (fileName: string) =>
|
||||||
|
apiService.fetchData<WizardSeedFileDto>({
|
||||||
|
method: 'GET',
|
||||||
|
url: `/api/app/list-form-wizard/file`,
|
||||||
|
params: { fileName },
|
||||||
|
})
|
||||||
|
|
||||||
export const deleteWizardFile = (fileName: string) =>
|
export const deleteWizardFile = (fileName: string) =>
|
||||||
apiService.fetchData({
|
apiService.fetchData({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import { FormContainer, Notification, Steps, toast } from '@/components/ui'
|
import { FormContainer, Notification, Steps, toast } from '@/components/ui'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import { ListFormWizardDto } from '@/proxy/admin/list-form/models'
|
|
||||||
import { SelectBoxOption } from '@/types/shared'
|
import { SelectBoxOption } from '@/types/shared'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { Form, Formik, FormikProps } from 'formik'
|
import { Form, Formik, FormikProps } from 'formik'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
import { getMenus } from '@/services/menu.service'
|
import { getMenus } from '@/services/menu.service'
|
||||||
import { getPermissions } from '@/services/identity.service'
|
import { getPermissions } from '@/services/identity.service'
|
||||||
|
|
@ -23,12 +22,14 @@ import WizardStep1, {
|
||||||
findRootCode,
|
findRootCode,
|
||||||
} from './WizardStep1'
|
} from './WizardStep1'
|
||||||
import WizardStep2 from './WizardStep2'
|
import WizardStep2 from './WizardStep2'
|
||||||
import WizardStep3, { WizardGroup } from './WizardStep3'
|
import WizardStep3, { WizardGroup, WizardGroupItem } from './WizardStep3'
|
||||||
import WizardStep4 from './WizardStep4'
|
import WizardStep4 from './WizardStep4'
|
||||||
import { Container } from '@/components/shared'
|
import { Container } from '@/components/shared'
|
||||||
import { sqlDataTypeToDbType } from '../edit/options'
|
import { sqlDataTypeToDbType } from '../edit/options'
|
||||||
import { useStoreActions } from '@/store/store'
|
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 ──────────────────────────────────────
|
// ─── Formik initial values & validation ──────────────────────────────────────
|
||||||
const initialValues: ListFormWizardDto = {
|
const initialValues: ListFormWizardDto = {
|
||||||
|
|
@ -106,6 +107,13 @@ const listFormValidationSchema = step1ValidationSchema.concat(step2ValidationSch
|
||||||
const Wizard = () => {
|
const Wizard = () => {
|
||||||
const [currentStep, setCurrentStep] = useState(0)
|
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 ──
|
// ── Data Source ──
|
||||||
const [isLoadingDataSource, setIsLoadingDataSource] = useState(false)
|
const [isLoadingDataSource, setIsLoadingDataSource] = useState(false)
|
||||||
const [dataSourceList, setDataSourceList] = useState<SelectBoxOption[]>([])
|
const [dataSourceList, setDataSourceList] = useState<SelectBoxOption[]>([])
|
||||||
|
|
@ -259,6 +267,118 @@ const Wizard = () => {
|
||||||
getPermissionGroupList()
|
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(
|
||||||
|
<Notification type="danger">
|
||||||
|
{translate('::App.Listforms.WizardFileLoadError') || 'Failed to load wizard file.'}
|
||||||
|
</Notification>,
|
||||||
|
{ placement: 'top-end' },
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
setIsLoadingEditData(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadEditData()
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [editFileName, isLoadingMenu, isLoadingDataSource, isLoadingPermissionGroup])
|
||||||
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const formikRef = useRef<FormikProps<ListFormWizardDto>>(null)
|
const formikRef = useRef<FormikProps<ListFormWizardDto>>(null)
|
||||||
|
|
||||||
|
|
@ -365,6 +485,11 @@ const Wizard = () => {
|
||||||
|
|
||||||
const values = formikRef.current.values
|
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
|
// 🔴 Önce kayıt işlemi TAMAMLANSIN
|
||||||
await postListFormWizard({
|
await postListFormWizard({
|
||||||
...values,
|
...values,
|
||||||
|
|
@ -418,7 +543,7 @@ const Wizard = () => {
|
||||||
<Container>
|
<Container>
|
||||||
<Helmet
|
<Helmet
|
||||||
titleTemplate={`%s | ${APP_NAME}`}
|
titleTemplate={`%s | ${APP_NAME}`}
|
||||||
title={translate('::' + 'App.Listforms.Wizard')}
|
title={translate('::' + (isEditMode ? 'App.Listforms.WizardEdit' : 'App.Listforms.Wizard'))}
|
||||||
defaultTitle={APP_NAME}
|
defaultTitle={APP_NAME}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -435,6 +560,12 @@ const Wizard = () => {
|
||||||
</Steps>
|
</Steps>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{isLoadingEditData && (
|
||||||
|
<p className="text-xs text-gray-400 text-center py-4 animate-pulse">
|
||||||
|
{translate('::App.Platform.Loading') || 'Loading...'}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<Formik
|
<Formik
|
||||||
innerRef={formikRef}
|
innerRef={formikRef}
|
||||||
initialValues={{ ...initialValues }}
|
initialValues={{ ...initialValues }}
|
||||||
|
|
@ -488,7 +619,9 @@ const Wizard = () => {
|
||||||
menuTree={menuTree}
|
menuTree={menuTree}
|
||||||
isLoadingMenu={isLoadingMenu}
|
isLoadingMenu={isLoadingMenu}
|
||||||
onMenuParentChange={handleMenuParentChange}
|
onMenuParentChange={handleMenuParentChange}
|
||||||
onClearMenuParent={() => formikRef.current?.setFieldValue('menuParentCode', '')}
|
onClearMenuParent={() =>
|
||||||
|
formikRef.current?.setFieldValue('menuParentCode', '')
|
||||||
|
}
|
||||||
onReloadMenu={getMenuList}
|
onReloadMenu={getMenuList}
|
||||||
permissionGroupList={permissionGroupList}
|
permissionGroupList={permissionGroupList}
|
||||||
isLoadingPermissionGroup={isLoadingPermissionGroup}
|
isLoadingPermissionGroup={isLoadingPermissionGroup}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { Button, Input, Notification, toast } from '@/components/ui'
|
import { Button, Input, Notification, toast } from '@/components/ui'
|
||||||
import Container from '@/components/shared/Container'
|
import Container from '@/components/shared/Container'
|
||||||
import { WizardFileInfoDto } from '@/proxy/admin/list-form/models'
|
import ConfirmDialog from '@/components/shared/ConfirmDialog'
|
||||||
import {
|
import {
|
||||||
FaTrash,
|
FaTrash,
|
||||||
FaSync,
|
FaSync,
|
||||||
|
|
@ -11,12 +11,16 @@ import {
|
||||||
FaPlus,
|
FaPlus,
|
||||||
FaExclamationTriangle,
|
FaExclamationTriangle,
|
||||||
FaSearch,
|
FaSearch,
|
||||||
|
FaEdit,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
|
import { FcAcceptDatabase } from 'react-icons/fc'
|
||||||
import { deleteWizardFile, getWizardFiles } from '@/services/wizard.service'
|
import { deleteWizardFile, getWizardFiles } from '@/services/wizard.service'
|
||||||
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { useStoreState } from '@/store/store'
|
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 { UiEvalService } from '@/services/UiEvalService'
|
||||||
|
|
||||||
// Timestamp formatı: "202605021730" → "2026-05-02 17:30"
|
// Timestamp formatı: "202605021730" → "2026-05-02 17:30"
|
||||||
const formatTimestamp = (raw: string): string => {
|
const formatTimestamp = (raw: string): string => {
|
||||||
|
|
@ -45,6 +49,7 @@ const WizardFileManager = () => {
|
||||||
const [deletingFile, setDeletingFile] = useState<string | null>(null)
|
const [deletingFile, setDeletingFile] = useState<string | null>(null)
|
||||||
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 filteredFiles = useMemo(() => {
|
const filteredFiles = useMemo(() => {
|
||||||
const q = search.trim().toLowerCase()
|
const q = search.trim().toLowerCase()
|
||||||
|
|
@ -123,7 +128,7 @@ const WizardFileManager = () => {
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-xs pointer-events-none" />
|
<FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-xs pointer-events-none" />
|
||||||
<Input
|
<Input
|
||||||
size="sm"
|
size="xs"
|
||||||
className="pl-6 w-44"
|
className="pl-6 w-44"
|
||||||
placeholder={translate('::App.Platform.Search') || 'Search...'}
|
placeholder={translate('::App.Platform.Search') || 'Search...'}
|
||||||
value={search}
|
value={search}
|
||||||
|
|
@ -131,7 +136,7 @@ const WizardFileManager = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="xs"
|
||||||
variant="default"
|
variant="default"
|
||||||
title={translate('::App.Platform.Refresh') || 'Yenile'}
|
title={translate('::App.Platform.Refresh') || 'Yenile'}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|
@ -140,13 +145,22 @@ const WizardFileManager = () => {
|
||||||
<FaSync />
|
<FaSync />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="xs"
|
||||||
|
variant="default"
|
||||||
|
icon={<FcAcceptDatabase />}
|
||||||
|
onClick={() => setShowDbMigrateDialog(true)}
|
||||||
|
title={translate('::App.DbMigrate.StartMessage') || 'Run DB Migration'}
|
||||||
|
>
|
||||||
|
{translate('::ListForms.ListForm.DbMigrate') || 'DB Migrate'}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
onClick={() => navigate(ROUTES_ENUM.protected.saas.listFormManagement.wizard)}
|
onClick={() => navigate(ROUTES_ENUM.protected.saas.listFormManagement.wizard)}
|
||||||
className="flex items-center"
|
className="flex items-center"
|
||||||
>
|
>
|
||||||
<FaPlus className="mr-1" />
|
<FaPlus className="mr-1" />
|
||||||
{translate('::ListForms.ListForm.AddNewRecord') || 'Add New Record'}
|
{translate('::ListForms.Wizard.AddNewRecord') || 'Add New Record'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -192,6 +206,20 @@ const WizardFileManager = () => {
|
||||||
<FaExclamationTriangle />
|
<FaExclamationTriangle />
|
||||||
</span>
|
</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
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
|
|
@ -209,7 +237,29 @@ const WizardFileManager = () => {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Confirm Dialog */}
|
</div>
|
||||||
|
|
||||||
|
{/* DB Migrate Confirmation Dialog */}
|
||||||
|
<ConfirmDialog
|
||||||
|
isOpen={showDbMigrateDialog}
|
||||||
|
type="info"
|
||||||
|
title={translate('::ListForms.ListForm.DbMigrate') || 'DB Migrate'}
|
||||||
|
cancelText={translate('::Cancel')}
|
||||||
|
confirmText={translate('::App.Platform.Execute') || 'Çalıştır'}
|
||||||
|
onCancel={() => setShowDbMigrateDialog(false)}
|
||||||
|
onClose={() => setShowDbMigrateDialog(false)}
|
||||||
|
onConfirm={() => {
|
||||||
|
setShowDbMigrateDialog(false)
|
||||||
|
UiEvalService.ApiDbMigrate()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p className="text-gray-600 dark:text-gray-400">
|
||||||
|
{translate('::App.DbMigrate.ConfirmMessage') ||
|
||||||
|
'Veritabanı migration işlemini başlatmak istediğinize emin misiniz?'}
|
||||||
|
</p>
|
||||||
|
</ConfirmDialog>
|
||||||
|
|
||||||
|
{/* 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">
|
||||||
|
|
@ -239,7 +289,6 @@ const WizardFileManager = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Button, FormItem, Input, Notification, Select, toast } from '@/components/ui'
|
import { Button, FormItem, Input, Notification, Select, toast } from '@/components/ui'
|
||||||
import { ListFormWizardDto } from '@/proxy/admin/list-form/models'
|
|
||||||
import { MenuDto } from '@/proxy/menus/models'
|
import { MenuDto } from '@/proxy/menus/models'
|
||||||
import { SelectBoxOption } from '@/types/shared'
|
import { SelectBoxOption } from '@/types/shared'
|
||||||
import navigationIcon from '@/proxy/menus/navigation-icon.config'
|
import navigationIcon from '@/proxy/menus/navigation-icon.config'
|
||||||
|
|
@ -20,6 +19,7 @@ import {
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { IconPickerField, MenuAddDialog } from '@/views/shared/MenuAddDialog'
|
import { IconPickerField, MenuAddDialog } from '@/views/shared/MenuAddDialog'
|
||||||
|
import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
||||||
|
|
||||||
// ─── Types (exported for Wizard.tsx) ─────────────────────────────────────────
|
// ─── Types (exported for Wizard.tsx) ─────────────────────────────────────────
|
||||||
|
|
||||||
|
|
@ -256,6 +256,19 @@ function TreeNode({
|
||||||
|
|
||||||
// ─── MenuTreeInline ───────────────────────────────────────────────────────────
|
// ─── MenuTreeInline ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Returns all ancestor codes of `code` in the flat rawItems list */
|
||||||
|
function getAncestorCodes(rawItems: MenuItem[], code: string): Set<string> {
|
||||||
|
const result = new Set<string>()
|
||||||
|
let current = code
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
const item = rawItems.find((r) => r.code === current)
|
||||||
|
if (!item?.parentCode) break
|
||||||
|
result.add(item.parentCode)
|
||||||
|
current = item.parentCode
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
interface MenuTreeInlineProps {
|
interface MenuTreeInlineProps {
|
||||||
value: string
|
value: string
|
||||||
onChange: (code: string) => void
|
onChange: (code: string) => void
|
||||||
|
|
@ -264,6 +277,7 @@ interface MenuTreeInlineProps {
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
invalid?: boolean
|
invalid?: boolean
|
||||||
onReload: () => void
|
onReload: () => void
|
||||||
|
initialExpanded?: Set<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
function MenuTreeInline({
|
function MenuTreeInline({
|
||||||
|
|
@ -274,8 +288,21 @@ function MenuTreeInline({
|
||||||
isLoading,
|
isLoading,
|
||||||
invalid,
|
invalid,
|
||||||
onReload,
|
onReload,
|
||||||
|
initialExpanded,
|
||||||
}: MenuTreeInlineProps) {
|
}: MenuTreeInlineProps) {
|
||||||
const [expanded, setExpanded] = useState<Set<string>>(new Set())
|
const [expanded, setExpanded] = useState<Set<string>>(() => initialExpanded ?? new Set())
|
||||||
|
|
||||||
|
// When value changes (e.g. edit mode loads), expand ancestor nodes
|
||||||
|
useEffect(() => {
|
||||||
|
if (!value || rawItems.length === 0) return
|
||||||
|
const ancestors = getAncestorCodes(rawItems, value)
|
||||||
|
if (ancestors.size === 0) return
|
||||||
|
setExpanded((prev) => {
|
||||||
|
const next = new Set(prev)
|
||||||
|
ancestors.forEach((c) => next.add(c))
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}, [value, rawItems])
|
||||||
const [editingCode, setEditingCode] = useState<string | null>(null)
|
const [editingCode, setEditingCode] = useState<string | null>(null)
|
||||||
const [editingValue, setEditingValue] = useState('')
|
const [editingValue, setEditingValue] = useState('')
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
|
|
@ -505,6 +532,7 @@ const WizardStep1 = ({
|
||||||
isLoading={isLoadingMenu}
|
isLoading={isLoadingMenu}
|
||||||
invalid={!!(errors.menuParentCode && touched.menuParentCode)}
|
invalid={!!(errors.menuParentCode && touched.menuParentCode)}
|
||||||
onReload={onReloadMenu}
|
onReload={onReloadMenu}
|
||||||
|
initialExpanded={values.menuParentCode ? getAncestorCodes(rawMenuItems, values.menuParentCode) : undefined}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Button, Checkbox, FormItem, Input, Select } from '@/components/ui'
|
import { Button, Checkbox, FormItem, Input, Select } from '@/components/ui'
|
||||||
import { ListFormWizardDto } from '@/proxy/admin/list-form/models'
|
|
||||||
import { SelectCommandTypeEnum } from '@/proxy/form/models'
|
import { SelectCommandTypeEnum } from '@/proxy/form/models'
|
||||||
import type { DatabaseColumnDto, SqlObjectExplorerDto } from '@/proxy/sql-query-manager/models'
|
import type { DatabaseColumnDto, SqlObjectExplorerDto } from '@/proxy/sql-query-manager/models'
|
||||||
import { SelectBoxOption } from '@/types/shared'
|
import { SelectBoxOption } from '@/types/shared'
|
||||||
|
|
@ -7,6 +6,7 @@ import { Field, FieldProps, FormikErrors, FormikTouched } from 'formik'
|
||||||
import CreatableSelect from 'react-select/creatable'
|
import CreatableSelect from 'react-select/creatable'
|
||||||
import { FaArrowLeft, FaArrowRight } from 'react-icons/fa'
|
import { FaArrowLeft, FaArrowRight } from 'react-icons/fa'
|
||||||
import { dbSourceTypeOptions, listFormDefaultLayoutOptions, selectCommandTypeOptions, sqlDataTypeToDbType } from '../edit/options'
|
import { dbSourceTypeOptions, listFormDefaultLayoutOptions, selectCommandTypeOptions, sqlDataTypeToDbType } from '../edit/options'
|
||||||
|
import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
||||||
|
|
||||||
// ─── Props ────────────────────────────────────────────────────────────────────
|
// ─── Props ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Button } from '@/components/ui'
|
import { Button } from '@/components/ui'
|
||||||
import type { ListFormWizardDto } from '@/proxy/admin/list-form/models'
|
|
||||||
import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import {
|
import {
|
||||||
|
|
@ -14,6 +13,7 @@ import {
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { WizardGroup } from './WizardStep3'
|
import { WizardGroup } from './WizardStep3'
|
||||||
import { dbSourceTypeOptions, selectCommandTypeOptions } from '../edit/options'
|
import { dbSourceTypeOptions, selectCommandTypeOptions } from '../edit/options'
|
||||||
|
import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { getDataSources } from '@/services/data-source.service'
|
||||||
import type { DataSourceDto } from '@/proxy/data-source'
|
import type { DataSourceDto } from '@/proxy/data-source'
|
||||||
import type { SqlQueryExecutionResultDto } from '@/proxy/sql-query-manager/models'
|
import type { SqlQueryExecutionResultDto } from '@/proxy/sql-query-manager/models'
|
||||||
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
|
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
|
||||||
import { FaDatabase, FaPlay, FaFileAlt, FaCopy } from 'react-icons/fa'
|
import { FaDatabase, FaPlay, FaFileAlt, FaCopy, FaExclamationTriangle } from 'react-icons/fa'
|
||||||
import { FaCheckCircle } from 'react-icons/fa'
|
import { FaCheckCircle } from 'react-icons/fa'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import SqlObjectExplorer, { type SqlExplorerSelectedObject } from './SqlObjectExplorer'
|
import SqlObjectExplorer, { type SqlExplorerSelectedObject } from './SqlObjectExplorer'
|
||||||
|
|
@ -1067,7 +1067,7 @@ GO`,
|
||||||
<Button variant="plain" onClick={handleCancelTemplateReplace}>
|
<Button variant="plain" onClick={handleCancelTemplateReplace}>
|
||||||
{translate('::Cancel')}
|
{translate('::Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="solid" onClick={handleConfirmTemplateReplace}>
|
<Button variant="solid" onClick={handleConfirmTemplateReplace} icon={<FaExclamationTriangle />} color="red-600">
|
||||||
{translate('::App.Platform.Replace')}
|
{translate('::App.Platform.Replace')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,27 @@ const Chart = React.lazy(() => import('./Chart'))
|
||||||
const GanttView = React.lazy(() => import('./GanttView'))
|
const GanttView = React.lazy(() => import('./GanttView'))
|
||||||
const SchedulerView = React.lazy(() => import('./SchedulerView'))
|
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 List: React.FC = () => {
|
||||||
const { listFormCode = '' } = useParams()
|
const { listFormCode = '' } = useParams()
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
|
|
@ -69,10 +90,10 @@ const List: React.FC = () => {
|
||||||
if (!gridDto) return
|
if (!gridDto) return
|
||||||
|
|
||||||
const savedLayout = states.find((s) => s.listFormCode === listFormCode)?.layout
|
const savedLayout = states.find((s) => s.listFormCode === listFormCode)?.layout
|
||||||
|
|
||||||
const defaultLayout = gridDto.gridOptions?.layoutDto?.defaultLayout
|
const defaultLayout = gridDto.gridOptions?.layoutDto?.defaultLayout
|
||||||
|
const candidate = savedLayout ?? defaultLayout
|
||||||
|
|
||||||
setViewMode(savedLayout ?? defaultLayout)
|
setViewMode(isLayoutValid(gridDto, candidate) ? candidate : 'grid')
|
||||||
}, [gridDto, states, listFormCode])
|
}, [gridDto, states, listFormCode])
|
||||||
|
|
||||||
/* =======================
|
/* =======================
|
||||||
|
|
|
||||||
|
|
@ -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
|
//Kullanicinin gridstate kaydi yapmasina izin verilmis ise gridState menu elemanlarini ekle
|
||||||
if (grdOpt?.stateStoringDto?.enabled) {
|
if (grdOpt?.stateStoringDto?.enabled) {
|
||||||
menus.push({
|
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)) {
|
if (checkPermission(gridDto?.gridOptions.permissionDto.i)) {
|
||||||
menus.push({
|
menus.push({
|
||||||
text: translate('::ListForms.ListForm.ImportManager'),
|
text: translate('::ListForms.ListForm.ImportManager'),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue