Wizard kısmında Tree,Gantt,Scheduler seçenekleri eklendi
This commit is contained in:
parent
b2dfb04879
commit
8dda4498ef
7 changed files with 274 additions and 9 deletions
|
|
@ -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<WizardColumnGroupInputDto> Groups { get; set; } = new();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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[]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<SqlObjectExplorerDto | null>(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<DatabaseColumnDto[]>([])
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -510,6 +510,116 @@ const WizardStep2 = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Tree options (full-width, shown when defaultLayout = 'tree') ─── */}
|
||||
{values.defaultLayout === 'tree' && (
|
||||
<div className="flex flex-wrap gap-6 mt-2 p-4 rounded-lg border border-indigo-200 dark:border-indigo-800 bg-indigo-50 dark:bg-indigo-900/20">
|
||||
<h6 className="w-full text-sm font-semibold text-indigo-700 dark:text-indigo-300 mb-1">
|
||||
{translate('::ListForms.ListFormEdit.DetailsLayoutDto.TreeLayout') || 'Tree Ayarları'}
|
||||
</h6>
|
||||
<FormItem
|
||||
label={translate('::App.Listform.ListformField.KeyFieldName')}
|
||||
className="min-w-[180px]"
|
||||
>
|
||||
<Field name="treeKeyExpr">
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable
|
||||
options={selectCommandColumns.map((c) => ({ label: c.columnName, value: c.columnName }))}
|
||||
value={values.treeKeyExpr ? { label: values.treeKeyExpr, value: values.treeKeyExpr } : null}
|
||||
onChange={(opt: any) => form.setFieldValue(field.name, opt?.value ?? '')}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.ParentIdExpr')}
|
||||
className="min-w-[180px]"
|
||||
>
|
||||
<Field name="treeParentIdExpr">
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable
|
||||
options={selectCommandColumns.map((c) => ({ 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 ?? '')}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
<FormItem label={translate('::ListForms.ListFormEdit.AutoExpandAll')}>
|
||||
<Field name="treeAutoExpandAll" component={Checkbox} />
|
||||
</FormItem>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Gantt options (full-width, shown when defaultLayout = 'gantt') ─── */}
|
||||
{values.defaultLayout === 'gantt' && (
|
||||
<div className="flex flex-wrap gap-6 mt-2 p-4 rounded-lg border border-amber-200 dark:border-amber-800 bg-amber-50 dark:bg-amber-900/20">
|
||||
<h6 className="w-full text-sm font-semibold text-amber-700 dark:text-amber-300 mb-1">
|
||||
{translate('::ListForms.ListFormEdit.DetailsLayoutDto.GanttLayout') || 'Gantt Ayarları'}
|
||||
</h6>
|
||||
{[
|
||||
{ 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 }) => (
|
||||
<FormItem key={name} label={label} className="min-w-[180px]">
|
||||
<Field name={name}>
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable
|
||||
options={selectCommandColumns.map((c) => ({ 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 ?? '')}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
))}
|
||||
<FormItem label={translate('::ListForms.ListFormEdit.AutoExpandAll')}>
|
||||
<Field name="ganttAutoExpandAll" component={Checkbox} />
|
||||
</FormItem>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Scheduler options (full-width, shown when defaultLayout = 'scheduler') ─── */}
|
||||
{values.defaultLayout === 'scheduler' && (
|
||||
<div className="flex flex-wrap gap-6 mt-2 p-4 rounded-lg border border-teal-200 dark:border-teal-800 bg-teal-50 dark:bg-teal-900/20">
|
||||
<h6 className="w-full text-sm font-semibold text-teal-700 dark:text-teal-300 mb-1">
|
||||
{translate('::ListForms.ListFormEdit.DetailsLayoutDto.SchedulerLayout') || 'Scheduler Ayarları'}
|
||||
</h6>
|
||||
{[
|
||||
{ name: 'schedulerTextExpr', label: translate('::ListForms.SchedulerOptions.TextExpr') },
|
||||
{ name: 'schedulerStartDateExpr', label: translate('::ListForms.SchedulerOptions.StartDateExpr') },
|
||||
{ name: 'schedulerEndDateExpr', label: translate('::ListForms.SchedulerOptions.EndDateExpr') },
|
||||
].map(({ name, label }) => (
|
||||
<FormItem key={name} label={label} className="min-w-[180px]">
|
||||
<Field name={name}>
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable
|
||||
options={selectCommandColumns.map((c) => ({ 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 ?? '')}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-6">
|
||||
<FormItem
|
||||
label={translate('::ListForms.Wizard.Step2.TitleTextEnglish')}
|
||||
|
|
|
|||
|
|
@ -36,18 +36,27 @@ function isLayoutValid(dto: GridDto, layout: ListViewLayoutType | undefined): bo
|
|||
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)
|
||||
return !!(
|
||||
dto.gridOptions?.layoutDto?.tree &&
|
||||
dto.gridOptions?.treeOptionDto?.keyExpr &&
|
||||
dto.gridOptions?.treeOptionDto?.parentIdExpr
|
||||
)
|
||||
if (layout === 'gantt')
|
||||
return !!(
|
||||
dto.gridOptions?.layoutDto?.gantt &&
|
||||
dto.gridOptions?.ganttOptionDto?.keyExpr &&
|
||||
dto.gridOptions?.ganttOptionDto?.parentIdExpr &&
|
||||
dto.gridOptions?.ganttOptionDto?.titleExpr
|
||||
dto.gridOptions?.ganttOptionDto?.titleExpr &&
|
||||
dto.gridOptions?.ganttOptionDto?.startExpr &&
|
||||
dto.gridOptions?.ganttOptionDto?.endExpr &&
|
||||
dto.gridOptions?.ganttOptionDto?.progressExpr
|
||||
)
|
||||
if (layout === 'scheduler')
|
||||
return !!(
|
||||
dto.gridOptions?.layoutDto?.scheduler &&
|
||||
dto.gridOptions?.schedulerOptionDto?.textExpr &&
|
||||
dto.gridOptions?.schedulerOptionDto?.startDateExpr
|
||||
dto.gridOptions?.schedulerOptionDto?.startDateExpr &&
|
||||
dto.gridOptions?.schedulerOptionDto?.endDateExpr
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
|
@ -92,7 +101,7 @@ const List: React.FC = () => {
|
|||
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])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue