From 8dda4498ef40c75765bb0f3dc64838586f560b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Sun, 3 May 2026 14:35:52 +0300 Subject: [PATCH] =?UTF-8?q?Wizard=20k=C4=B1sm=C4=B1nda=20Tree,Gantt,Schedu?= =?UTF-8?q?ler=20se=C3=A7enekleri=20eklendi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ListForms/Wizard/ListFormWizardDto.cs | 19 +++ .../ListForms/ListFormWizardAppService.cs | 28 +++++ ...nts.json => 202605031434_Departments.json} | 23 +++- ui/src/proxy/admin/wizard/models.ts | 20 ++++ ui/src/views/admin/listForm/wizard/Wizard.tsx | 66 +++++++++++ .../admin/listForm/wizard/WizardStep2.tsx | 110 ++++++++++++++++++ ui/src/views/list/List.tsx | 17 ++- 7 files changed, 274 insertions(+), 9 deletions(-) rename api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/{202605031235_Departments.json => 202605031434_Departments.json} (88%) diff --git a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/ListFormWizardDto.cs b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/ListFormWizardDto.cs index cb78695..44d6f6b 100644 --- a/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/ListFormWizardDto.cs +++ b/api/src/Sozsoft.Platform.Application.Contracts/ListForms/Wizard/ListFormWizardDto.cs @@ -48,6 +48,25 @@ public class ListFormWizardDto public string KeyFieldName { get; set; } public DbType KeyFieldDbSourceType { get; set; } + // Tree options (required when DefaultLayout = "tree") + public string TreeKeyExpr { get; set; } + public string TreeParentIdExpr { get; set; } + public bool TreeAutoExpandAll { get; set; } + + // Gantt options (required when DefaultLayout = "gantt") + public string GanttKeyExpr { get; set; } + public string GanttParentIdExpr { get; set; } + public bool GanttAutoExpandAll { get; set; } + public string GanttTitleExpr { get; set; } + public string GanttStartExpr { get; set; } + public string GanttEndExpr { get; set; } + public string GanttProgressExpr { get; set; } + + // Scheduler options (required when DefaultLayout = "scheduler") + public string SchedulerTextExpr { get; set; } + public string SchedulerStartDateExpr { get; set; } + public string SchedulerEndDateExpr { get; set; } + public List Groups { get; set; } = new(); } diff --git a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs index a113bb7..e72af51 100644 --- a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs +++ b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs @@ -284,6 +284,34 @@ public class ListFormWizardAppService( PagerOptionJson = WizardConsts.DefaultPagerOptionJson, EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail), EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null, + TreeOptionJson = (input.Tree || input.DefaultLayout == "tree") && !string.IsNullOrEmpty(input.TreeParentIdExpr) + ? JsonSerializer.Serialize(new TreeOptionDto + { + KeyExpr = input.TreeKeyExpr, + ParentIdExpr = input.TreeParentIdExpr, + AutoExpandAll = input.TreeAutoExpandAll, + }) + : null, + GanttOptionJson = (input.Gantt || input.DefaultLayout == "gantt") && !string.IsNullOrEmpty(input.GanttParentIdExpr) + ? JsonSerializer.Serialize(new GanttOptionDto + { + KeyExpr = input.GanttKeyExpr, + ParentIdExpr = input.GanttParentIdExpr, + AutoExpandAll = input.GanttAutoExpandAll, + TitleExpr = input.GanttTitleExpr, + StartExpr = input.GanttStartExpr, + EndExpr = input.GanttEndExpr, + ProgressExpr = input.GanttProgressExpr, + }) + : null, + SchedulerOptionJson = (input.Scheduler || input.DefaultLayout == "scheduler") && !string.IsNullOrEmpty(input.SchedulerTextExpr) + ? JsonSerializer.Serialize(new SchedulerOptionDto + { + TextExpr = input.SchedulerTextExpr, + StartDateExpr = input.SchedulerStartDateExpr, + EndDateExpr = input.SchedulerEndDateExpr, + }) + : null, }, autoSave: true); // ListFormField - each item in each group becomes a visible field record diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605031235_Departments.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605031434_Departments.json similarity index 88% rename from api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605031235_Departments.json rename to api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605031434_Departments.json index 06ec57d..a6cb8fb 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605031235_Departments.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardData/202605031434_Departments.json @@ -11,7 +11,7 @@ "AllowDeleting": true, "AllowDetail": false, "ConfirmDelete": true, - "DefaultLayout": "grid", + "DefaultLayout": "tree", "Grid": true, "Pivot": true, "Tree": true, @@ -35,6 +35,19 @@ "SelectCommand": "Adm_T_Department", "KeyFieldName": "Id", "KeyFieldDbSourceType": 9, + "TreeKeyExpr": "Id", + "TreeParentIdExpr": "ParentId", + "TreeAutoExpandAll": true, + "GanttKeyExpr": "", + "GanttParentIdExpr": "", + "GanttAutoExpandAll": false, + "GanttTitleExpr": "", + "GanttStartExpr": "", + "GanttEndExpr": "", + "GanttProgressExpr": "", + "SchedulerTextExpr": "", + "SchedulerStartDateExpr": "", + "SchedulerEndDateExpr": "", "Groups": [ { "Caption": "", @@ -48,7 +61,7 @@ "EditorScript": "", "ColSpan": 1, "IsRequired": true, - "DbSourceType": 12, + "DbSourceType": 9, "TurkishCaption": "Id", "EnglishCaption": "Id", "LookupDataSourceType": 1, @@ -64,7 +77,7 @@ "EditorScript": "", "ColSpan": 1, "IsRequired": false, - "DbSourceType": 12, + "DbSourceType": 9, "TurkishCaption": "Branch Id", "EnglishCaption": "Branch Id", "LookupDataSourceType": 2, @@ -80,7 +93,7 @@ "EditorScript": "", "ColSpan": 1, "IsRequired": true, - "DbSourceType": 12, + "DbSourceType": 16, "TurkishCaption": "Name", "EnglishCaption": "Name", "LookupDataSourceType": 1, @@ -96,7 +109,7 @@ "EditorScript": "", "ColSpan": 1, "IsRequired": false, - "DbSourceType": 12, + "DbSourceType": 9, "TurkishCaption": "Parent Id", "EnglishCaption": "Parent Id", "LookupDataSourceType": 2, diff --git a/ui/src/proxy/admin/wizard/models.ts b/ui/src/proxy/admin/wizard/models.ts index 0ac7520..953a9c1 100644 --- a/ui/src/proxy/admin/wizard/models.ts +++ b/ui/src/proxy/admin/wizard/models.ts @@ -55,6 +55,26 @@ export interface ListFormWizardDto { selectCommand: string keyFieldName: string keyFieldDbSourceType: number + + // Tree options (required when defaultLayout = 'tree') + treeKeyExpr?: string + treeParentIdExpr?: string + treeAutoExpandAll?: boolean + + // Gantt options (required when defaultLayout = 'gantt') + ganttKeyExpr?: string + ganttParentIdExpr?: string + ganttAutoExpandAll?: boolean + ganttTitleExpr?: string + ganttStartExpr?: string + ganttEndExpr?: string + ganttProgressExpr?: string + + // Scheduler options (required when defaultLayout = 'scheduler') + schedulerTextExpr?: string + schedulerStartDateExpr?: string + schedulerEndDateExpr?: string + groups?: ListFormWizardColumnGroupDto[] } diff --git a/ui/src/views/admin/listForm/wizard/Wizard.tsx b/ui/src/views/admin/listForm/wizard/Wizard.tsx index cbffc44..0abe19d 100644 --- a/ui/src/views/admin/listForm/wizard/Wizard.tsx +++ b/ui/src/views/admin/listForm/wizard/Wizard.tsx @@ -68,6 +68,19 @@ const initialValues: ListFormWizardDto = { selectCommand: '', keyFieldName: '', keyFieldDbSourceType: DbTypeEnum.Int32, + treeKeyExpr: '', + treeParentIdExpr: '', + treeAutoExpandAll: false, + ganttKeyExpr: '', + ganttParentIdExpr: '', + ganttAutoExpandAll: false, + ganttTitleExpr: '', + ganttStartExpr: '', + ganttEndExpr: '', + ganttProgressExpr: '', + schedulerTextExpr: '', + schedulerStartDateExpr: '', + schedulerEndDateExpr: '', } const step1ValidationSchema = Yup.object().shape({ @@ -123,6 +136,8 @@ const Wizard = () => { const [dbObjects, setDbObjects] = useState(null) const [isLoadingDbObjects, setIsLoadingDbObjects] = useState(false) const [currentDataSource, setCurrentDataSource] = useState('') + // In edit mode, stores the selectCommand to load columns for once dbObjects is ready + const pendingEditColumnsRef = useRef<{ dsCode: string; selectCommand: string; selectCommandType: SelectCommandTypeEnum } | null>(null) const loadDbObjects = async (dsCode: string) => { if (!dsCode) { @@ -144,6 +159,35 @@ const Wizard = () => { loadDbObjects(currentDataSource) }, [currentDataSource]) + // When dbObjects become available in edit mode, load columns for the saved selectCommand + useEffect(() => { + if (!dbObjects || !pendingEditColumnsRef.current) return + const { dsCode, selectCommand, selectCommandType } = pendingEditColumnsRef.current + pendingEditColumnsRef.current = null + // Find schema from dbObjects + const allObjects = [ + ...dbObjects.tables.map((t) => ({ name: t.tableName, schema: t.schemaName })), + ...dbObjects.storedProcedures.map((p) => ({ name: p.objectName, schema: p.schemaName })), + ...dbObjects.views.map((v) => ({ name: v.objectName, schema: v.schemaName })), + ...dbObjects.functions.map((f) => ({ name: f.objectName, schema: f.schemaName })), + ] + const match = allObjects.find((o) => o.name === selectCommand) + if (!match && selectCommandType !== SelectCommandTypeEnum.Query) return + const schema = match?.schema ?? 'dbo' + // Load columns without wiping groups/selectedColumns + ;(async () => { + setIsLoadingColumns(true) + try { + const res = await sqlObjectManagerService.getTableColumns(dsCode, schema, selectCommand) + setSelectCommandColumns(res.data ?? []) + } catch { + setSelectCommandColumns([]) + } finally { + setIsLoadingColumns(false) + } + })() + }, [dbObjects]) + // ── Column List for KeyFieldName & Column Selector ── const [selectCommandColumns, setSelectCommandColumns] = useState([]) const [isLoadingColumns, setIsLoadingColumns] = useState(false) @@ -322,8 +366,30 @@ const Wizard = () => { selectCommand: w.selectCommand ?? '', keyFieldName: w.keyFieldName ?? '', keyFieldDbSourceType: w.keyFieldDbSourceType ?? DbTypeEnum.Int32, + treeKeyExpr: w.treeKeyExpr ?? '', + treeParentIdExpr: w.treeParentIdExpr ?? '', + treeAutoExpandAll: w.treeAutoExpandAll ?? false, + ganttKeyExpr: w.ganttKeyExpr ?? '', + ganttParentIdExpr: w.ganttParentIdExpr ?? '', + ganttAutoExpandAll: w.ganttAutoExpandAll ?? false, + ganttTitleExpr: w.ganttTitleExpr ?? '', + ganttStartExpr: w.ganttStartExpr ?? '', + ganttEndExpr: w.ganttEndExpr ?? '', + ganttProgressExpr: w.ganttProgressExpr ?? '', + schedulerTextExpr: w.schedulerTextExpr ?? '', + schedulerStartDateExpr: w.schedulerStartDateExpr ?? '', + schedulerEndDateExpr: w.schedulerEndDateExpr ?? '', }) + // Queue column load to run once dbObjects is available + if (w.dataSourceCode && w.selectCommand) { + pendingEditColumnsRef.current = { + dsCode: w.dataSourceCode, + selectCommand: w.selectCommand, + selectCommandType: w.selectCommandType ?? SelectCommandTypeEnum.Table, + } + } + // Restore datasource to trigger db objects load if (w.dataSourceCode) { setCurrentDataSource(w.dataSourceCode) diff --git a/ui/src/views/admin/listForm/wizard/WizardStep2.tsx b/ui/src/views/admin/listForm/wizard/WizardStep2.tsx index 6ed56dc..f23df26 100644 --- a/ui/src/views/admin/listForm/wizard/WizardStep2.tsx +++ b/ui/src/views/admin/listForm/wizard/WizardStep2.tsx @@ -510,6 +510,116 @@ const WizardStep2 = ({ + {/* ── Tree options (full-width, shown when defaultLayout = 'tree') ─── */} + {values.defaultLayout === 'tree' && ( +
+
+ {translate('::ListForms.ListFormEdit.DetailsLayoutDto.TreeLayout') || 'Tree Ayarları'} +
+ + + {({ field, form }: FieldProps) => ( + ({ label: c.columnName, value: c.columnName }))} + value={values.treeParentIdExpr ? { label: values.treeParentIdExpr, value: values.treeParentIdExpr } : null} + onChange={(opt: any) => form.setFieldValue(field.name, opt?.value ?? '')} + /> + )} + + + + + +
+ )} + + {/* ── Gantt options (full-width, shown when defaultLayout = 'gantt') ─── */} + {values.defaultLayout === 'gantt' && ( +
+
+ {translate('::ListForms.ListFormEdit.DetailsLayoutDto.GanttLayout') || 'Gantt Ayarları'} +
+ {[ + { name: 'ganttKeyExpr', label: translate('::App.Listform.ListformField.KeyFieldName') }, + { name: 'ganttParentIdExpr', label: translate('::ListForms.ListFormEdit.ParentIdExpr') }, + { name: 'ganttTitleExpr', label: translate('::ListForms.ListFormEdit.TitleExpr') }, + { name: 'ganttStartExpr', label: translate('::ListForms.ListFormEdit.StartExpr') }, + { name: 'ganttEndExpr', label: translate('::ListForms.ListFormEdit.EndExpr') }, + { name: 'ganttProgressExpr', label: translate('::ListForms.ListFormEdit.ProgressExpr') }, + ].map(({ name, label }) => ( + + + {({ field, form }: FieldProps) => ( + ({ label: c.columnName, value: c.columnName }))} + value={(values as any)[name] ? { label: (values as any)[name], value: (values as any)[name] } : null} + onChange={(opt: any) => form.setFieldValue(field.name, opt?.value ?? '')} + /> + )} + + + ))} +
+ )} +
{ const savedLayout = states.find((s) => s.listFormCode === listFormCode)?.layout const defaultLayout = gridDto.gridOptions?.layoutDto?.defaultLayout const candidate = savedLayout ?? defaultLayout - + setViewMode(isLayoutValid(gridDto, candidate) ? candidate : 'grid') }, [gridDto, states, listFormCode])