From 5806ff5f9faff540caf328fcf53bebc61d2a5c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Sun, 31 May 2026 21:16:41 +0300 Subject: [PATCH] Editor Options Builder --- .../EditorOptionsBuilderDialog.tsx | 1 - ui/src/views/form/FormDevExpress.tsx | 10 ++- ui/src/views/form/useFormData.tsx | 40 +++++---- ui/src/views/list/Grid.tsx | 84 +++++++++++-------- ui/src/views/list/Tree.tsx | 80 +++++++++++------- 5 files changed, 131 insertions(+), 84 deletions(-) diff --git a/ui/src/views/admin/listForm/edit/json-row-operations/EditorOptionsBuilderDialog.tsx b/ui/src/views/admin/listForm/edit/json-row-operations/EditorOptionsBuilderDialog.tsx index 4717c0b..c58cf59 100644 --- a/ui/src/views/admin/listForm/edit/json-row-operations/EditorOptionsBuilderDialog.tsx +++ b/ui/src/views/admin/listForm/edit/json-row-operations/EditorOptionsBuilderDialog.tsx @@ -24,7 +24,6 @@ const baseInputClass = const boolOptions = [ { key: 'showClearButton', label: 'showClearButton' }, { key: 'readOnly', label: 'readOnly' }, - { key: 'disabled', label: 'disabled' }, { key: 'searchEnabled', label: 'searchEnabled' }, { key: 'acceptCustomValue', label: 'acceptCustomValue' }, { key: 'showSpinButtons', label: 'showSpinButtons' }, diff --git a/ui/src/views/form/FormDevExpress.tsx b/ui/src/views/form/FormDevExpress.tsx index 76491af..da10f89 100644 --- a/ui/src/views/form/FormDevExpress.tsx +++ b/ui/src/views/form/FormDevExpress.tsx @@ -74,6 +74,11 @@ const FormDevExpress = (props: { try { const editor = refForm.current?.instance().getEditor(item.dataField!) if (editor && mode !== 'view') { + if (item.editorOptions?.disabled === true) { + editor.option('disabled', true) + return + } + // Parent fieldlerden en az biri boşsa disabled olmalı const shouldDisable = parentFields.some((parentField: string) => { return !formDataRef.current || !formDataRef.current[parentField] @@ -244,8 +249,7 @@ const FormDevExpress = (props: { key={'formItem-' + i} {...formItem} editorOptions={{ - ...formItem.editorOptions, - ...(mode === 'view' ? { readOnly: true } : { autoFocus: i === 1 }), + ...(mode === 'view' ? {} : { autoFocus: i === 1 }), ...(formItem.editorType === 'dxDateBox' ? { useMaskBehavior: true, @@ -256,6 +260,8 @@ const FormDevExpress = (props: { ...(formItem.colData?.placeHolder ? { placeholder: translate('::' + formItem.colData.placeHolder) } : {}), + ...formItem.editorOptions, + ...(mode === 'view' ? { readOnly: true } : {}), buttons: (formItem.editorOptions?.buttons || []).map((btn: any) => { if (btn?.options?.onClick && typeof btn.options.onClick === 'string') { const origClick = eval(`(${btn.options.onClick})`) diff --git a/ui/src/views/form/useFormData.tsx b/ui/src/views/form/useFormData.tsx index 4e5de73..abae5e1 100644 --- a/ui/src/views/form/useFormData.tsx +++ b/ui/src/views/form/useFormData.tsx @@ -224,12 +224,24 @@ const useGridData = (props: { return a.order >= b.order ? 1 : -1 }) .map((i: EditingFormItemDto) => { - let editorOptions = {} + let editorOptions: Record = {} + let parsedEditorOptions: Record = {} const colData = gridDto.columnFormats.find((x) => x.fieldName === i.dataField) try { - editorOptions = i.editorOptions && JSON.parse(i.editorOptions) + parsedEditorOptions = i.editorOptions ? JSON.parse(i.editorOptions) : {} } catch {} + const lookupEditorOptions = colData?.lookupDto?.dataSourceType + ? { + dataSource: getLookupDataSource(colData?.editorOptions, colData, formData), + valueExpr: colData?.lookupDto?.valueExpr?.toLowerCase(), + displayExpr: colData?.lookupDto?.displayExpr?.toLowerCase(), + } + : {} + editorOptions = { + ...lookupEditorOptions, + ...parsedEditorOptions, + } const item: SimpleItemWithColData = { canRead: gridDto.columnFormats.find((x: any) => x.fieldName === i.dataField)?.canRead ?? @@ -260,16 +272,7 @@ const useGridData = (props: { : i.editorType2, colSpan: i.colSpan, isRequired: i.isRequired, - editorOptions: { - ...editorOptions, - ...(colData?.lookupDto?.dataSourceType - ? { - dataSource: getLookupDataSource(colData?.editorOptions, colData, formData), - valueExpr: colData?.lookupDto?.valueExpr?.toLowerCase(), - displayExpr: colData?.lookupDto?.displayExpr?.toLowerCase(), - } - : {}), - }, + editorOptions, colData, tagBoxOptions: i.tagBoxOptions, gridBoxOptions: i.gridBoxOptions, @@ -315,14 +318,21 @@ const useGridData = (props: { items: (groupItem.items as SimpleItemWithColData[])?.map((item) => { const colData = gridDto.columnFormats.find((x) => x.fieldName === item.dataField) if (colData?.lookupDto?.dataSourceType) { + const currentDataSource = item.editorOptions?.dataSource + const keepCustomDataSource = + currentDataSource !== undefined && typeof currentDataSource?.load !== 'function' + return { ...item, editorOptions: { ...item.editorOptions, // formData null bile olsa getLookupDataSource çağrılmalı (null parametrelerle API çağrısı yapılacak) - dataSource: getLookupDataSource(colData?.editorOptions, colData, formData || null), - valueExpr: colData?.lookupDto?.valueExpr?.toLowerCase(), - displayExpr: colData?.lookupDto?.displayExpr?.toLowerCase(), + dataSource: keepCustomDataSource + ? currentDataSource + : getLookupDataSource(colData?.editorOptions, colData, formData || null), + valueExpr: item.editorOptions?.valueExpr ?? colData?.lookupDto?.valueExpr?.toLowerCase(), + displayExpr: + item.editorOptions?.displayExpr ?? colData?.lookupDto?.displayExpr?.toLowerCase(), }, } } diff --git a/ui/src/views/list/Grid.tsx b/ui/src/views/list/Grid.tsx index e93769a..52c5180 100644 --- a/ui/src/views/list/Grid.tsx +++ b/ui/src/views/list/Grid.tsx @@ -577,14 +577,21 @@ const Grid = (props: GridProps) => { const columnFormat = gridDto.columnFormats.find((column) => column.fieldName === fieldName) const isNewRow = Boolean((editor as any).row?.isNewRow) || mode === 'new' + const hasReadOnlyEditorOption = editor.editorOptions?.readOnly === true + const hasDisabledEditorOption = editor.editorOptions?.disabled === true + if ( (isNewRow && columnFormat?.allowAdding === false) || (!isNewRow && columnFormat?.allowEditing === false) ) { editor.editorOptions.readOnly = true } else if (isNewRow && columnFormat?.allowAdding === true) { - editor.editorOptions.readOnly = false - editor.editorOptions.disabled = false + if (!hasReadOnlyEditorOption) { + editor.editorOptions.readOnly = false + } + if (!hasDisabledEditorOption) { + editor.editorOptions.disabled = false + } } // Cascade mantığı @@ -624,7 +631,19 @@ const Grid = (props: GridProps) => { (pf: string) => !rowData[pf], ) try { - formInstance.getEditor(childFieldName)?.option('disabled', shouldDisable) + const childFormItem = gridDto.gridOptions.editingFormDto + .flatMap((group) => group.items || []) + .find((i) => i.dataField === childFieldName) + const childEditorOptions = childFormItem?.editorOptions + ? JSON.parse(childFormItem.editorOptions) + : {} + const childEditor = formInstance.getEditor(childFieldName) + + if (childEditorOptions?.disabled === true) { + childEditor?.option('disabled', true) + } else { + childEditor?.option('disabled', shouldDisable) + } } catch {} } }) @@ -960,17 +979,10 @@ const Grid = (props: GridProps) => { const mapFormItem = useCallback( (i: EditingFormItemDto) => { let editorOptions: EditorOptionsWithButtons = {} + let parsedEditorOptions: EditorOptionsWithButtons = {} + const forcedEditorOptions: EditorOptionsWithButtons = {} try { - editorOptions = i.editorOptions && JSON.parse(i.editorOptions) - - if (editorOptions?.buttons) { - editorOptions.buttons = (editorOptions?.buttons || []).map((btn: any) => { - if (btn?.options?.onClick && typeof btn.options.onClick === 'string') { - btn.options.onClick = eval(`(${btn.options.onClick})`) - } - return btn - }) - } + parsedEditorOptions = i.editorOptions ? JSON.parse(i.editorOptions) : {} const rawFilter = searchParams?.get('filter') if (rawFilter) { @@ -983,10 +995,7 @@ const Grid = (props: GridProps) => { const existsInExtra = extraFilters.some((f) => f.fieldName === i.dataField && !!f.value) if (!existsInExtra) { - editorOptions = { - ...editorOptions, - readOnly: true, - } + forcedEditorOptions.readOnly = true } } } @@ -995,36 +1004,29 @@ const Grid = (props: GridProps) => { const fieldName = i.dataField.split(':')[0] const listFormField = gridDto?.columnFormats.find((x: any) => x.fieldName === fieldName) + const defaultEditorOptions: EditorOptionsWithButtons = {} + if (listFormField?.sourceDbType === DbTypeEnum.Date) { - editorOptions = { - ...{ + Object.assign(defaultEditorOptions, { type: 'date', dateSerializationFormat: 'yyyy-MM-dd', displayFormat: 'shortDate', - }, - ...editorOptions, - } + }) } else if ( listFormField?.sourceDbType === DbTypeEnum.DateTime || listFormField?.sourceDbType === DbTypeEnum.DateTime2 || listFormField?.sourceDbType === DbTypeEnum.DateTimeOffset ) { - editorOptions = { - ...{ + Object.assign(defaultEditorOptions, { type: 'datetime', dateSerializationFormat: 'yyyy-MM-ddTHH:mm:ss', displayFormat: 'shortDateShortTime', - }, - ...editorOptions, - } + }) } // Her item'a placeholder olarak captionName ekle if (listFormField?.placeHolder) { - editorOptions = { - ...editorOptions, - placeholder: translate('::' + listFormField.placeHolder), - } + defaultEditorOptions.placeholder = translate('::' + listFormField.placeHolder) } // Set defaultValue for @AUTONUMBER fields @@ -1033,10 +1035,22 @@ const Grid = (props: GridProps) => { listFormField?.defaultValue === '@AUTONUMBER' && mode === 'new' ) { - editorOptions = { - ...editorOptions, - value: autoNumber(), - } + defaultEditorOptions.value = autoNumber() + } + + editorOptions = { + ...defaultEditorOptions, + ...parsedEditorOptions, + ...forcedEditorOptions, + } + + if (editorOptions?.buttons) { + editorOptions.buttons = (editorOptions?.buttons || []).map((btn: any) => { + if (btn?.options?.onClick && typeof btn.options.onClick === 'string') { + btn.options.onClick = eval(`(${btn.options.onClick})`) + } + return btn + }) } const item: SimpleItemWithColData = { diff --git a/ui/src/views/list/Tree.tsx b/ui/src/views/list/Tree.tsx index 3060b82..f752c11 100644 --- a/ui/src/views/list/Tree.tsx +++ b/ui/src/views/list/Tree.tsx @@ -526,14 +526,21 @@ const Tree = (props: TreeProps) => { const columnFormat = gridDto.columnFormats.find((column) => column.fieldName === fieldName) const isNewRow = Boolean((editor as any).row?.isNewRow) || mode === 'new' + const hasReadOnlyEditorOption = editor.editorOptions?.readOnly === true + const hasDisabledEditorOption = editor.editorOptions?.disabled === true + if ( (isNewRow && columnFormat?.allowAdding === false) || (!isNewRow && columnFormat?.allowEditing === false) ) { editor.editorOptions.readOnly = true } else if (isNewRow && columnFormat?.allowAdding === true) { - editor.editorOptions.readOnly = false - editor.editorOptions.disabled = false + if (!hasReadOnlyEditorOption) { + editor.editorOptions.readOnly = false + } + if (!hasDisabledEditorOption) { + editor.editorOptions.disabled = false + } } // Cascade disabled mantığı @@ -581,7 +588,17 @@ const Tree = (props: TreeProps) => { try { const editorInstance = formInstance.getEditor(col.fieldName!) if (editorInstance) { - editorInstance.option('disabled', shouldDisable) + const formItem = gridDto.gridOptions.editingFormDto + .flatMap((group) => group.items || []) + .find((i) => i.dataField === col.fieldName) + const editorOptions = formItem?.editorOptions + ? JSON.parse(formItem.editorOptions) + : {} + + editorInstance.option( + 'disabled', + editorOptions?.disabled === true ? true : shouldDisable, + ) } } catch (err) { console.debug('Cascade disabled update skipped for', col.fieldName, err) @@ -1082,22 +1099,10 @@ const Tree = (props: TreeProps) => { // Helper function: item mapper const mapFormItem = (i: EditingFormItemDto) => { let editorOptions: EditorOptionsWithButtons = {} + let parsedEditorOptions: EditorOptionsWithButtons = {} + const forcedEditorOptions: EditorOptionsWithButtons = {} try { - editorOptions = i.editorOptions && JSON.parse(i.editorOptions) - - if (editorOptions?.buttons) { - editorOptions.buttons = (editorOptions?.buttons || []).map( - (btn: any) => { - if ( - btn?.options?.onClick && - typeof btn.options.onClick === 'string' - ) { - btn.options.onClick = eval(`(${btn.options.onClick})`) - } - return btn - }, - ) - } + parsedEditorOptions = i.editorOptions ? JSON.parse(i.editorOptions) : {} const rawFilter = searchParams?.get('filter') if (rawFilter) { @@ -1114,10 +1119,7 @@ const Tree = (props: TreeProps) => { ) if (!existsInExtra) { - editorOptions = { - ...editorOptions, - readOnly: true, - } + forcedEditorOptions.readOnly = true } } } @@ -1128,28 +1130,44 @@ const Tree = (props: TreeProps) => { (x: any) => x.fieldName === fieldName, ) + const defaultEditorOptions: EditorOptionsWithButtons = {} + if (listFormField?.sourceDbType === DbTypeEnum.Date) { - editorOptions = { - ...{ + Object.assign(defaultEditorOptions, { type: 'date', dateSerializationFormat: 'yyyy-MM-dd', displayFormat: 'shortDate', - }, - ...editorOptions, - } + }) } else if ( listFormField?.sourceDbType === DbTypeEnum.DateTime || listFormField?.sourceDbType === DbTypeEnum.DateTime2 || listFormField?.sourceDbType === DbTypeEnum.DateTimeOffset ) { - editorOptions = { - ...{ + Object.assign(defaultEditorOptions, { type: 'datetime', dateSerializationFormat: 'yyyy-MM-ddTHH:mm:ss', displayFormat: 'shortDateShortTime', + }) + } + + editorOptions = { + ...defaultEditorOptions, + ...parsedEditorOptions, + ...forcedEditorOptions, + } + + if (editorOptions?.buttons) { + editorOptions.buttons = (editorOptions?.buttons || []).map( + (btn: any) => { + if ( + btn?.options?.onClick && + typeof btn.options.onClick === 'string' + ) { + btn.options.onClick = eval(`(${btn.options.onClick})`) + } + return btn }, - ...editorOptions, - } + ) } const item: SimpleItemWithColData = {